1 /* $NetBSD: rd.c,v 1.44 2000/10/10 19:58:43 he Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Copyright (c) 1988 University of Utah. 41 * Copyright (c) 1982, 1990, 1993 42 * The Regents of the University of California. All rights reserved. 43 * 44 * This code is derived from software contributed to Berkeley by 45 * the Systems Programming Group of the University of Utah Computer 46 * Science Department. 47 * 48 * Redistribution and use in source and binary forms, with or without 49 * modification, are permitted provided that the following conditions 50 * are met: 51 * 1. Redistributions of source code must retain the above copyright 52 * notice, this list of conditions and the following disclaimer. 53 * 2. Redistributions in binary form must reproduce the above copyright 54 * notice, this list of conditions and the following disclaimer in the 55 * documentation and/or other materials provided with the distribution. 56 * 3. All advertising materials mentioning features or use of this software 57 * must display the following acknowledgement: 58 * This product includes software developed by the University of 59 * California, Berkeley and its contributors. 60 * 4. Neither the name of the University nor the names of its contributors 61 * may be used to endorse or promote products derived from this software 62 * without specific prior written permission. 63 * 64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 67 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 74 * SUCH DAMAGE. 75 * 76 * from: Utah $Hdr: rd.c 1.44 92/12/26$ 77 * 78 * @(#)rd.c 8.2 (Berkeley) 5/19/94 79 */ 80 81 /* 82 * CS80/SS80 disk driver 83 */ 84 85 #include "opt_useleds.h" 86 #include "rnd.h" 87 88 #include <sys/param.h> 89 #include <sys/systm.h> 90 #include <sys/buf.h> 91 #include <sys/conf.h> 92 #include <sys/device.h> 93 #include <sys/disk.h> 94 #include <sys/disklabel.h> 95 #include <sys/fcntl.h> 96 #include <sys/ioctl.h> 97 #include <sys/proc.h> 98 #include <sys/stat.h> 99 100 #if NRND > 0 101 #include <sys/rnd.h> 102 #endif 103 104 #include <hp300/dev/hpibvar.h> 105 106 #include <hp300/dev/rdreg.h> 107 #include <hp300/dev/rdvar.h> 108 109 #ifdef USELEDS 110 #include <hp300/hp300/leds.h> 111 #endif 112 113 int rderrthresh = RDRETRY-1; /* when to start reporting errors */ 114 115 #ifdef DEBUG 116 /* error message tables */ 117 char *err_reject[] = { 118 0, 0, 119 "channel parity error", /* 0x2000 */ 120 0, 0, 121 "illegal opcode", /* 0x0400 */ 122 "module addressing", /* 0x0200 */ 123 "address bounds", /* 0x0100 */ 124 "parameter bounds", /* 0x0080 */ 125 "illegal parameter", /* 0x0040 */ 126 "message sequence", /* 0x0020 */ 127 0, 128 "message length", /* 0x0008 */ 129 0, 0, 0 130 }; 131 132 char *err_fault[] = { 133 0, 134 "cross unit", /* 0x4000 */ 135 0, 136 "controller fault", /* 0x1000 */ 137 0, 0, 138 "unit fault", /* 0x0200 */ 139 0, 140 "diagnostic result", /* 0x0080 */ 141 0, 142 "operator release request", /* 0x0020 */ 143 "diagnostic release request", /* 0x0010 */ 144 "internal maintenance release request", /* 0x0008 */ 145 0, 146 "power fail", /* 0x0002 */ 147 "retransmit" /* 0x0001 */ 148 }; 149 150 char *err_access[] = { 151 "illegal parallel operation", /* 0x8000 */ 152 "uninitialized media", /* 0x4000 */ 153 "no spares available", /* 0x2000 */ 154 "not ready", /* 0x1000 */ 155 "write protect", /* 0x0800 */ 156 "no data found", /* 0x0400 */ 157 0, 0, 158 "unrecoverable data overflow", /* 0x0080 */ 159 "unrecoverable data", /* 0x0040 */ 160 0, 161 "end of file", /* 0x0010 */ 162 "end of volume", /* 0x0008 */ 163 0, 0, 0 164 }; 165 166 char *err_info[] = { 167 "operator release request", /* 0x8000 */ 168 "diagnostic release request", /* 0x4000 */ 169 "internal maintenance release request", /* 0x2000 */ 170 "media wear", /* 0x1000 */ 171 "latency induced", /* 0x0800 */ 172 0, 0, 173 "auto sparing invoked", /* 0x0100 */ 174 0, 175 "recoverable data overflow", /* 0x0040 */ 176 "marginal data", /* 0x0020 */ 177 "recoverable data", /* 0x0010 */ 178 0, 179 "maintenance track overflow", /* 0x0004 */ 180 0, 0 181 }; 182 183 int rddebug = 0x80; 184 #define RDB_FOLLOW 0x01 185 #define RDB_STATUS 0x02 186 #define RDB_IDENT 0x04 187 #define RDB_IO 0x08 188 #define RDB_ASYNC 0x10 189 #define RDB_ERROR 0x80 190 #endif 191 192 /* 193 * Misc. HW description, indexed by sc_type. 194 * Nothing really critical here, could do without it. 195 */ 196 struct rdidentinfo rdidentinfo[] = { 197 { RD7946AID, 0, "7945A", NRD7945ABPT, 198 NRD7945ATRK, 968, 108416 }, 199 200 { RD9134DID, 1, "9134D", NRD9134DBPT, 201 NRD9134DTRK, 303, 29088 }, 202 203 { RD9134LID, 1, "9122S", NRD9122SBPT, 204 NRD9122STRK, 77, 1232 }, 205 206 { RD7912PID, 0, "7912P", NRD7912PBPT, 207 NRD7912PTRK, 572, 128128 }, 208 209 { RD7914PID, 0, "7914P", NRD7914PBPT, 210 NRD7914PTRK, 1152, 258048 }, 211 212 { RD7958AID, 0, "7958A", NRD7958ABPT, 213 NRD7958ATRK, 1013, 255276 }, 214 215 { RD7957AID, 0, "7957A", NRD7957ABPT, 216 NRD7957ATRK, 1036, 159544 }, 217 218 { RD7933HID, 0, "7933H", NRD7933HBPT, 219 NRD7933HTRK, 1321, 789958 }, 220 221 { RD9134LID, 1, "9134L", NRD9134LBPT, 222 NRD9134LTRK, 973, 77840 }, 223 224 { RD7936HID, 0, "7936H", NRD7936HBPT, 225 NRD7936HTRK, 698, 600978 }, 226 227 { RD7937HID, 0, "7937H", NRD7937HBPT, 228 NRD7937HTRK, 698, 1116102 }, 229 230 { RD7914CTID, 0, "7914CT", NRD7914PBPT, 231 NRD7914PTRK, 1152, 258048 }, 232 233 { RD7946AID, 0, "7946A", NRD7945ABPT, 234 NRD7945ATRK, 968, 108416 }, 235 236 { RD9134LID, 1, "9122D", NRD9122SBPT, 237 NRD9122STRK, 77, 1232 }, 238 239 { RD7957BID, 0, "7957B", NRD7957BBPT, 240 NRD7957BTRK, 1269, 159894 }, 241 242 { RD7958BID, 0, "7958B", NRD7958BBPT, 243 NRD7958BTRK, 786, 297108 }, 244 245 { RD7959BID, 0, "7959B", NRD7959BBPT, 246 NRD7959BTRK, 1572, 594216 }, 247 248 { RD2200AID, 0, "2200A", NRD2200ABPT, 249 NRD2200ATRK, 1449, 654948 }, 250 251 { RD2203AID, 0, "2203A", NRD2203ABPT, 252 NRD2203ATRK, 1449, 1309896 } 253 }; 254 int numrdidentinfo = sizeof(rdidentinfo) / sizeof(rdidentinfo[0]); 255 256 bdev_decl(rd); 257 cdev_decl(rd); 258 259 int rdident __P((struct device *, struct rd_softc *, 260 struct hpibbus_attach_args *)); 261 void rdreset __P((struct rd_softc *)); 262 void rdustart __P((struct rd_softc *)); 263 int rdgetinfo __P((dev_t)); 264 void rdrestart __P((void *)); 265 struct buf *rdfinish __P((struct rd_softc *, struct buf *)); 266 267 void rdrestart __P((void *)); 268 void rdustart __P((struct rd_softc *)); 269 struct buf *rdfinish __P((struct rd_softc *, struct buf *)); 270 void rdstart __P((void *)); 271 void rdgo __P((void *)); 272 void rdintr __P((void *)); 273 int rdstatus __P((struct rd_softc *)); 274 int rderror __P((int)); 275 #ifdef DEBUG 276 void rdprinterr __P((char *, short, char **)); 277 #endif 278 279 int rdmatch __P((struct device *, struct cfdata *, void *)); 280 void rdattach __P((struct device *, struct device *, void *)); 281 282 struct cfattach rd_ca = { 283 sizeof(struct rd_softc), rdmatch, rdattach 284 }; 285 286 extern struct cfdriver rd_cd; 287 288 int 289 rdmatch(parent, match, aux) 290 struct device *parent; 291 struct cfdata *match; 292 void *aux; 293 { 294 struct hpibbus_attach_args *ha = aux; 295 296 /* 297 * Set punit if operator specified one in the kernel 298 * configuration file. 299 */ 300 if (match->hpibbuscf_punit != HPIBBUSCF_PUNIT_DEFAULT && 301 match->hpibbuscf_punit < HPIB_NPUNITS) 302 ha->ha_punit = match->hpibbuscf_punit; 303 304 if (rdident(parent, NULL, ha) == 0) { 305 /* 306 * XXX Some aging HP-IB drives are slow to 307 * XXX respond; give them a chance to catch 308 * XXX up and probe them again. 309 */ 310 delay(10000); 311 ha->ha_id = hpibid(parent->dv_unit, ha->ha_slave); 312 return (rdident(parent, NULL, ha)); 313 } 314 return (1); 315 } 316 317 void 318 rdattach(parent, self, aux) 319 struct device *parent, *self; 320 void *aux; 321 { 322 struct rd_softc *sc = (struct rd_softc *)self; 323 struct hpibbus_attach_args *ha = aux; 324 325 BUFQ_INIT(&sc->sc_tab); 326 327 if (rdident(parent, sc, ha) == 0) { 328 printf("\n%s: didn't respond to describe command!\n", 329 sc->sc_dev.dv_xname); 330 return; 331 } 332 333 /* 334 * Initialize and attach the disk structure. 335 */ 336 bzero(&sc->sc_dkdev, sizeof(sc->sc_dkdev)); 337 sc->sc_dkdev.dk_name = sc->sc_dev.dv_xname; 338 disk_attach(&sc->sc_dkdev); 339 340 sc->sc_slave = ha->ha_slave; 341 sc->sc_punit = ha->ha_punit; 342 343 callout_init(&sc->sc_restart_ch); 344 345 /* Initialize the hpib job queue entry */ 346 sc->sc_hq.hq_softc = sc; 347 sc->sc_hq.hq_slave = sc->sc_slave; 348 sc->sc_hq.hq_start = rdstart; 349 sc->sc_hq.hq_go = rdgo; 350 sc->sc_hq.hq_intr = rdintr; 351 352 sc->sc_flags = RDF_ALIVE; 353 #ifdef DEBUG 354 /* always report errors */ 355 if (rddebug & RDB_ERROR) 356 rderrthresh = 0; 357 #endif 358 #if NRND > 0 359 /* 360 * attach the device into the random source list 361 */ 362 rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname, 363 RND_TYPE_DISK, 0); 364 #endif 365 } 366 367 int 368 rdident(parent, sc, ha) 369 struct device *parent; 370 struct rd_softc *sc; 371 struct hpibbus_attach_args *ha; 372 { 373 struct rd_describe *desc = sc != NULL ? &sc->sc_rddesc : NULL; 374 u_char stat, cmd[3]; 375 char name[7]; 376 int i, id, n, ctlr, slave; 377 378 ctlr = parent->dv_unit; 379 slave = ha->ha_slave; 380 381 /* Verify that we have a CS80 device. */ 382 if ((ha->ha_id & 0x200) == 0) 383 return (0); 384 385 /* Is it one of the disks we support? */ 386 for (id = 0; id < numrdidentinfo; id++) 387 if (ha->ha_id == rdidentinfo[id].ri_hwid) 388 break; 389 if (id == numrdidentinfo || ha->ha_punit > rdidentinfo[id].ri_maxunum) 390 return (0); 391 392 /* 393 * If we're just probing for the device, that's all the 394 * work we need to do. 395 */ 396 if (sc == NULL) 397 return (1); 398 399 /* 400 * Reset device and collect description 401 */ 402 rdreset(sc); 403 cmd[0] = C_SUNIT(ha->ha_punit); 404 cmd[1] = C_SVOL(0); 405 cmd[2] = C_DESC; 406 hpibsend(ctlr, slave, C_CMD, cmd, sizeof(cmd)); 407 hpibrecv(ctlr, slave, C_EXEC, desc, 37); 408 hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 409 bzero(name, sizeof(name)); 410 if (stat == 0) { 411 n = desc->d_name; 412 for (i = 5; i >= 0; i--) { 413 name[i] = (n & 0xf) + '0'; 414 n >>= 4; 415 } 416 } 417 418 #ifdef DEBUG 419 if (rddebug & RDB_IDENT) { 420 printf("\n%s: name: %x ('%s')\n", 421 sc->sc_dev.dv_xname, desc->d_name, name); 422 printf(" iuw %x, maxxfr %d, ctype %d\n", 423 desc->d_iuw, desc->d_cmaxxfr, desc->d_ctype); 424 printf(" utype %d, bps %d, blkbuf %d, burst %d, blktime %d\n", 425 desc->d_utype, desc->d_sectsize, 426 desc->d_blkbuf, desc->d_burstsize, desc->d_blocktime); 427 printf(" avxfr %d, ort %d, atp %d, maxint %d, fv %x, rv %x\n", 428 desc->d_uavexfr, desc->d_retry, desc->d_access, 429 desc->d_maxint, desc->d_fvbyte, desc->d_rvbyte); 430 printf(" maxcyl/head/sect %d/%d/%d, maxvsect %d, inter %d\n", 431 desc->d_maxcyl, desc->d_maxhead, desc->d_maxsect, 432 desc->d_maxvsectl, desc->d_interleave); 433 printf("%s", sc->sc_dev.dv_xname); 434 } 435 #endif 436 437 /* 438 * Take care of a couple of anomolies: 439 * 1. 7945A and 7946A both return same HW id 440 * 2. 9122S and 9134D both return same HW id 441 * 3. 9122D and 9134L both return same HW id 442 */ 443 switch (ha->ha_id) { 444 case RD7946AID: 445 if (bcmp(name, "079450", 6) == 0) 446 id = RD7945A; 447 else 448 id = RD7946A; 449 break; 450 451 case RD9134LID: 452 if (bcmp(name, "091340", 6) == 0) 453 id = RD9134L; 454 else 455 id = RD9122D; 456 break; 457 458 case RD9134DID: 459 if (bcmp(name, "091220", 6) == 0) 460 id = RD9122S; 461 else 462 id = RD9134D; 463 break; 464 } 465 466 sc->sc_type = id; 467 468 /* 469 * XXX We use DEV_BSIZE instead of the sector size value pulled 470 * XXX off the driver because all of this code assumes 512 byte 471 * XXX blocks. ICK! 472 */ 473 printf(": %s\n", rdidentinfo[id].ri_desc); 474 printf("%s: %d cylinders, %d heads, %d blocks, %d bytes/block\n", 475 sc->sc_dev.dv_xname, rdidentinfo[id].ri_ncyl, 476 rdidentinfo[id].ri_ntpc, rdidentinfo[id].ri_nblocks, 477 DEV_BSIZE); 478 479 return (1); 480 } 481 482 void 483 rdreset(rs) 484 struct rd_softc *rs; 485 { 486 int ctlr = rs->sc_dev.dv_parent->dv_unit; 487 int slave = rs->sc_slave; 488 u_char stat; 489 490 rs->sc_clear.c_unit = C_SUNIT(rs->sc_punit); 491 rs->sc_clear.c_cmd = C_CLEAR; 492 hpibsend(ctlr, slave, C_TCMD, &rs->sc_clear, sizeof(rs->sc_clear)); 493 hpibswait(ctlr, slave); 494 hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 495 496 rs->sc_src.c_unit = C_SUNIT(RDCTLR); 497 rs->sc_src.c_nop = C_NOP; 498 rs->sc_src.c_cmd = C_SREL; 499 rs->sc_src.c_param = C_REL; 500 hpibsend(ctlr, slave, C_CMD, &rs->sc_src, sizeof(rs->sc_src)); 501 hpibswait(ctlr, slave); 502 hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 503 504 rs->sc_ssmc.c_unit = C_SUNIT(rs->sc_punit); 505 rs->sc_ssmc.c_cmd = C_SSM; 506 rs->sc_ssmc.c_refm = REF_MASK; 507 rs->sc_ssmc.c_fefm = FEF_MASK; 508 rs->sc_ssmc.c_aefm = AEF_MASK; 509 rs->sc_ssmc.c_iefm = IEF_MASK; 510 hpibsend(ctlr, slave, C_CMD, &rs->sc_ssmc, sizeof(rs->sc_ssmc)); 511 hpibswait(ctlr, slave); 512 hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 513 #ifdef DEBUG 514 rs->sc_stats.rdresets++; 515 #endif 516 } 517 518 /* 519 * Read or constuct a disklabel 520 */ 521 int 522 rdgetinfo(dev) 523 dev_t dev; 524 { 525 int unit = rdunit(dev); 526 struct rd_softc *rs = rd_cd.cd_devs[unit]; 527 struct disklabel *lp = rs->sc_dkdev.dk_label; 528 struct partition *pi; 529 char *msg; 530 531 /* 532 * Set some default values to use while reading the label 533 * or to use if there isn't a label. 534 */ 535 bzero((caddr_t)lp, sizeof *lp); 536 lp->d_type = DTYPE_HPIB; 537 lp->d_secsize = DEV_BSIZE; 538 lp->d_nsectors = 32; 539 lp->d_ntracks = 20; 540 lp->d_ncylinders = 1; 541 lp->d_secpercyl = 32*20; 542 lp->d_npartitions = 3; 543 lp->d_partitions[2].p_offset = 0; 544 lp->d_partitions[2].p_size = LABELSECTOR+1; 545 546 /* 547 * Now try to read the disklabel 548 */ 549 msg = readdisklabel(rdlabdev(dev), rdstrategy, lp, NULL); 550 if (msg == NULL) 551 return (0); 552 553 pi = lp->d_partitions; 554 printf("%s: WARNING: %s, ", rs->sc_dev.dv_xname, msg); 555 #ifdef COMPAT_NOLABEL 556 printf("using old default partitioning\n"); 557 rdmakedisklabel(unit, lp); 558 #else 559 printf("defining `c' partition as entire disk\n"); 560 pi[2].p_size = rdidentinfo[rs->sc_type].ri_nblocks; 561 /* XXX reset other info since readdisklabel screws with it */ 562 lp->d_npartitions = 3; 563 pi[0].p_size = 0; 564 #endif 565 return(0); 566 } 567 568 int 569 rdopen(dev, flags, mode, p) 570 dev_t dev; 571 int flags, mode; 572 struct proc *p; 573 { 574 int unit = rdunit(dev); 575 struct rd_softc *rs; 576 int error, mask, part; 577 578 if (unit >= rd_cd.cd_ndevs || 579 (rs = rd_cd.cd_devs[unit]) == NULL || 580 (rs->sc_flags & RDF_ALIVE) == 0) 581 return (ENXIO); 582 583 /* 584 * Wait for any pending opens/closes to complete 585 */ 586 while (rs->sc_flags & (RDF_OPENING|RDF_CLOSING)) 587 (void) tsleep(rs, PRIBIO, "rdopen", 0); 588 589 /* 590 * On first open, get label and partition info. 591 * We may block reading the label, so be careful 592 * to stop any other opens. 593 */ 594 if (rs->sc_dkdev.dk_openmask == 0) { 595 rs->sc_flags |= RDF_OPENING; 596 error = rdgetinfo(dev); 597 rs->sc_flags &= ~RDF_OPENING; 598 wakeup((caddr_t)rs); 599 if (error) 600 return(error); 601 } 602 603 part = rdpart(dev); 604 mask = 1 << part; 605 606 /* Check that the partition exists. */ 607 if (part != RAW_PART && 608 (part > rs->sc_dkdev.dk_label->d_npartitions || 609 rs->sc_dkdev.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) 610 return (ENXIO); 611 612 /* Ensure only one open at a time. */ 613 switch (mode) { 614 case S_IFCHR: 615 rs->sc_dkdev.dk_copenmask |= mask; 616 break; 617 case S_IFBLK: 618 rs->sc_dkdev.dk_bopenmask |= mask; 619 break; 620 } 621 rs->sc_dkdev.dk_openmask = 622 rs->sc_dkdev.dk_copenmask | rs->sc_dkdev.dk_bopenmask; 623 624 return(0); 625 } 626 627 int 628 rdclose(dev, flag, mode, p) 629 dev_t dev; 630 int flag, mode; 631 struct proc *p; 632 { 633 int unit = rdunit(dev); 634 struct rd_softc *rs = rd_cd.cd_devs[unit]; 635 struct disk *dk = &rs->sc_dkdev; 636 int mask, s; 637 638 mask = 1 << rdpart(dev); 639 if (mode == S_IFCHR) 640 dk->dk_copenmask &= ~mask; 641 else 642 dk->dk_bopenmask &= ~mask; 643 dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask; 644 /* 645 * On last close, we wait for all activity to cease since 646 * the label/parition info will become invalid. Since we 647 * might sleep, we must block any opens while we are here. 648 * Note we don't have to about other closes since we know 649 * we are the last one. 650 */ 651 if (dk->dk_openmask == 0) { 652 rs->sc_flags |= RDF_CLOSING; 653 s = splbio(); 654 while (rs->sc_active) { 655 rs->sc_flags |= RDF_WANTED; 656 (void) tsleep(&rs->sc_tab, PRIBIO, "rdclose", 0); 657 } 658 splx(s); 659 rs->sc_flags &= ~(RDF_CLOSING|RDF_WLABEL); 660 wakeup((caddr_t)rs); 661 } 662 return(0); 663 } 664 665 void 666 rdstrategy(bp) 667 struct buf *bp; 668 { 669 int unit = rdunit(bp->b_dev); 670 struct rd_softc *rs = rd_cd.cd_devs[unit]; 671 struct partition *pinfo; 672 daddr_t bn; 673 int sz, s; 674 int offset; 675 676 #ifdef DEBUG 677 if (rddebug & RDB_FOLLOW) 678 printf("rdstrategy(%p): dev %x, bn %x, bcount %lx, %c\n", 679 bp, bp->b_dev, bp->b_blkno, bp->b_bcount, 680 (bp->b_flags & B_READ) ? 'R' : 'W'); 681 #endif 682 bn = bp->b_blkno; 683 sz = howmany(bp->b_bcount, DEV_BSIZE); 684 pinfo = &rs->sc_dkdev.dk_label->d_partitions[rdpart(bp->b_dev)]; 685 686 /* Don't perform partition translation on RAW_PART. */ 687 offset = (rdpart(bp->b_dev) == RAW_PART) ? 0 : pinfo->p_offset; 688 689 if (rdpart(bp->b_dev) != RAW_PART) { 690 /* 691 * XXX This block of code belongs in 692 * XXX bounds_check_with_label() 693 */ 694 695 if (bn < 0 || bn + sz > pinfo->p_size) { 696 sz = pinfo->p_size - bn; 697 if (sz == 0) { 698 bp->b_resid = bp->b_bcount; 699 goto done; 700 } 701 if (sz < 0) { 702 bp->b_error = EINVAL; 703 goto bad; 704 } 705 bp->b_bcount = dbtob(sz); 706 } 707 /* 708 * Check for write to write protected label 709 */ 710 if (bn + offset <= LABELSECTOR && 711 #if LABELSECTOR != 0 712 bn + offset + sz > LABELSECTOR && 713 #endif 714 !(bp->b_flags & B_READ) && !(rs->sc_flags & RDF_WLABEL)) { 715 bp->b_error = EROFS; 716 goto bad; 717 } 718 } 719 bp->b_rawblkno = bn + offset; 720 s = splbio(); 721 disksort_blkno(&rs->sc_tab, bp); 722 if (rs->sc_active == 0) { 723 rs->sc_active = 1; 724 rdustart(rs); 725 } 726 splx(s); 727 return; 728 bad: 729 bp->b_flags |= B_ERROR; 730 done: 731 biodone(bp); 732 } 733 734 /* 735 * Called from timeout() when handling maintenance releases 736 */ 737 void 738 rdrestart(arg) 739 void *arg; 740 { 741 int s = splbio(); 742 rdustart((struct rd_softc *)arg); 743 splx(s); 744 } 745 746 void 747 rdustart(rs) 748 struct rd_softc *rs; 749 { 750 struct buf *bp; 751 752 bp = BUFQ_FIRST(&rs->sc_tab); 753 rs->sc_addr = bp->b_data; 754 rs->sc_resid = bp->b_bcount; 755 if (hpibreq(rs->sc_dev.dv_parent, &rs->sc_hq)) 756 rdstart(rs); 757 } 758 759 struct buf * 760 rdfinish(rs, bp) 761 struct rd_softc *rs; 762 struct buf *bp; 763 { 764 765 rs->sc_errcnt = 0; 766 BUFQ_REMOVE(&rs->sc_tab, bp); 767 bp->b_resid = 0; 768 biodone(bp); 769 hpibfree(rs->sc_dev.dv_parent, &rs->sc_hq); 770 if ((bp = BUFQ_FIRST(&rs->sc_tab)) != NULL) 771 return (bp); 772 rs->sc_active = 0; 773 if (rs->sc_flags & RDF_WANTED) { 774 rs->sc_flags &= ~RDF_WANTED; 775 wakeup((caddr_t)&rs->sc_tab); 776 } 777 return (NULL); 778 } 779 780 void 781 rdstart(arg) 782 void *arg; 783 { 784 struct rd_softc *rs = arg; 785 struct buf *bp = BUFQ_FIRST(&rs->sc_tab); 786 int part, ctlr, slave; 787 788 ctlr = rs->sc_dev.dv_parent->dv_unit; 789 slave = rs->sc_slave; 790 791 again: 792 #ifdef DEBUG 793 if (rddebug & RDB_FOLLOW) 794 printf("rdstart(%s): bp %p, %c\n", rs->sc_dev.dv_xname, bp, 795 (bp->b_flags & B_READ) ? 'R' : 'W'); 796 #endif 797 part = rdpart(bp->b_dev); 798 rs->sc_flags |= RDF_SEEK; 799 rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); 800 rs->sc_ioc.c_volume = C_SVOL(0); 801 rs->sc_ioc.c_saddr = C_SADDR; 802 rs->sc_ioc.c_hiaddr = 0; 803 rs->sc_ioc.c_addr = RDBTOS(bp->b_rawblkno); 804 rs->sc_ioc.c_nop2 = C_NOP; 805 rs->sc_ioc.c_slen = C_SLEN; 806 rs->sc_ioc.c_len = rs->sc_resid; 807 rs->sc_ioc.c_cmd = bp->b_flags & B_READ ? C_READ : C_WRITE; 808 #ifdef DEBUG 809 if (rddebug & RDB_IO) 810 printf("rdstart: hpibsend(%x, %x, %x, %p, %x)\n", 811 ctlr, slave, C_CMD, 812 &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2); 813 #endif 814 if (hpibsend(ctlr, slave, C_CMD, &rs->sc_ioc.c_unit, 815 sizeof(rs->sc_ioc)-2) == sizeof(rs->sc_ioc)-2) { 816 817 /* Instrumentation. */ 818 disk_busy(&rs->sc_dkdev); 819 rs->sc_dkdev.dk_seek++; 820 821 #ifdef DEBUG 822 if (rddebug & RDB_IO) 823 printf("rdstart: hpibawait(%x)\n", ctlr); 824 #endif 825 hpibawait(ctlr); 826 return; 827 } 828 /* 829 * Experience has shown that the hpibwait in this hpibsend will 830 * occasionally timeout. It appears to occur mostly on old 7914 831 * drives with full maintenance tracks. We should probably 832 * integrate this with the backoff code in rderror. 833 */ 834 #ifdef DEBUG 835 if (rddebug & RDB_ERROR) 836 printf("%s: rdstart: cmd %x adr %lx blk %d len %d ecnt %d\n", 837 rs->sc_dev.dv_xname, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, 838 bp->b_blkno, rs->sc_resid, rs->sc_errcnt); 839 rs->sc_stats.rdretries++; 840 #endif 841 rs->sc_flags &= ~RDF_SEEK; 842 rdreset(rs); 843 if (rs->sc_errcnt++ < RDRETRY) 844 goto again; 845 printf("%s: rdstart err: cmd 0x%x sect %ld blk %d len %d\n", 846 rs->sc_dev.dv_xname, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, 847 bp->b_blkno, rs->sc_resid); 848 bp->b_flags |= B_ERROR; 849 bp->b_error = EIO; 850 bp = rdfinish(rs, bp); 851 if (bp) { 852 rs->sc_addr = bp->b_data; 853 rs->sc_resid = bp->b_bcount; 854 if (hpibreq(rs->sc_dev.dv_parent, &rs->sc_hq)) 855 goto again; 856 } 857 } 858 859 void 860 rdgo(arg) 861 void *arg; 862 { 863 struct rd_softc *rs = arg; 864 struct buf *bp = BUFQ_FIRST(&rs->sc_tab); 865 int rw, ctlr, slave; 866 867 ctlr = rs->sc_dev.dv_parent->dv_unit; 868 slave = rs->sc_slave; 869 870 rw = bp->b_flags & B_READ; 871 872 /* Instrumentation. */ 873 disk_busy(&rs->sc_dkdev); 874 875 #ifdef USELEDS 876 ledcontrol(0, 0, LED_DISK); 877 #endif 878 hpibgo(ctlr, slave, C_EXEC, rs->sc_addr, rs->sc_resid, rw, rw != 0); 879 } 880 881 /* ARGSUSED */ 882 void 883 rdintr(arg) 884 void *arg; 885 { 886 struct rd_softc *rs = arg; 887 int unit = rs->sc_dev.dv_unit; 888 struct buf *bp = BUFQ_FIRST(&rs->sc_tab); 889 u_char stat = 13; /* in case hpibrecv fails */ 890 int rv, restart, ctlr, slave; 891 892 ctlr = rs->sc_dev.dv_parent->dv_unit; 893 slave = rs->sc_slave; 894 895 #ifdef DEBUG 896 if (rddebug & RDB_FOLLOW) 897 printf("rdintr(%d): bp %p, %c, flags %x\n", unit, bp, 898 (bp->b_flags & B_READ) ? 'R' : 'W', rs->sc_flags); 899 if (bp == NULL) { 900 printf("%s: bp == NULL\n", rs->sc_dev.dv_xname); 901 return; 902 } 903 #endif 904 disk_unbusy(&rs->sc_dkdev, (bp->b_bcount - bp->b_resid)); 905 906 if (rs->sc_flags & RDF_SEEK) { 907 rs->sc_flags &= ~RDF_SEEK; 908 if (hpibustart(ctlr)) 909 rdgo(rs); 910 return; 911 } 912 if ((rs->sc_flags & RDF_SWAIT) == 0) { 913 #ifdef DEBUG 914 rs->sc_stats.rdpolltries++; 915 #endif 916 if (hpibpptest(ctlr, slave) == 0) { 917 #ifdef DEBUG 918 rs->sc_stats.rdpollwaits++; 919 #endif 920 921 /* Instrumentation. */ 922 disk_busy(&rs->sc_dkdev); 923 rs->sc_flags |= RDF_SWAIT; 924 hpibawait(ctlr); 925 return; 926 } 927 } else 928 rs->sc_flags &= ~RDF_SWAIT; 929 rv = hpibrecv(ctlr, slave, C_QSTAT, &stat, 1); 930 if (rv != 1 || stat) { 931 #ifdef DEBUG 932 if (rddebug & RDB_ERROR) 933 printf("rdintr: recv failed or bad stat %d\n", stat); 934 #endif 935 restart = rderror(unit); 936 #ifdef DEBUG 937 rs->sc_stats.rdretries++; 938 #endif 939 if (rs->sc_errcnt++ < RDRETRY) { 940 if (restart) 941 rdstart(rs); 942 return; 943 } 944 bp->b_flags |= B_ERROR; 945 bp->b_error = EIO; 946 } 947 if (rdfinish(rs, bp)) 948 rdustart(rs); 949 #if NRND > 0 950 rnd_add_uint32(&rs->rnd_source, bp->b_blkno); 951 #endif 952 } 953 954 int 955 rdstatus(rs) 956 struct rd_softc *rs; 957 { 958 int c, s; 959 u_char stat; 960 int rv; 961 962 c = rs->sc_dev.dv_parent->dv_unit; 963 s = rs->sc_slave; 964 rs->sc_rsc.c_unit = C_SUNIT(rs->sc_punit); 965 rs->sc_rsc.c_sram = C_SRAM; 966 rs->sc_rsc.c_ram = C_RAM; 967 rs->sc_rsc.c_cmd = C_STATUS; 968 bzero((caddr_t)&rs->sc_stat, sizeof(rs->sc_stat)); 969 rv = hpibsend(c, s, C_CMD, &rs->sc_rsc, sizeof(rs->sc_rsc)); 970 if (rv != sizeof(rs->sc_rsc)) { 971 #ifdef DEBUG 972 if (rddebug & RDB_STATUS) 973 printf("rdstatus: send C_CMD failed %d != %d\n", 974 rv, sizeof(rs->sc_rsc)); 975 #endif 976 return(1); 977 } 978 rv = hpibrecv(c, s, C_EXEC, &rs->sc_stat, sizeof(rs->sc_stat)); 979 if (rv != sizeof(rs->sc_stat)) { 980 #ifdef DEBUG 981 if (rddebug & RDB_STATUS) 982 printf("rdstatus: send C_EXEC failed %d != %d\n", 983 rv, sizeof(rs->sc_stat)); 984 #endif 985 return(1); 986 } 987 rv = hpibrecv(c, s, C_QSTAT, &stat, 1); 988 if (rv != 1 || stat) { 989 #ifdef DEBUG 990 if (rddebug & RDB_STATUS) 991 printf("rdstatus: recv failed %d or bad stat %d\n", 992 rv, stat); 993 #endif 994 return(1); 995 } 996 return(0); 997 } 998 999 /* 1000 * Deal with errors. 1001 * Returns 1 if request should be restarted, 1002 * 0 if we should just quietly give up. 1003 */ 1004 int 1005 rderror(unit) 1006 int unit; 1007 { 1008 struct rd_softc *rs = rd_cd.cd_devs[unit]; 1009 struct rd_stat *sp; 1010 struct buf *bp; 1011 daddr_t hwbn, pbn; 1012 char *hexstr __P((int, int)); /* XXX */ 1013 1014 if (rdstatus(rs)) { 1015 #ifdef DEBUG 1016 printf("%s: couldn't get status\n", rs->sc_dev.dv_xname); 1017 #endif 1018 rdreset(rs); 1019 return(1); 1020 } 1021 sp = &rs->sc_stat; 1022 if (sp->c_fef & FEF_REXMT) 1023 return(1); 1024 if (sp->c_fef & FEF_PF) { 1025 rdreset(rs); 1026 return(1); 1027 } 1028 /* 1029 * Unit requests release for internal maintenance. 1030 * We just delay awhile and try again later. Use expontially 1031 * increasing backoff ala ethernet drivers since we don't really 1032 * know how long the maintenance will take. With RDWAITC and 1033 * RDRETRY as defined, the range is 1 to 32 seconds. 1034 */ 1035 if (sp->c_fef & FEF_IMR) { 1036 extern int hz; 1037 int rdtimo = RDWAITC << rs->sc_errcnt; 1038 #ifdef DEBUG 1039 printf("%s: internal maintenance, %d second timeout\n", 1040 rs->sc_dev.dv_xname, rdtimo); 1041 rs->sc_stats.rdtimeouts++; 1042 #endif 1043 hpibfree(rs->sc_dev.dv_parent, &rs->sc_hq); 1044 callout_reset(&rs->sc_restart_ch, rdtimo * hz, rdrestart, rs); 1045 return(0); 1046 } 1047 /* 1048 * Only report error if we have reached the error reporting 1049 * threshhold. By default, this will only report after the 1050 * retry limit has been exceeded. 1051 */ 1052 if (rs->sc_errcnt < rderrthresh) 1053 return(1); 1054 1055 /* 1056 * First conjure up the block number at which the error occured. 1057 * Note that not all errors report a block number, in that case 1058 * we just use b_blkno. 1059 */ 1060 bp = BUFQ_FIRST(&rs->sc_tab); 1061 pbn = rs->sc_dkdev.dk_label->d_partitions[rdpart(bp->b_dev)].p_offset; 1062 if ((sp->c_fef & FEF_CU) || (sp->c_fef & FEF_DR) || 1063 (sp->c_ief & IEF_RRMASK)) { 1064 hwbn = RDBTOS(pbn + bp->b_blkno); 1065 pbn = bp->b_blkno; 1066 } else { 1067 hwbn = sp->c_blk; 1068 pbn = RDSTOB(hwbn) - pbn; 1069 } 1070 /* 1071 * Now output a generic message suitable for badsect. 1072 * Note that we don't use harderr cuz it just prints 1073 * out b_blkno which is just the beginning block number 1074 * of the transfer, not necessary where the error occured. 1075 */ 1076 printf("%s%c: hard error sn%d\n", rs->sc_dev.dv_xname, 1077 'a'+rdpart(bp->b_dev), pbn); 1078 /* 1079 * Now report the status as returned by the hardware with 1080 * attempt at interpretation (unless debugging). 1081 */ 1082 printf("%s %s error:", rs->sc_dev.dv_xname, 1083 (bp->b_flags & B_READ) ? "read" : "write"); 1084 #ifdef DEBUG 1085 if (rddebug & RDB_ERROR) { 1086 /* status info */ 1087 printf("\n volume: %d, unit: %d\n", 1088 (sp->c_vu>>4)&0xF, sp->c_vu&0xF); 1089 rdprinterr("reject", sp->c_ref, err_reject); 1090 rdprinterr("fault", sp->c_fef, err_fault); 1091 rdprinterr("access", sp->c_aef, err_access); 1092 rdprinterr("info", sp->c_ief, err_info); 1093 printf(" block: %d, P1-P10: ", hwbn); 1094 printf("0x%x", *(u_int *)&sp->c_raw[0]); 1095 printf("0x%x", *(u_int *)&sp->c_raw[4]); 1096 printf("0x%x\n", *(u_short *)&sp->c_raw[8]); 1097 /* command */ 1098 printf(" ioc: "); 1099 printf("0x%x", *(u_int *)&rs->sc_ioc.c_pad); 1100 printf("0x%x", *(u_short *)&rs->sc_ioc.c_hiaddr); 1101 printf("0x%x", *(u_int *)&rs->sc_ioc.c_addr); 1102 printf("0x%x", *(u_short *)&rs->sc_ioc.c_nop2); 1103 printf("0x%x", *(u_int *)&rs->sc_ioc.c_len); 1104 printf("0x%x\n", *(u_short *)&rs->sc_ioc.c_cmd); 1105 return(1); 1106 } 1107 #endif 1108 printf(" v%d u%d, R0x%x F0x%x A0x%x I0x%x\n", 1109 (sp->c_vu>>4)&0xF, sp->c_vu&0xF, 1110 sp->c_ref, sp->c_fef, sp->c_aef, sp->c_ief); 1111 printf("P1-P10: "); 1112 printf("0x%x", *(u_int *)&sp->c_raw[0]); 1113 printf("0x%x", *(u_int *)&sp->c_raw[4]); 1114 printf("0x%x\n", *(u_short *)&sp->c_raw[8]); 1115 return(1); 1116 } 1117 1118 int 1119 rdread(dev, uio, flags) 1120 dev_t dev; 1121 struct uio *uio; 1122 int flags; 1123 { 1124 1125 return (physio(rdstrategy, NULL, dev, B_READ, minphys, uio)); 1126 } 1127 1128 int 1129 rdwrite(dev, uio, flags) 1130 dev_t dev; 1131 struct uio *uio; 1132 int flags; 1133 { 1134 1135 return (physio(rdstrategy, NULL, dev, B_WRITE, minphys, uio)); 1136 } 1137 1138 int 1139 rdioctl(dev, cmd, data, flag, p) 1140 dev_t dev; 1141 u_long cmd; 1142 caddr_t data; 1143 int flag; 1144 struct proc *p; 1145 { 1146 int unit = rdunit(dev); 1147 struct rd_softc *sc = rd_cd.cd_devs[unit]; 1148 struct disklabel *lp = sc->sc_dkdev.dk_label; 1149 int error, flags; 1150 1151 switch (cmd) { 1152 case DIOCGDINFO: 1153 *(struct disklabel *)data = *lp; 1154 return (0); 1155 1156 case DIOCGPART: 1157 ((struct partinfo *)data)->disklab = lp; 1158 ((struct partinfo *)data)->part = 1159 &lp->d_partitions[rdpart(dev)]; 1160 return (0); 1161 1162 case DIOCWLABEL: 1163 if ((flag & FWRITE) == 0) 1164 return (EBADF); 1165 if (*(int *)data) 1166 sc->sc_flags |= RDF_WLABEL; 1167 else 1168 sc->sc_flags &= ~RDF_WLABEL; 1169 return (0); 1170 1171 case DIOCSDINFO: 1172 if ((flag & FWRITE) == 0) 1173 return (EBADF); 1174 return (setdisklabel(lp, (struct disklabel *)data, 1175 (sc->sc_flags & RDF_WLABEL) ? 0 1176 : sc->sc_dkdev.dk_openmask, 1177 (struct cpu_disklabel *)0)); 1178 1179 case DIOCWDINFO: 1180 if ((flag & FWRITE) == 0) 1181 return (EBADF); 1182 error = setdisklabel(lp, (struct disklabel *)data, 1183 (sc->sc_flags & RDF_WLABEL) ? 0 1184 : sc->sc_dkdev.dk_openmask, 1185 (struct cpu_disklabel *)0); 1186 if (error) 1187 return (error); 1188 flags = sc->sc_flags; 1189 sc->sc_flags = RDF_ALIVE | RDF_WLABEL; 1190 error = writedisklabel(rdlabdev(dev), rdstrategy, lp, 1191 (struct cpu_disklabel *)0); 1192 sc->sc_flags = flags; 1193 return (error); 1194 } 1195 return(EINVAL); 1196 } 1197 1198 int 1199 rdsize(dev) 1200 dev_t dev; 1201 { 1202 int unit = rdunit(dev); 1203 struct rd_softc *rs; 1204 int psize, didopen = 0; 1205 1206 if (unit >= rd_cd.cd_ndevs || 1207 (rs = rd_cd.cd_devs[unit]) == NULL || 1208 (rs->sc_flags & RDF_ALIVE) == 0) 1209 return (-1); 1210 1211 /* 1212 * We get called very early on (via swapconf) 1213 * without the device being open so we may need 1214 * to handle it here. 1215 */ 1216 if (rs->sc_dkdev.dk_openmask == 0) { 1217 if (rdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) 1218 return(-1); 1219 didopen = 1; 1220 } 1221 psize = rs->sc_dkdev.dk_label->d_partitions[rdpart(dev)].p_size * 1222 (rs->sc_dkdev.dk_label->d_secsize / DEV_BSIZE); 1223 if (didopen) 1224 (void) rdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); 1225 return (psize); 1226 } 1227 1228 #ifdef DEBUG 1229 void 1230 rdprinterr(str, err, tab) 1231 char *str; 1232 short err; 1233 char **tab; 1234 { 1235 int i; 1236 int printed; 1237 1238 if (err == 0) 1239 return; 1240 printf(" %s error %d field:", str, err); 1241 printed = 0; 1242 for (i = 0; i < 16; i++) 1243 if (err & (0x8000 >> i)) 1244 printf("%s%s", printed++ ? " + " : " ", tab[i]); 1245 printf("\n"); 1246 } 1247 #endif 1248 1249 static int rddoingadump; /* simple mutex */ 1250 1251 /* 1252 * Non-interrupt driven, non-dma dump routine. 1253 */ 1254 int 1255 rddump(dev, blkno, va, size) 1256 dev_t dev; 1257 daddr_t blkno; 1258 caddr_t va; 1259 size_t size; 1260 { 1261 int sectorsize; /* size of a disk sector */ 1262 int nsects; /* number of sectors in partition */ 1263 int sectoff; /* sector offset of partition */ 1264 int totwrt; /* total number of sectors left to write */ 1265 int nwrt; /* current number of sectors to write */ 1266 int unit, part; 1267 int ctlr, slave; 1268 struct rd_softc *rs; 1269 struct disklabel *lp; 1270 char stat; 1271 1272 /* Check for recursive dump; if so, punt. */ 1273 if (rddoingadump) 1274 return (EFAULT); 1275 rddoingadump = 1; 1276 1277 /* Decompose unit and partition. */ 1278 unit = rdunit(dev); 1279 part = rdpart(dev); 1280 1281 /* Make sure dump device is ok. */ 1282 if (unit >= rd_cd.cd_ndevs || 1283 (rs = rd_cd.cd_devs[unit]) == NULL || 1284 (rs->sc_flags & RDF_ALIVE) == 0) 1285 return (ENXIO); 1286 1287 ctlr = rs->sc_dev.dv_parent->dv_unit; 1288 slave = rs->sc_slave; 1289 1290 /* 1291 * Convert to disk sectors. Request must be a multiple of size. 1292 */ 1293 lp = rs->sc_dkdev.dk_label; 1294 sectorsize = lp->d_secsize; 1295 if ((size % sectorsize) != 0) 1296 return (EFAULT); 1297 totwrt = size / sectorsize; 1298 blkno = dbtob(blkno) / sectorsize; /* blkno in DEV_BSIZE units */ 1299 1300 nsects = lp->d_partitions[part].p_size; 1301 sectoff = lp->d_partitions[part].p_offset; 1302 1303 /* Check transfer bounds against partition size. */ 1304 if ((blkno < 0) || (blkno + totwrt) > nsects) 1305 return (EINVAL); 1306 1307 /* Offset block number to start of partition. */ 1308 blkno += sectoff; 1309 1310 while (totwrt > 0) { 1311 nwrt = totwrt; /* XXX */ 1312 #ifndef RD_DUMP_NOT_TRUSTED 1313 /* 1314 * Fill out and send HPIB command. 1315 */ 1316 rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); 1317 rs->sc_ioc.c_volume = C_SVOL(0); 1318 rs->sc_ioc.c_saddr = C_SADDR; 1319 rs->sc_ioc.c_hiaddr = 0; 1320 rs->sc_ioc.c_addr = RDBTOS(blkno); 1321 rs->sc_ioc.c_nop2 = C_NOP; 1322 rs->sc_ioc.c_slen = C_SLEN; 1323 rs->sc_ioc.c_len = nwrt * sectorsize; 1324 rs->sc_ioc.c_cmd = C_WRITE; 1325 hpibsend(ctlr, slave, C_CMD, &rs->sc_ioc.c_unit, 1326 sizeof(rs->sc_ioc)-2); 1327 if (hpibswait(ctlr, slave)) 1328 return (EIO); 1329 1330 /* 1331 * Send the data. 1332 */ 1333 hpibsend(ctlr, slave, C_EXEC, va, nwrt * sectorsize); 1334 (void) hpibswait(ctlr, slave); 1335 hpibrecv(ctlr, slave, C_QSTAT, &stat, 1); 1336 if (stat) 1337 return (EIO); 1338 #else /* RD_DUMP_NOT_TRUSTED */ 1339 /* Let's just talk about this first... */ 1340 printf("%s: dump addr %p, blk %d\n", sc->sc_dev.dv_xname, 1341 va, blkno); 1342 delay(500 * 1000); /* half a second */ 1343 #endif /* RD_DUMP_NOT_TRUSTED */ 1344 1345 /* update block count */ 1346 totwrt -= nwrt; 1347 blkno += nwrt; 1348 va += sectorsize * nwrt; 1349 } 1350 rddoingadump = 0; 1351 return (0); 1352 } 1353