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