1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1982, 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * %sccs.include.redist.c% 11 * 12 * from: Utah $Hdr: rd.c 1.30 89/09/17$ 13 * 14 * @(#)rd.c 7.3 (Berkeley) 05/25/90 15 */ 16 17 /* 18 * CS80/SS80 disk driver 19 */ 20 #include "rd.h" 21 #if NRD > 0 22 23 #include "param.h" 24 #include "systm.h" 25 #include "errno.h" 26 #include "dkstat.h" 27 #include "disklabel.h" 28 #include "buf.h" 29 #include "uio.h" 30 31 #include "device.h" 32 #include "rdreg.h" 33 34 int rdinit(), rdstart(), rdgo(), rdintr(); 35 struct driver rddriver = { 36 rdinit, "rd", rdstart, rdgo, rdintr, 37 }; 38 39 struct rd_softc { 40 struct hp_device *sc_hd; 41 int sc_flags; 42 short sc_type; 43 short sc_punit; 44 char *sc_addr; 45 int sc_resid; 46 u_int sc_wpms; 47 struct rdinfo *sc_info; 48 struct devqueue sc_dq; 49 struct rd_iocmd sc_ioc; 50 struct rd_rscmd sc_rsc; 51 struct rd_stat sc_stat; 52 struct rd_ssmcmd sc_ssmc; 53 struct rd_srcmd sc_src; 54 struct rd_clearcmd sc_clear; 55 } rd_softc[NRD]; 56 57 /* sc_flags values */ 58 #define RDF_ALIVE 0x1 59 #define RDF_SEEK 0x2 60 #define RDF_SWAIT 0x4 61 62 struct size { 63 daddr_t nblocks; 64 int cyloff; 65 }; 66 67 #ifdef DEBUG 68 int rddebug = 0x80; 69 #define RDB_FOLLOW 0x01 70 #define RDB_STATUS 0x02 71 #define RDB_IDENT 0x04 72 #define RDB_IO 0x08 73 #define RDB_ASYNC 0x10 74 #define RDB_ERROR 0x80 75 #define RDB_DUMP 0x80000000 76 77 struct rdstats { 78 long rdretries; 79 long rdresets; 80 long rdtimeouts; 81 long rdpolltries; 82 long rdpollwaits; 83 } rdstats[NRD]; 84 85 /* error message tables */ 86 char *err_reject[] = { 87 0, 0, 88 "channel parity error", /* 0x2000 */ 89 0, 0, 90 "illegal opcode", /* 0x0400 */ 91 "module addressing", /* 0x0200 */ 92 "address bounds", /* 0x0100 */ 93 "parameter bounds", /* 0x0080 */ 94 "illegal parameter", /* 0x0040 */ 95 "message sequence", /* 0x0020 */ 96 0, 97 "message length", /* 0x0008 */ 98 0, 0, 0 99 }; 100 101 char *err_fault[] = { 102 0, 103 "cross unit", /* 0x4000 */ 104 0, 105 "controller fault", /* 0x1000 */ 106 0, 0, 107 "unit fault", /* 0x0200 */ 108 0, 109 "diagnostic result", /* 0x0080 */ 110 0, 111 "operator release request", /* 0x0020 */ 112 "diagnostic release request", /* 0x0010 */ 113 "internal maintenance release request", /* 0x0008 */ 114 0, 115 "power fail", /* 0x0002 */ 116 "retransmit" /* 0x0001 */ 117 }; 118 119 char *err_access[] = { 120 "illegal parallel operation", /* 0x8000 */ 121 "uninitialized media", /* 0x4000 */ 122 "no spares available", /* 0x2000 */ 123 "not ready", /* 0x1000 */ 124 "write protect", /* 0x0800 */ 125 "no data found", /* 0x0400 */ 126 0, 0, 127 "unrecoverable data overflow", /* 0x0080 */ 128 "unrecoverable data", /* 0x0040 */ 129 0, 130 "end of file", /* 0x0010 */ 131 "end of volume", /* 0x0008 */ 132 0, 0, 0 133 }; 134 135 char *err_info[] = { 136 "operator release request", /* 0x8000 */ 137 "diagnostic release request", /* 0x4000 */ 138 "internal maintenance release request", /* 0x2000 */ 139 "media wear", /* 0x1000 */ 140 "latency induced", /* 0x0800 */ 141 0, 0, 142 "auto sparing invoked", /* 0x0100 */ 143 0, 144 "recoverable data overflow", /* 0x0040 */ 145 "marginal data", /* 0x0020 */ 146 "recoverable data", /* 0x0010 */ 147 0, 148 "maintenance track overflow", /* 0x0004 */ 149 0, 0 150 }; 151 #endif 152 153 /* 154 * CS/80 partitions. We reserve the first cylinder for a LIF 155 * style boot directory (the 8k allowed in the BSD filesystem 156 * is just way too small). This boot area is outside of all but 157 * the C partition. This implies that you cannot use the C 158 * partition on a bootable disk since the filesystem would overlay 159 * the boot area. You must use the A partition. 160 * 161 * These maps support four basic layouts: 162 * 163 * A/B/G: This is the "traditional" setup for a bootable disk. 164 * A is the root partition, B the swap, and G a user partition. 165 * A/D/H: This is a setup for bootable systems requiring more swap 166 * (e.g. those who use HPCL). It has A as the root, D as a 167 * larger swap, and H as a smaller user partition. 168 * A/D/E/F: Similar to A/D/H with E and F breaking H into two partitions. 169 * E could be used for /usr and F for users. 170 * C: This gives a single, non-bootable, large user filesystem. 171 * Good for second drives on a machine (e.g. /usr/src). 172 */ 173 struct size rd7945A_sizes[8] = { 174 RDSZ(15904), 1, /* A=cyl 1 thru 142 */ 175 RDSZ(20160), 143, /* B=cyl 143 thru 322 */ 176 RDSZ(108416), 0, /* C=cyl 0 thru 967 */ 177 RDSZ(40320), 143, /* D=cyl 143 thru 502 */ 178 RDSZ(0), 0, /* E=<undefined> */ 179 RDSZ(0), 0, /* F=<undefined> */ 180 RDSZ(72240), 323, /* G=cyl 323 thru 967 */ 181 RDSZ(52080), 503, /* H=cyl 503 thru 967 */ 182 }, rd9134D_sizes[8] = { 183 RDSZ(15936), 1, /* A=cyl 1 thru 166 */ 184 RDSZ(13056), 167, /* B=cyl 167 thru 302 */ 185 RDSZ(29088), 0, /* C=cyl 0 thru 302 */ 186 RDSZ(0), 0, /* D=<undefined> */ 187 RDSZ(0), 0, /* E=<undefined> */ 188 RDSZ(0), 0, /* F=<undefined> */ 189 RDSZ(0), 0, /* G=<undefined> */ 190 RDSZ(0), 0, /* H=<undefined> */ 191 }, rd9122S_sizes[8] = { 192 RDSZ(0), 0, /* A=<undefined> */ 193 RDSZ(0), 0, /* B=<undefined> */ 194 RDSZ(1232), 0, /* C=cyl 0 thru 76 */ 195 RDSZ(0), 0, /* D=<undefined> */ 196 RDSZ(0), 0, /* E=<undefined> */ 197 RDSZ(0), 0, /* F=<undefined> */ 198 RDSZ(0), 0, /* G=<undefined> */ 199 RDSZ(0), 0, /* H=<undefined> */ 200 }, rd7912P_sizes[8] = { 201 RDSZ(15904), 0, /* A=cyl 1 thru 71 */ 202 RDSZ(22400), 72, /* B=cyl 72 thru 171 */ 203 RDSZ(128128), 0, /* C=cyl 0 thru 571 */ 204 RDSZ(42560), 72, /* D=cyl 72 thru 261 */ 205 RDSZ(0), 292, /* E=<undefined> */ 206 RDSZ(0), 542, /* F=<undefined> */ 207 RDSZ(89600), 172, /* G=cyl 221 thru 571 */ 208 RDSZ(69440), 262, /* H=cyl 262 thru 571 */ 209 }, rd7914P_sizes[8] = { 210 RDSZ(15904), 1, /* A=cyl 1 thru 71 */ 211 RDSZ(40320), 72, /* B=cyl 72 thru 251 */ 212 RDSZ(258048), 0, /* C=cyl 0 thru 1151 */ 213 RDSZ(64960), 72, /* D=cyl 72 thru 361 */ 214 RDSZ(98560), 362, /* E=cyl 362 thru 801 */ 215 RDSZ(78400), 802, /* F=cyl 802 thru 1151 */ 216 RDSZ(201600), 252, /* G=cyl 221 thru 1151 */ 217 RDSZ(176960), 362, /* H=cyl 362 thru 1151 */ 218 }, rd7933H_sizes[8] = { 219 RDSZ(16146), 1, /* A=cyl 1 thru 27 */ 220 RDSZ(66976), 28, /* B=cyl 28 thru 139 */ 221 RDSZ(789958), 0, /* C=cyl 0 thru 1320 */ 222 RDSZ(16146), 140, /* D=cyl 140 thru 166 */ 223 RDSZ(165646), 167, /* E=cyl 167 thru 443 */ 224 RDSZ(165646), 444, /* F=cyl 444 thru 720 */ 225 RDSZ(706238), 140, /* G=cyl 140 thru 1320 */ 226 RDSZ(358800), 721, /* H=cyl 721 thru 1320 */ 227 }, rd9134L_sizes[8] = { 228 RDSZ(15920), 1, /* A=cyl 1 thru 199 */ 229 RDSZ(20000), 200, /* B=cyl 200 thru 449 */ 230 RDSZ(77840), 0, /* C=cyl 0 thru 972 */ 231 RDSZ(32000), 200, /* D=cyl 200 thru 599 */ 232 RDSZ(0), 0, /* E=<undefined> */ 233 RDSZ(0), 0, /* F=<undefined> */ 234 RDSZ(41840), 450, /* G=cyl 450 thru 972 */ 235 RDSZ(29840), 600, /* H=cyl 600 thru 972 */ 236 }, rd7957A_sizes[8] = { 237 RDSZ(16016), 1, /* A=cyl 1 thru 104 */ 238 RDSZ(24640), 105, /* B=cyl 105 thru 264 */ 239 RDSZ(159544), 0, /* C=cyl 0 thru 1035 */ 240 RDSZ(42350), 105, /* D=cyl 105 thru 379 */ 241 RDSZ(54824), 380, /* E=cyl 380 thru 735 */ 242 RDSZ(46200), 736, /* F=cyl 736 thru 1035 */ 243 RDSZ(118734), 265, /* G=cyl 265 thru 1035 */ 244 RDSZ(101024), 380, /* H=cyl 380 thru 1035 */ 245 }, rd7958A_sizes[8] = { 246 RDSZ(16128), 1, /* A=cyl 1 thru 64 */ 247 RDSZ(32256), 65, /* B=cyl 65 thru 192 */ 248 RDSZ(255276), 0, /* C=cyl 0 thru 1012 */ 249 RDSZ(48384), 65, /* D=cyl 65 thru 256 */ 250 RDSZ(100800), 257, /* E=cyl 257 thru 656 */ 251 RDSZ(89712), 657, /* F=cyl 657 thru 1012 */ 252 RDSZ(206640), 193, /* G=cyl 193 thru 1012 */ 253 RDSZ(190512), 257, /* H=cyl 257 thru 1012 */ 254 }, rd7957B_sizes[8] = { 255 RDSZ(16002), 1, /* A=cyl 1 thru 127 */ 256 RDSZ(32760), 128, /* B=cyl 128 thru 387 */ 257 RDSZ(159894), 0, /* C=cyl 0 thru 1268 */ 258 RDSZ(49140), 128, /* D=cyl 128 thru 517 */ 259 RDSZ(50400), 518, /* E=cyl 518 thru 917 */ 260 RDSZ(44226), 918, /* F=cyl 918 thru 1268 */ 261 RDSZ(111006), 388, /* G=cyl 388 thru 1268 */ 262 RDSZ(94626), 518, /* H=cyl 518 thru 1268 */ 263 }, rd7958B_sizes[8] = { 264 RDSZ(16254), 1, /* A=cyl 1 thru 43 */ 265 RDSZ(32886), 44, /* B=cyl 44 thru 130 */ 266 RDSZ(297108), 0, /* C=cyl 0 thru 785 */ 267 RDSZ(49140), 44, /* D=cyl 44 thru 173 */ 268 RDSZ(121716), 174, /* E=cyl 174 thru 495 */ 269 RDSZ(109620), 496, /* F=cyl 496 thru 785 */ 270 RDSZ(247590), 131, /* G=cyl 131 thru 785 */ 271 RDSZ(231336), 174, /* H=cyl 174 thru 785 */ 272 }, rd7959B_sizes[8] = { 273 RDSZ(16254), 1, /* A=cyl 1 thru 43 */ 274 RDSZ(49140), 44, /* B=cyl 44 thru 173 */ 275 RDSZ(594216), 0, /* C=cyl 0 thru 1571 */ 276 RDSZ(65772), 44, /* D=cyl 44 thru 217 */ 277 RDSZ(303912), 218, /* E=cyl 218 thru 1021 */ 278 RDSZ(207900), 1022, /* F=cyl 1022 thru 1571 */ 279 RDSZ(528444), 174, /* G=cyl 174 thru 1571 */ 280 RDSZ(511812), 218, /* H=cyl 218 thru 1571 */ 281 282 #if DEV_BSIZE == 512 283 /* 284 * These values would not work for 1k, 285 * since the number of cylinders would be different. 286 */ 287 }, rd7936H_sizes[8] = { 288 RDSZ(16359), 1, /* A=cyl 1 thru 19 */ 289 RDSZ(67158), 20, /* B=cyl 20 thru 97 */ 290 RDSZ(600978), 0, /* C=cyl 0 thru 697 */ 291 RDSZ(16359), 98, /* D=cyl 98 thru 116 */ 292 RDSZ(120540), 117, /* E=cyl 117 thru 256 */ 293 RDSZ(120540), 256, /* F=cyl 256 thru 396 */ 294 RDSZ(516600), 98, /* G=cyl 98 thru 697 */ 295 RDSZ(259161), 397, /* H=cyl 397 thru 697 */ 296 }, rd7937H_sizes[8] = { 297 #ifdef UTAH 298 RDSZ(15990), 1, /* A=cyl 1 thru 10 */ 299 RDSZ(67158), 11, /* B=cyl 11 thru 52 */ 300 RDSZ(1116102), 0, /* C=cyl 0 thru 697 */ 301 RDSZ(124722), 53, /* D=cyl 53 thru 130 */ 302 RDSZ(163098), 131, /* E=cyl 131 thru 232 */ 303 RDSZ(287820), 233, /* F=cyl 233 thru 412 */ 304 RDSZ(1031355), 53, /* G=cyl 53 thru 697 */ 305 RDSZ(455715), 413, /* H=cyl 413 thru 697 */ 306 #else 307 RDSZ(15990), 1, /* A=cyl 1 thru 10 */ 308 RDSZ(67158), 11, /* B=cyl 11 thru 52 */ 309 RDSZ(1116102), 0, /* C=cyl 0 thru 697 */ 310 RDSZ(15990), 53, /* D=cyl 53 thru 62 */ 311 RDSZ(246246), 63, /* E=cyl 63 thru 216 */ 312 RDSZ(246246), 217, /* F=cyl 217 thru 370 */ 313 RDSZ(1031355), 53, /* G=cyl 53 thru 697 */ 314 RDSZ(522873), 371, /* H=cyl 371 thru 697 */ 315 #endif 316 #endif 317 }; 318 319 struct rdinfo { 320 int nbpt; /* DEV_BSIZE blocks per track */ 321 int ntpc; /* tracks per cylinder */ 322 int nbpc; /* blocks per cylinder */ 323 struct size *sizes; /* default partition info (if no disklabel) */ 324 short hwid; /* 2 byte HW id */ 325 short maxunum; /* maximum allowed unit number */ 326 char *desc; /* drive type description */ 327 }; 328 329 struct rdinfo rdinfo[] = { 330 NRD7945ABPT, NRD7945ATRK, NRD7945ABPT * NRD7945ATRK, 331 rd7945A_sizes, RD7946AID, 0, "7945A", 332 NRD9134DBPT, NRD9134DTRK, NRD9134DBPT * NRD9134DTRK, 333 rd9134D_sizes, RD9134DID, 1, "9134D", 334 NRD9122SBPT, NRD9122STRK, NRD9122SBPT * NRD9122STRK, 335 rd9122S_sizes, RD9134LID, 1, "9122S", 336 NRD7912PBPT, NRD7912PTRK, NRD7912PBPT * NRD7912PTRK, 337 rd7912P_sizes, RD7912PID, 0, "7912P", 338 NRD7914PBPT, NRD7914PTRK, NRD7914PBPT * NRD7914PTRK, 339 rd7914P_sizes, RD7914PID, 0, "7914P", 340 NRD7958ABPT, NRD7958ATRK, NRD7958ABPT * NRD7958ATRK, 341 rd7958A_sizes, RD7958AID, 0, "7958A", 342 NRD7957ABPT, NRD7957ATRK, NRD7957ABPT * NRD7957ATRK, 343 rd7957A_sizes, RD7957AID, 0, "7957A", 344 NRD7933HBPT, NRD7933HTRK, NRD7933HBPT * NRD7933HTRK, 345 rd7933H_sizes, RD7933HID, 0, "7933H", 346 NRD9134LBPT, NRD9134LTRK, NRD9134LBPT * NRD9134LTRK, 347 rd9134L_sizes, RD9134LID, 1, "9134L", 348 NRD7936HBPT, NRD7936HTRK, NRD7936HBPT * NRD7936HTRK, 349 rd7936H_sizes, RD7936HID, 0, "7936H", 350 NRD7937HBPT, NRD7937HTRK, NRD7937HBPT * NRD7937HTRK, 351 rd7937H_sizes, RD7937HID, 0, "7937H", 352 NRD7914PBPT, NRD7914PTRK, NRD7914PBPT * NRD7914PTRK, 353 rd7914P_sizes, RD7914CTID, 0, "7914CT", 354 NRD7945ABPT, NRD7945ATRK, NRD7945ABPT * NRD7945ATRK, 355 rd7945A_sizes, RD7946AID, 0, "7946A", 356 NRD9122SBPT, NRD9122STRK, NRD9122SBPT * NRD9122STRK, 357 rd9122S_sizes, RD9134LID, 1, "9122D", 358 NRD7957BBPT, NRD7957BTRK, NRD7957BBPT * NRD7957BTRK, 359 rd7957B_sizes, RD7957BID, 0, "7957B", 360 NRD7958BBPT, NRD7958BTRK, NRD7958BBPT * NRD7958BTRK, 361 rd7958B_sizes, RD7958BID, 0, "7958B", 362 NRD7959BBPT, NRD7959BTRK, NRD7959BBPT * NRD7959BTRK, 363 rd7959B_sizes, RD7959BID, 0, "7959B", 364 }; 365 int nrdinfo = sizeof(rdinfo) / sizeof(rdinfo[0]); 366 367 struct buf rdtab[NRD]; 368 struct buf rdbuf[NRD]; 369 370 #define rdunit(x) ((minor(x) >> 3) & 0xf) 371 #define rdpart(x) (minor(x) & 0x7) 372 #define rdpunit(x) ((x) & 7) 373 #define b_cylin b_resid 374 #define RDRETRY 5 375 #define RDWAITC 1 /* min time for timeout in seconds */ 376 377 int rderrthresh = RDRETRY-1; /* when to start reporting errors */ 378 379 rdinit(hd) 380 register struct hp_device *hd; 381 { 382 register struct rd_softc *rs = &rd_softc[hd->hp_unit]; 383 384 rs->sc_hd = hd; 385 rs->sc_punit = rdpunit(hd->hp_flags); 386 rs->sc_type = rdident(rs, hd); 387 if (rs->sc_type < 0) 388 return(0); 389 rs->sc_dq.dq_ctlr = hd->hp_ctlr; 390 rs->sc_dq.dq_unit = hd->hp_unit; 391 rs->sc_dq.dq_slave = hd->hp_slave; 392 rs->sc_dq.dq_driver = &rddriver; 393 rs->sc_info = &rdinfo[rs->sc_type]; 394 rs->sc_flags = RDF_ALIVE; 395 #ifdef DEBUG 396 /* always report errors */ 397 if (rddebug & RDB_ERROR) 398 rderrthresh = 0; 399 #endif 400 return(1); 401 } 402 403 rdident(rs, hd) 404 struct rd_softc *rs; 405 struct hp_device *hd; 406 { 407 struct rd_describe desc; 408 u_char stat, cmd[3]; 409 int unit, lunit; 410 char name[7]; 411 register int ctlr, slave, id, i; 412 413 ctlr = hd->hp_ctlr; 414 slave = hd->hp_slave; 415 unit = rs->sc_punit; 416 lunit = hd->hp_unit; 417 418 /* 419 * Grab device id and make sure: 420 * 1. It is a CS80 device. 421 * 2. It is one of the types we support. 422 * 3. If it is a 7946, we are accessing the disk unit (0) 423 */ 424 id = hpibid(ctlr, slave); 425 if ((id & 0x200) == 0) 426 return(-1); 427 for (i = 0; i < nrdinfo; i++) 428 if (id == rdinfo[i].hwid) 429 break; 430 if (i == nrdinfo || unit > rdinfo[i].maxunum) 431 return(-1); 432 id = i; 433 434 /* 435 * Reset drive and collect device description. 436 * Don't really use the description info right now but 437 * might come in handy in the future (for disk labels). 438 */ 439 rdreset(rs, hd); 440 cmd[0] = C_SUNIT(unit); 441 cmd[1] = C_SVOL(0); 442 cmd[2] = C_DESC; 443 hpibsend(ctlr, slave, C_CMD, cmd, sizeof(cmd)); 444 hpibrecv(ctlr, slave, C_EXEC, &desc, 37); 445 hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 446 bzero(name, sizeof(name)); 447 if (!stat) { 448 register int n = desc.d_name; 449 for (i = 5; i >= 0; i--) { 450 name[i] = (n & 0xf) + '0'; 451 n >>= 4; 452 } 453 /* use drive characteristics to calculate xfer rate */ 454 rs->sc_wpms = 1000000 * (desc.d_sectsize/2) / desc.d_blocktime; 455 } 456 #ifdef DEBUG 457 if (rddebug & RDB_IDENT) { 458 printf("rd%d: name: %x ('%s')\n", 459 lunit, desc.d_name, name); 460 printf(" iuw %x, maxxfr %d, ctype %d\n", 461 desc.d_iuw, desc.d_cmaxxfr, desc.d_ctype); 462 printf(" utype %d, bps %d, blkbuf %d, burst %d, blktime %d\n", 463 desc.d_utype, desc.d_sectsize, 464 desc.d_blkbuf, desc.d_burstsize, desc.d_blocktime); 465 printf(" avxfr %d, ort %d, atp %d, maxint %d, fv %x, rv %x\n", 466 desc.d_uavexfr, desc.d_retry, desc.d_access, 467 desc.d_maxint, desc.d_fvbyte, desc.d_rvbyte); 468 printf(" maxcyl/head/sect %d/%d/%d, maxvsect %d, inter %d\n", 469 desc.d_maxcyl, desc.d_maxhead, desc.d_maxsect, 470 desc.d_maxvsectl, desc.d_interleave); 471 } 472 #endif 473 /* 474 * Take care of a couple of anomolies: 475 * 1. 7945A and 7946A both return same HW id 476 * 2. 9122S and 9134D both return same HW id 477 * 3. 9122D and 9134L both return same HW id 478 */ 479 switch (rdinfo[id].hwid) { 480 case RD7946AID: 481 if (bcmp(name, "079450", 6) == 0) 482 id = RD7945A; 483 else 484 id = RD7946A; 485 break; 486 487 case RD9134LID: 488 if (bcmp(name, "091340", 6) == 0) 489 id = RD9134L; 490 else 491 id = RD9122D; 492 break; 493 494 case RD9134DID: 495 if (bcmp(name, "091220", 6) == 0) 496 id = RD9122S; 497 else 498 id = RD9134D; 499 break; 500 } 501 printf("rd%d: %s\n", lunit, rdinfo[id].desc); 502 return(id); 503 } 504 505 rdreset(rs, hd) 506 register struct rd_softc *rs; 507 register struct hp_device *hd; 508 { 509 u_char stat; 510 511 rs->sc_clear.c_unit = C_SUNIT(rs->sc_punit); 512 rs->sc_clear.c_cmd = C_CLEAR; 513 hpibsend(hd->hp_ctlr, hd->hp_slave, C_TCMD, &rs->sc_clear, 514 sizeof(rs->sc_clear)); 515 hpibswait(hd->hp_ctlr, hd->hp_slave); 516 hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat)); 517 rs->sc_src.c_unit = C_SUNIT(RDCTLR); 518 rs->sc_src.c_nop = C_NOP; 519 rs->sc_src.c_cmd = C_SREL; 520 rs->sc_src.c_param = C_REL; 521 hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_src, 522 sizeof(rs->sc_src)); 523 hpibswait(hd->hp_ctlr, hd->hp_slave); 524 hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat)); 525 rs->sc_ssmc.c_unit = C_SUNIT(rs->sc_punit); 526 rs->sc_ssmc.c_cmd = C_SSM; 527 rs->sc_ssmc.c_refm = REF_MASK; 528 rs->sc_ssmc.c_fefm = FEF_MASK; 529 rs->sc_ssmc.c_aefm = AEF_MASK; 530 rs->sc_ssmc.c_iefm = IEF_MASK; 531 hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_ssmc, 532 sizeof(rs->sc_ssmc)); 533 hpibswait(hd->hp_ctlr, hd->hp_slave); 534 hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat)); 535 #ifdef DEBUG 536 rdstats[hd->hp_unit].rdresets++; 537 #endif 538 } 539 540 /*ARGSUSED*/ 541 rdopen(dev, flags) 542 dev_t dev; 543 { 544 register int unit = rdunit(dev); 545 register struct rd_softc *rs = &rd_softc[unit]; 546 547 if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) 548 return(ENXIO); 549 if (rs->sc_hd->hp_dk >= 0) { 550 /* guess at xfer rate based on 3600 rpm (60 rps) */ 551 if (rs->sc_wpms == 0) 552 rs->sc_wpms = 60 * rs->sc_info->nbpt * DEV_BSIZE / 2; 553 dk_wpms[rs->sc_hd->hp_dk] = rs->sc_wpms; 554 } 555 return(0); 556 } 557 558 rdstrategy(bp) 559 register struct buf *bp; 560 { 561 register int part = rdpart(bp->b_dev); 562 register int unit = rdunit(bp->b_dev); 563 register int bn, sz; 564 register struct rd_softc *rs = &rd_softc[unit]; 565 register struct buf *dp = &rdtab[unit]; 566 int s; 567 568 #ifdef DEBUG 569 if (rddebug & RDB_FOLLOW) 570 printf("rdstrategy(%x): dev %x, bn %x, bcount %x, %c\n", 571 bp, bp->b_dev, bp->b_blkno, bp->b_bcount, 572 (bp->b_flags & B_READ) ? 'R' : 'W'); 573 #endif 574 bn = bp->b_blkno; 575 sz = (bp->b_bcount + (DEV_BSIZE - 1)) >> DEV_BSHIFT; 576 if (bn < 0 || bn + sz > rs->sc_info->sizes[part].nblocks) { 577 if (bn == rs->sc_info->sizes[part].nblocks) { 578 bp->b_resid = bp->b_bcount; 579 goto done; 580 } 581 bp->b_error = EINVAL; 582 goto bad; 583 } 584 bp->b_cylin = bn / rs->sc_info->nbpc + rs->sc_info->sizes[part].cyloff; 585 s = splbio(); 586 disksort(dp, bp); 587 if (dp->b_active == 0) { 588 dp->b_active = 1; 589 rdustart(unit); 590 } 591 splx(s); 592 return; 593 bad: 594 bp->b_flags |= B_ERROR; 595 done: 596 biodone(bp); 597 } 598 599 /* 600 * Called from timeout() when handling maintenance releases 601 */ 602 rdrestart(unit) 603 int unit; 604 { 605 int s = splbio(); 606 rdustart(unit); 607 splx(s); 608 } 609 610 rdustart(unit) 611 register int unit; 612 { 613 register struct buf *bp; 614 register struct rd_softc *rs = &rd_softc[unit]; 615 616 bp = rdtab[unit].b_actf; 617 rs->sc_addr = bp->b_un.b_addr; 618 rs->sc_resid = bp->b_bcount; 619 if (hpibreq(&rs->sc_dq)) 620 rdstart(unit); 621 } 622 623 rdstart(unit) 624 register int unit; 625 { 626 register struct rd_softc *rs = &rd_softc[unit]; 627 register struct buf *bp = rdtab[unit].b_actf; 628 register struct hp_device *hp = rs->sc_hd; 629 register int part; 630 631 again: 632 #ifdef DEBUG 633 if (rddebug & RDB_FOLLOW) 634 printf("rdstart(%d): bp %x, %c\n", unit, bp, 635 (bp->b_flags & B_READ) ? 'R' : 'W'); 636 #endif 637 part = rdpart(bp->b_dev); 638 rs->sc_flags |= RDF_SEEK; 639 rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); 640 rs->sc_ioc.c_volume = C_SVOL(0); 641 rs->sc_ioc.c_saddr = C_SADDR; 642 rs->sc_ioc.c_hiaddr = 0; 643 rs->sc_ioc.c_addr = RDBTOS(bp->b_blkno + rs->sc_info->nbpc * 644 rs->sc_info->sizes[part].cyloff); 645 rs->sc_ioc.c_nop2 = C_NOP; 646 rs->sc_ioc.c_slen = C_SLEN; 647 rs->sc_ioc.c_len = rs->sc_resid; 648 rs->sc_ioc.c_cmd = bp->b_flags & B_READ ? C_READ : C_WRITE; 649 #ifdef DEBUG 650 if (rddebug & RDB_IO) 651 printf("rdstart: hpibsend(%x, %x, %x, %x, %x)\n", 652 hp->hp_ctlr, hp->hp_slave, C_CMD, 653 &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2); 654 #endif 655 if (hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, &rs->sc_ioc.c_unit, 656 sizeof(rs->sc_ioc)-2) == sizeof(rs->sc_ioc)-2) { 657 if (hp->hp_dk >= 0) { 658 dk_busy |= 1 << hp->hp_dk; 659 dk_seek[hp->hp_dk]++; 660 } 661 #ifdef DEBUG 662 if (rddebug & RDB_IO) 663 printf("rdstart: hpibawait(%x)\n", hp->hp_ctlr); 664 #endif 665 hpibawait(hp->hp_ctlr); 666 return; 667 } 668 /* 669 * Experience has shown that the hpibwait in this hpibsend will 670 * occasionally timeout. It appears to occur mostly on old 7914 671 * drives with full maintenance tracks. We should probably 672 * integrate this with the backoff code in rderror. 673 */ 674 #ifdef DEBUG 675 if (rddebug & RDB_ERROR) 676 printf("rd%d: rdstart: cmd %x adr %d blk %d len %d ecnt %d\n", 677 unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, 678 bp->b_blkno, rs->sc_resid, rdtab[unit].b_errcnt); 679 rdstats[unit].rdretries++; 680 #endif 681 rs->sc_flags &= ~RDF_SEEK; 682 rdreset(rs, hp); 683 if (rdtab[unit].b_errcnt++ < RDRETRY) 684 goto again; 685 printf("rd%d: rdstart err: cmd 0x%x sect %d blk %d len %d\n", 686 unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, 687 bp->b_blkno, rs->sc_resid); 688 rdtab[unit].b_errcnt = 0; 689 rdtab[unit].b_actf = bp->b_actf; 690 bp->b_flags |= B_ERROR; 691 bp->b_error = EIO; 692 bp->b_resid = 0; 693 biodone(bp); 694 hpibfree(&rs->sc_dq); 695 bp = rdtab[unit].b_actf; 696 if (bp == NULL) { 697 rdtab[unit].b_active = 0; 698 return; 699 } 700 rs->sc_addr = bp->b_un.b_addr; 701 rs->sc_resid = bp->b_bcount; 702 if (hpibreq(&rs->sc_dq)) 703 goto again; 704 } 705 706 rdgo(unit) 707 register int unit; 708 { 709 register struct rd_softc *rs = &rd_softc[unit]; 710 register struct hp_device *hp = rs->sc_hd; 711 struct buf *bp = rdtab[unit].b_actf; 712 713 if (hp->hp_dk >= 0) { 714 dk_busy |= 1 << hp->hp_dk; 715 dk_xfer[hp->hp_dk]++; 716 dk_wds[hp->hp_dk] += rs->sc_resid >> 6; 717 } 718 hpibgo(hp->hp_ctlr, hp->hp_slave, C_EXEC, 719 rs->sc_addr, rs->sc_resid, bp->b_flags & B_READ); 720 } 721 722 rdintr(unit) 723 register int unit; 724 { 725 register struct rd_softc *rs = &rd_softc[unit]; 726 register struct buf *bp = rdtab[unit].b_actf; 727 register struct hp_device *hp = rs->sc_hd; 728 u_char stat = 13; /* in case hpibrecv fails */ 729 int restart; 730 731 #ifdef DEBUG 732 if (rddebug & RDB_FOLLOW) 733 printf("rdintr(%d): bp %x, %c, flags %x\n", unit, bp, 734 (bp->b_flags & B_READ) ? 'R' : 'W', rs->sc_flags); 735 if (bp == NULL) { 736 printf("rd%d: bp == NULL\n", unit); 737 return; 738 } 739 #endif 740 if (hp->hp_dk >= 0) 741 dk_busy &= ~(1 << hp->hp_dk); 742 if (rs->sc_flags & RDF_SEEK) { 743 rs->sc_flags &= ~RDF_SEEK; 744 if (hpibustart(hp->hp_ctlr)) 745 rdgo(unit); 746 return; 747 } 748 if ((rs->sc_flags & RDF_SWAIT) == 0) { 749 #ifdef DEBUG 750 rdstats[unit].rdpolltries++; 751 #endif 752 if (hpibpptest(hp->hp_ctlr, hp->hp_slave) == 0) { 753 #ifdef DEBUG 754 rdstats[unit].rdpollwaits++; 755 #endif 756 if (hp->hp_dk >= 0) 757 dk_busy |= 1 << hp->hp_dk; 758 rs->sc_flags |= RDF_SWAIT; 759 hpibawait(hp->hp_ctlr); 760 return; 761 } 762 } else 763 rs->sc_flags &= ~RDF_SWAIT; 764 if (!hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1) || stat) { 765 #ifdef DEBUG 766 if (rddebug & RDB_ERROR) 767 printf("rdintr: recv failed or bad stat %d\n", stat); 768 #endif 769 restart = rderror(unit); 770 #ifdef DEBUG 771 rdstats[unit].rdretries++; 772 #endif 773 if (rdtab[unit].b_errcnt++ < RDRETRY) { 774 if (restart) 775 rdstart(unit); 776 return; 777 } 778 bp->b_flags |= B_ERROR; 779 bp->b_error = EIO; 780 } 781 rdtab[unit].b_errcnt = 0; 782 rdtab[unit].b_actf = bp->b_actf; 783 bp->b_resid = 0; 784 biodone(bp); 785 hpibfree(&rs->sc_dq); 786 if (rdtab[unit].b_actf) 787 rdustart(unit); 788 else 789 rdtab[unit].b_active = 0; 790 } 791 792 rdstatus(rs) 793 register struct rd_softc *rs; 794 { 795 register int c, s; 796 u_char stat; 797 int rv; 798 799 c = rs->sc_hd->hp_ctlr; 800 s = rs->sc_hd->hp_slave; 801 rs->sc_rsc.c_unit = C_SUNIT(rs->sc_punit); 802 rs->sc_rsc.c_sram = C_SRAM; 803 rs->sc_rsc.c_ram = C_RAM; 804 rs->sc_rsc.c_cmd = C_STATUS; 805 bzero((caddr_t)&rs->sc_stat, sizeof(rs->sc_stat)); 806 rv = hpibsend(c, s, C_CMD, &rs->sc_rsc, sizeof(rs->sc_rsc)); 807 if (rv != sizeof(rs->sc_rsc)) { 808 #ifdef DEBUG 809 if (rddebug & RDB_STATUS) 810 printf("rdstatus: send C_CMD failed %d != %d\n", 811 rv, sizeof(rs->sc_rsc)); 812 #endif 813 return(1); 814 } 815 rv = hpibrecv(c, s, C_EXEC, &rs->sc_stat, sizeof(rs->sc_stat)); 816 if (rv != sizeof(rs->sc_stat)) { 817 #ifdef DEBUG 818 if (rddebug & RDB_STATUS) 819 printf("rdstatus: send C_EXEC failed %d != %d\n", 820 rv, sizeof(rs->sc_stat)); 821 #endif 822 return(1); 823 } 824 rv = hpibrecv(c, s, C_QSTAT, &stat, 1); 825 if (rv != 1 || stat) { 826 #ifdef DEBUG 827 if (rddebug & RDB_STATUS) 828 printf("rdstatus: recv failed %d or bad stat %d\n", 829 rv, stat); 830 #endif 831 return(1); 832 } 833 return(0); 834 } 835 836 /* 837 * Deal with errors. 838 * Returns 1 if request should be restarted, 839 * 0 if we should just quietly give up. 840 */ 841 rderror(unit) 842 int unit; 843 { 844 struct rd_softc *rs = &rd_softc[unit]; 845 register struct rd_stat *sp; 846 struct buf *bp; 847 daddr_t hwbn, pbn; 848 849 if (rdstatus(rs)) { 850 #ifdef DEBUG 851 printf("rd%d: couldn't get status\n", unit); 852 #endif 853 rdreset(rs, rs->sc_hd); 854 return(1); 855 } 856 sp = &rs->sc_stat; 857 if (sp->c_fef & FEF_REXMT) 858 return(1); 859 if (sp->c_fef & FEF_PF) { 860 rdreset(rs, rs->sc_hd); 861 return(1); 862 } 863 /* 864 * Unit requests release for internal maintenance. 865 * We just delay awhile and try again later. Use expontially 866 * increasing backoff ala ethernet drivers since we don't really 867 * know how long the maintenance will take. With RDWAITC and 868 * RDRETRY as defined, the range is 1 to 32 seconds. 869 */ 870 if (sp->c_fef & FEF_IMR) { 871 extern int hz; 872 int rdtimo = RDWAITC << rdtab[unit].b_errcnt; 873 #ifdef DEBUG 874 printf("rd%d: internal maintenance, %d second timeout\n", 875 unit, rdtimo); 876 rdstats[unit].rdtimeouts++; 877 #endif 878 hpibfree(&rs->sc_dq); 879 timeout(rdrestart, unit, rdtimo*hz); 880 return(0); 881 } 882 /* 883 * Only report error if we have reached the error reporting 884 * threshhold. By default, this will only report after the 885 * retry limit has been exceeded. 886 */ 887 if (rdtab[unit].b_errcnt < rderrthresh) 888 return(1); 889 890 /* 891 * First conjure up the block number at which the error occured. 892 * Note that not all errors report a block number, in that case 893 * we just use b_blkno. 894 */ 895 bp = rdtab[unit].b_actf; 896 pbn = rs->sc_info->nbpc * 897 rs->sc_info->sizes[rdpart(bp->b_dev)].cyloff; 898 if ((sp->c_fef & FEF_CU) || (sp->c_fef & FEF_DR) || 899 (sp->c_ief & IEF_RRMASK)) { 900 hwbn = RDBTOS(pbn + bp->b_blkno); 901 pbn = bp->b_blkno; 902 } else { 903 hwbn = sp->c_blk; 904 pbn = RDSTOB(hwbn) - pbn; 905 } 906 /* 907 * Now output a generic message suitable for badsect. 908 * Note that we don't use harderr cuz it just prints 909 * out b_blkno which is just the beginning block number 910 * of the transfer, not necessary where the error occured. 911 */ 912 printf("rd%d%c: hard error sn%d\n", 913 rdunit(bp->b_dev), 'a'+rdpart(bp->b_dev), pbn); 914 /* 915 * Now report the status as returned by the hardware with 916 * attempt at interpretation (unless debugging). 917 */ 918 printf("rd%d %s error:", 919 unit, (bp->b_flags & B_READ) ? "read" : "write"); 920 #ifdef DEBUG 921 if (rddebug & RDB_ERROR) { 922 /* status info */ 923 printf("\n volume: %d, unit: %d\n", 924 (sp->c_vu>>4)&0xF, sp->c_vu&0xF); 925 rdprinterr("reject", sp->c_ref, err_reject); 926 rdprinterr("fault", sp->c_fef, err_fault); 927 rdprinterr("access", sp->c_aef, err_access); 928 rdprinterr("info", sp->c_ief, err_info); 929 printf(" block: %d, P1-P10: ", hwbn); 930 printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8)); 931 printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8)); 932 printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4)); 933 /* command */ 934 printf(" ioc: "); 935 printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_pad, 8)); 936 printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_hiaddr, 4)); 937 printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_addr, 8)); 938 printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_nop2, 4)); 939 printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_len, 8)); 940 printf("%s\n", hexstr(*(u_short *)&rs->sc_ioc.c_cmd, 4)); 941 return(1); 942 } 943 #endif 944 printf(" v%d u%d, R0x%x F0x%x A0x%x I0x%x\n", 945 (sp->c_vu>>4)&0xF, sp->c_vu&0xF, 946 sp->c_ref, sp->c_fef, sp->c_aef, sp->c_ief); 947 printf("P1-P10: "); 948 printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8)); 949 printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8)); 950 printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4)); 951 return(1); 952 } 953 954 rdread(dev, uio) 955 dev_t dev; 956 struct uio *uio; 957 { 958 register int unit = rdunit(dev); 959 960 return(physio(rdstrategy, &rdbuf[unit], dev, B_READ, minphys, uio)); 961 } 962 963 rdwrite(dev, uio) 964 dev_t dev; 965 struct uio *uio; 966 { 967 register int unit = rdunit(dev); 968 969 return(physio(rdstrategy, &rdbuf[unit], dev, B_WRITE, minphys, uio)); 970 } 971 972 /*ARGSUSED*/ 973 rdioctl(dev, cmd, data, flag) 974 dev_t dev; 975 int cmd; 976 caddr_t data; 977 int flag; 978 { 979 return(EINVAL); 980 } 981 982 rdsize(dev) 983 dev_t dev; 984 { 985 register int unit = rdunit(dev); 986 register struct rd_softc *rs = &rd_softc[unit]; 987 988 if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) 989 return(-1); 990 return(rs->sc_info->sizes[rdpart(dev)].nblocks); 991 } 992 993 #ifdef DEBUG 994 rdprinterr(str, err, tab) 995 char *str; 996 short err; 997 char *tab[]; 998 { 999 register int i; 1000 int printed; 1001 1002 if (err == 0) 1003 return; 1004 printf(" %s error field:", str, err); 1005 printed = 0; 1006 for (i = 0; i < 16; i++) 1007 if (err & (0x8000 >> i)) 1008 printf("%s%s", printed++ ? " + " : " ", tab[i]); 1009 printf("\n"); 1010 } 1011 #endif 1012 1013 #include "machine/pte.h" 1014 #include "machine/vmparam.h" 1015 #include "../sys/vmmac.h" 1016 1017 /* 1018 * Non-interrupt driven, non-dma dump routine. 1019 */ 1020 rddump(dev) 1021 dev_t dev; 1022 { 1023 int part = rdpart(dev); 1024 int unit = rdunit(dev); 1025 register struct rd_softc *rs = &rd_softc[unit]; 1026 register struct hp_device *hp = rs->sc_hd; 1027 register daddr_t baddr; 1028 register int maddr; 1029 register int pages, i; 1030 char stat; 1031 extern int lowram, dumpsize; 1032 1033 pages = dumpsize; 1034 #ifdef DEBUG 1035 if (rddebug & RDB_DUMP) 1036 printf("rddump(%x): u %d p %d dumplo %d ram %x pmem %d\n", 1037 dev, unit, part, dumplo, lowram, ctod(pages)); 1038 #endif 1039 /* is drive ok? */ 1040 if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) 1041 return (ENXIO); 1042 /* HPIB idle? */ 1043 if (!hpibreq(&rs->sc_dq)) { 1044 #ifdef DEBUG 1045 /* is this a safe thing to do?? */ 1046 hpibreset(hp->hp_ctlr); 1047 rdreset(rs, rs->sc_hd); 1048 printf("[ drive %d reset ] ", unit); 1049 #else 1050 return (EFAULT); 1051 #endif 1052 } 1053 /* dump parameters in range? */ 1054 if (dumplo < 0 || dumplo >= rs->sc_info->sizes[part].nblocks) 1055 return (EINVAL); 1056 if (dumplo + ctod(pages) > rs->sc_info->sizes[part].nblocks) 1057 pages = dtoc(rs->sc_info->sizes[part].nblocks - dumplo); 1058 maddr = lowram; 1059 baddr = dumplo + rs->sc_info->nbpc * rs->sc_info->sizes[part].cyloff; 1060 #ifdef DEBUG 1061 if (rddebug & RDB_DUMP) 1062 printf("rddump: dumping %d pages from %x to disk block %d\n", 1063 pages, maddr, baddr); 1064 #endif 1065 for (i = 0; i < pages; i++) { 1066 #ifdef DEBUG 1067 #define NPGMB (1024*1024/NBPG) 1068 /* print out how many Mbs we have dumped */ 1069 if (i && (i % NPGMB) == 0) 1070 printf("%d ", i / NPGMB); 1071 #undef NPBMG 1072 #endif 1073 rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); 1074 rs->sc_ioc.c_volume = C_SVOL(0); 1075 rs->sc_ioc.c_saddr = C_SADDR; 1076 rs->sc_ioc.c_hiaddr = 0; 1077 rs->sc_ioc.c_addr = RDBTOS(baddr); 1078 rs->sc_ioc.c_nop2 = C_NOP; 1079 rs->sc_ioc.c_slen = C_SLEN; 1080 rs->sc_ioc.c_len = NBPG; 1081 rs->sc_ioc.c_cmd = C_WRITE; 1082 hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, 1083 &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2); 1084 if (hpibswait(hp->hp_ctlr, hp->hp_slave)) { 1085 #ifdef DEBUG 1086 if (rddebug & RDB_DUMP) 1087 printf("rddump: IOC wait timeout\n"); 1088 #endif 1089 return (EIO); 1090 } 1091 mapin(mmap, (u_int)vmmap, btop(maddr), PG_URKR|PG_CI|PG_V); 1092 hpibsend(hp->hp_ctlr, hp->hp_slave, C_EXEC, vmmap, NBPG); 1093 if (hpibswait(hp->hp_ctlr, hp->hp_slave)) { 1094 #ifdef DEBUG 1095 if (rddebug & RDB_DUMP) 1096 printf("rddump: write wait timeout\n"); 1097 #endif 1098 } 1099 hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1); 1100 if (stat) { 1101 #ifdef DEBUG 1102 if (rddebug & RDB_DUMP) 1103 printf("rddump: write failed, status %x\n", 1104 stat); 1105 #endif 1106 return (EIO); 1107 } 1108 maddr += NBPG; 1109 baddr += ctod(1); 1110 } 1111 return (0); 1112 } 1113 #endif 1114