1 /* $NetBSD: rd.c,v 1.85 2008/03/29 06:47:08 tsutsui 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.85 2008/03/29 06:47:08 tsutsui 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/bufq.h> 129 #include <sys/conf.h> 130 #include <sys/device.h> 131 #include <sys/disk.h> 132 #include <sys/disklabel.h> 133 #include <sys/fcntl.h> 134 #include <sys/ioctl.h> 135 #include <sys/proc.h> 136 #include <sys/stat.h> 137 138 #if NRND > 0 139 #include <sys/rnd.h> 140 #endif 141 142 #include <hp300/dev/hpibvar.h> 143 144 #include <hp300/dev/rdreg.h> 145 #include <hp300/dev/rdvar.h> 146 147 #ifdef USELEDS 148 #include <hp300/hp300/leds.h> 149 #endif 150 151 #include "ioconf.h" 152 153 int rderrthresh = RDRETRY-1; /* when to start reporting errors */ 154 155 #ifdef DEBUG 156 /* error message tables */ 157 static const char *err_reject[] = { 158 0, 0, 159 "channel parity error", /* 0x2000 */ 160 0, 0, 161 "illegal opcode", /* 0x0400 */ 162 "module addressing", /* 0x0200 */ 163 "address bounds", /* 0x0100 */ 164 "parameter bounds", /* 0x0080 */ 165 "illegal parameter", /* 0x0040 */ 166 "message sequence", /* 0x0020 */ 167 0, 168 "message length", /* 0x0008 */ 169 0, 0, 0 170 }; 171 172 static const char *err_fault[] = { 173 0, 174 "cross unit", /* 0x4000 */ 175 0, 176 "controller fault", /* 0x1000 */ 177 0, 0, 178 "unit fault", /* 0x0200 */ 179 0, 180 "diagnostic result", /* 0x0080 */ 181 0, 182 "operator release request", /* 0x0020 */ 183 "diagnostic release request", /* 0x0010 */ 184 "internal maintenance release request", /* 0x0008 */ 185 0, 186 "power fail", /* 0x0002 */ 187 "retransmit" /* 0x0001 */ 188 }; 189 190 static const char *err_access[] = { 191 "illegal parallel operation", /* 0x8000 */ 192 "uninitialized media", /* 0x4000 */ 193 "no spares available", /* 0x2000 */ 194 "not ready", /* 0x1000 */ 195 "write protect", /* 0x0800 */ 196 "no data found", /* 0x0400 */ 197 0, 0, 198 "unrecoverable data overflow", /* 0x0080 */ 199 "unrecoverable data", /* 0x0040 */ 200 0, 201 "end of file", /* 0x0010 */ 202 "end of volume", /* 0x0008 */ 203 0, 0, 0 204 }; 205 206 static const char *err_info[] = { 207 "operator release request", /* 0x8000 */ 208 "diagnostic release request", /* 0x4000 */ 209 "internal maintenance release request", /* 0x2000 */ 210 "media wear", /* 0x1000 */ 211 "latency induced", /* 0x0800 */ 212 0, 0, 213 "auto sparing invoked", /* 0x0100 */ 214 0, 215 "recoverable data overflow", /* 0x0040 */ 216 "marginal data", /* 0x0020 */ 217 "recoverable data", /* 0x0010 */ 218 0, 219 "maintenance track overflow", /* 0x0004 */ 220 0, 0 221 }; 222 223 int rddebug = 0x80; 224 #define RDB_FOLLOW 0x01 225 #define RDB_STATUS 0x02 226 #define RDB_IDENT 0x04 227 #define RDB_IO 0x08 228 #define RDB_ASYNC 0x10 229 #define RDB_ERROR 0x80 230 #endif 231 232 /* 233 * Misc. HW description, indexed by sc_type. 234 * Nothing really critical here, could do without it. 235 */ 236 static const struct rdidentinfo rdidentinfo[] = { 237 { RD7946AID, 0, "7945A", NRD7945ABPT, 238 NRD7945ATRK, 968, 108416 }, 239 240 { RD9134DID, 1, "9134D", NRD9134DBPT, 241 NRD9134DTRK, 303, 29088 }, 242 243 { RD9134LID, 1, "9122S", NRD9122SBPT, 244 NRD9122STRK, 77, 1232 }, 245 246 { RD7912PID, 0, "7912P", NRD7912PBPT, 247 NRD7912PTRK, 572, 128128 }, 248 249 { RD7914PID, 0, "7914P", NRD7914PBPT, 250 NRD7914PTRK, 1152, 258048 }, 251 252 { RD7958AID, 0, "7958A", NRD7958ABPT, 253 NRD7958ATRK, 1013, 255276 }, 254 255 { RD7957AID, 0, "7957A", NRD7957ABPT, 256 NRD7957ATRK, 1036, 159544 }, 257 258 { RD7933HID, 0, "7933H", NRD7933HBPT, 259 NRD7933HTRK, 1321, 789958 }, 260 261 { RD9134LID, 1, "9134L", NRD9134LBPT, 262 NRD9134LTRK, 973, 77840 }, 263 264 { RD7936HID, 0, "7936H", NRD7936HBPT, 265 NRD7936HTRK, 698, 600978 }, 266 267 { RD7937HID, 0, "7937H", NRD7937HBPT, 268 NRD7937HTRK, 698, 1116102 }, 269 270 { RD7914CTID, 0, "7914CT", NRD7914PBPT, 271 NRD7914PTRK, 1152, 258048 }, 272 273 { RD7946AID, 0, "7946A", NRD7945ABPT, 274 NRD7945ATRK, 968, 108416 }, 275 276 { RD9134LID, 1, "9122D", NRD9122SBPT, 277 NRD9122STRK, 77, 1232 }, 278 279 { RD7957BID, 0, "7957B", NRD7957BBPT, 280 NRD7957BTRK, 1269, 159894 }, 281 282 { RD7958BID, 0, "7958B", NRD7958BBPT, 283 NRD7958BTRK, 786, 297108 }, 284 285 { RD7959BID, 0, "7959B", NRD7959BBPT, 286 NRD7959BTRK, 1572, 594216 }, 287 288 { RD2200AID, 0, "2200A", NRD2200ABPT, 289 NRD2200ATRK, 1449, 654948 }, 290 291 { RD2203AID, 0, "2203A", NRD2203ABPT, 292 NRD2203ATRK, 1449, 1309896 } 293 }; 294 static const int numrdidentinfo = __arraycount(rdidentinfo); 295 296 static int rdident(struct device *, struct rd_softc *, 297 struct hpibbus_attach_args *); 298 static void rdreset(struct rd_softc *); 299 static void rdustart(struct rd_softc *); 300 static int rdgetinfo(dev_t); 301 static void rdrestart(void *); 302 static struct buf *rdfinish(struct rd_softc *, struct buf *); 303 304 static void rdgetdefaultlabel(struct rd_softc *, struct disklabel *); 305 static void rdrestart(void *); 306 static void rdustart(struct rd_softc *); 307 static struct buf *rdfinish(struct rd_softc *, struct buf *); 308 static void rdstart(void *); 309 static void rdgo(void *); 310 static void rdintr(void *); 311 static int rdstatus(struct rd_softc *); 312 static int rderror(int); 313 #ifdef DEBUG 314 static void rdprinterr(const char *, short, const char **); 315 #endif 316 317 static int rdmatch(device_t, cfdata_t, void *); 318 static void rdattach(device_t, device_t, void *); 319 320 CFATTACH_DECL_NEW(rd, sizeof(struct rd_softc), 321 rdmatch, rdattach, NULL, NULL); 322 323 static dev_type_open(rdopen); 324 static dev_type_close(rdclose); 325 static dev_type_read(rdread); 326 static dev_type_write(rdwrite); 327 static dev_type_ioctl(rdioctl); 328 static dev_type_strategy(rdstrategy); 329 static dev_type_dump(rddump); 330 static dev_type_size(rdsize); 331 332 const struct bdevsw rd_bdevsw = { 333 rdopen, rdclose, rdstrategy, rdioctl, rddump, rdsize, D_DISK 334 }; 335 336 const struct cdevsw rd_cdevsw = { 337 rdopen, rdclose, rdread, rdwrite, rdioctl, 338 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 339 }; 340 341 static int 342 rdmatch(device_t parent, cfdata_t cf, void *aux) 343 { 344 struct hpibbus_attach_args *ha = aux; 345 346 /* 347 * Set punit if operator specified one in the kernel 348 * configuration file. 349 */ 350 if (cf->hpibbuscf_punit != HPIBBUSCF_PUNIT_DEFAULT && 351 cf->hpibbuscf_punit < HPIB_NPUNITS) 352 ha->ha_punit = cf->hpibbuscf_punit; 353 354 if (rdident(parent, NULL, ha) == 0) { 355 /* 356 * XXX Some aging HP-IB drives are slow to 357 * XXX respond; give them a chance to catch 358 * XXX up and probe them again. 359 */ 360 delay(10000); 361 ha->ha_id = hpibid(device_unit(parent), ha->ha_slave); 362 return rdident(parent, NULL, ha); 363 } 364 return 1; 365 } 366 367 static void 368 rdattach(device_t parent, device_t self, void *aux) 369 { 370 struct rd_softc *sc = device_private(self); 371 struct hpibbus_attach_args *ha = aux; 372 373 sc->sc_dev = self; 374 bufq_alloc(&sc->sc_tab, "disksort", BUFQ_SORT_RAWBLOCK); 375 376 if (rdident(parent, sc, ha) == 0) { 377 aprint_error(": didn't respond to describe command!\n"); 378 return; 379 } 380 381 /* 382 * Initialize and attach the disk structure. 383 */ 384 memset(&sc->sc_dkdev, 0, sizeof(sc->sc_dkdev)); 385 disk_init(&sc->sc_dkdev, device_xname(sc->sc_dev), NULL); 386 disk_attach(&sc->sc_dkdev); 387 388 sc->sc_slave = ha->ha_slave; 389 sc->sc_punit = ha->ha_punit; 390 391 callout_init(&sc->sc_restart_ch, 0); 392 393 /* Initialize the hpib job queue entry */ 394 sc->sc_hq.hq_softc = sc; 395 sc->sc_hq.hq_slave = sc->sc_slave; 396 sc->sc_hq.hq_start = rdstart; 397 sc->sc_hq.hq_go = rdgo; 398 sc->sc_hq.hq_intr = rdintr; 399 400 sc->sc_flags = RDF_ALIVE; 401 #ifdef DEBUG 402 /* always report errors */ 403 if (rddebug & RDB_ERROR) 404 rderrthresh = 0; 405 #endif 406 #if NRND > 0 407 /* 408 * attach the device into the random source list 409 */ 410 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 411 RND_TYPE_DISK, 0); 412 #endif 413 } 414 415 static int 416 rdident(device_t parent, struct rd_softc *sc, 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 = device_unit(parent); 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 aprint_debug("\n"); 466 aprint_debug_dev(sc->sc_dev, "name: %x ('%s')\n", 467 desc->d_name, name); 468 aprint_debug(" iuw %x, maxxfr %d, ctype %d\n", 469 desc->d_iuw, desc->d_cmaxxfr, desc->d_ctype); 470 aprint_debug(" utype %d, bps %d, blkbuf %d, burst %d," 471 " blktime %d\n", 472 desc->d_utype, desc->d_sectsize, 473 desc->d_blkbuf, desc->d_burstsize, desc->d_blocktime); 474 aprint_debug(" avxfr %d, ort %d, atp %d, maxint %d, fv %x" 475 ", rv %x\n", 476 desc->d_uavexfr, desc->d_retry, desc->d_access, 477 desc->d_maxint, desc->d_fvbyte, desc->d_rvbyte); 478 aprint_debug(" maxcyl/head/sect %d/%d/%d, maxvsect %d," 479 " inter %d\n", 480 desc->d_maxcyl, desc->d_maxhead, desc->d_maxsect, 481 desc->d_maxvsectl, desc->d_interleave); 482 aprint_normal("%s", device_xname(sc->sc_dev)); 483 } 484 #endif 485 486 /* 487 * Take care of a couple of anomolies: 488 * 1. 7945A and 7946A both return same HW id 489 * 2. 9122S and 9134D both return same HW id 490 * 3. 9122D and 9134L both return same HW id 491 */ 492 switch (ha->ha_id) { 493 case RD7946AID: 494 if (memcmp(name, "079450", 6) == 0) 495 id = RD7945A; 496 else 497 id = RD7946A; 498 break; 499 500 case RD9134LID: 501 if (memcmp(name, "091340", 6) == 0) 502 id = RD9134L; 503 else 504 id = RD9122D; 505 break; 506 507 case RD9134DID: 508 if (memcmp(name, "091220", 6) == 0) 509 id = RD9122S; 510 else 511 id = RD9134D; 512 break; 513 } 514 515 sc->sc_type = id; 516 517 /* 518 * XXX We use DEV_BSIZE instead of the sector size value pulled 519 * XXX off the driver because all of this code assumes 512 byte 520 * XXX blocks. ICK! 521 */ 522 aprint_normal(": %s\n", rdidentinfo[id].ri_desc); 523 aprint_normal_dev(sc->sc_dev, "%d cylinders, %d heads, %d blocks," 524 " %d bytes/block\n", 525 rdidentinfo[id].ri_ncyl, 526 rdidentinfo[id].ri_ntpc, rdidentinfo[id].ri_nblocks, 527 DEV_BSIZE); 528 529 return 1; 530 } 531 532 static void 533 rdreset(struct rd_softc *sc) 534 { 535 int ctlr = device_unit(device_parent(sc->sc_dev)); 536 int slave = sc->sc_slave; 537 u_char stat; 538 539 sc->sc_clear.c_unit = C_SUNIT(sc->sc_punit); 540 sc->sc_clear.c_cmd = C_CLEAR; 541 hpibsend(ctlr, slave, C_TCMD, &sc->sc_clear, sizeof(sc->sc_clear)); 542 hpibswait(ctlr, slave); 543 hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 544 545 sc->sc_src.c_unit = C_SUNIT(RDCTLR); 546 sc->sc_src.c_nop = C_NOP; 547 sc->sc_src.c_cmd = C_SREL; 548 sc->sc_src.c_param = C_REL; 549 hpibsend(ctlr, slave, C_CMD, &sc->sc_src, sizeof(sc->sc_src)); 550 hpibswait(ctlr, slave); 551 hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 552 553 sc->sc_ssmc.c_unit = C_SUNIT(sc->sc_punit); 554 sc->sc_ssmc.c_cmd = C_SSM; 555 sc->sc_ssmc.c_refm = REF_MASK; 556 sc->sc_ssmc.c_fefm = FEF_MASK; 557 sc->sc_ssmc.c_aefm = AEF_MASK; 558 sc->sc_ssmc.c_iefm = IEF_MASK; 559 hpibsend(ctlr, slave, C_CMD, &sc->sc_ssmc, sizeof(sc->sc_ssmc)); 560 hpibswait(ctlr, slave); 561 hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 562 #ifdef DEBUG 563 sc->sc_stats.rdresets++; 564 #endif 565 } 566 567 /* 568 * Read or construct a disklabel 569 */ 570 static int 571 rdgetinfo(dev_t dev) 572 { 573 int unit = rdunit(dev); 574 struct rd_softc *sc = device_private(rd_cd.cd_devs[unit]); 575 struct disklabel *lp = sc->sc_dkdev.dk_label; 576 struct partition *pi; 577 const char *msg; 578 579 /* 580 * Set some default values to use while reading the label 581 * or to use if there isn't a label. 582 */ 583 memset((void *)lp, 0, sizeof *lp); 584 rdgetdefaultlabel(sc, lp); 585 586 /* 587 * Now try to read the disklabel 588 */ 589 msg = readdisklabel(rdlabdev(dev), rdstrategy, lp, NULL); 590 if (msg == NULL) 591 return 0; 592 593 pi = lp->d_partitions; 594 printf("%s: WARNING: %s\n", device_xname(sc->sc_dev), msg); 595 596 pi[2].p_size = rdidentinfo[sc->sc_type].ri_nblocks; 597 /* XXX reset other info since readdisklabel screws with it */ 598 lp->d_npartitions = 3; 599 pi[0].p_size = 0; 600 601 return 0; 602 } 603 604 static int 605 rdopen(dev_t dev, int flags, int mode, struct lwp *l) 606 { 607 int unit = rdunit(dev); 608 struct rd_softc *sc; 609 int error, mask, part; 610 611 if (unit >= rd_cd.cd_ndevs || 612 (sc = device_private(rd_cd.cd_devs[unit])) == NULL || 613 (sc->sc_flags & RDF_ALIVE) == 0) 614 return ENXIO; 615 616 /* 617 * Wait for any pending opens/closes to complete 618 */ 619 while (sc->sc_flags & (RDF_OPENING|RDF_CLOSING)) 620 (void) tsleep(sc, PRIBIO, "rdopen", 0); 621 622 /* 623 * On first open, get label and partition info. 624 * We may block reading the label, so be careful 625 * to stop any other opens. 626 */ 627 if (sc->sc_dkdev.dk_openmask == 0) { 628 sc->sc_flags |= RDF_OPENING; 629 error = rdgetinfo(dev); 630 sc->sc_flags &= ~RDF_OPENING; 631 wakeup((void *)sc); 632 if (error) 633 return error; 634 } 635 636 part = rdpart(dev); 637 mask = 1 << part; 638 639 /* Check that the partition exists. */ 640 if (part != RAW_PART && 641 (part > sc->sc_dkdev.dk_label->d_npartitions || 642 sc->sc_dkdev.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) 643 return ENXIO; 644 645 /* Ensure only one open at a time. */ 646 switch (mode) { 647 case S_IFCHR: 648 sc->sc_dkdev.dk_copenmask |= mask; 649 break; 650 case S_IFBLK: 651 sc->sc_dkdev.dk_bopenmask |= mask; 652 break; 653 } 654 sc->sc_dkdev.dk_openmask = 655 sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask; 656 657 return 0; 658 } 659 660 static int 661 rdclose(dev_t dev, int flag, int mode, struct lwp *l) 662 { 663 int unit = rdunit(dev); 664 struct rd_softc *sc = device_private(rd_cd.cd_devs[unit]); 665 struct disk *dk = &sc->sc_dkdev; 666 int mask, s; 667 668 mask = 1 << rdpart(dev); 669 if (mode == S_IFCHR) 670 dk->dk_copenmask &= ~mask; 671 else 672 dk->dk_bopenmask &= ~mask; 673 dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask; 674 /* 675 * On last close, we wait for all activity to cease since 676 * the label/parition info will become invalid. Since we 677 * might sleep, we must block any opens while we are here. 678 * Note we don't have to about other closes since we know 679 * we are the last one. 680 */ 681 if (dk->dk_openmask == 0) { 682 sc->sc_flags |= RDF_CLOSING; 683 s = splbio(); 684 while (sc->sc_active) { 685 sc->sc_flags |= RDF_WANTED; 686 (void) tsleep(&sc->sc_tab, PRIBIO, "rdclose", 0); 687 } 688 splx(s); 689 sc->sc_flags &= ~(RDF_CLOSING|RDF_WLABEL); 690 wakeup((void *)sc); 691 } 692 return 0; 693 } 694 695 static void 696 rdstrategy(struct buf *bp) 697 { 698 int unit = rdunit(bp->b_dev); 699 struct rd_softc *sc = device_private(rd_cd.cd_devs[unit]); 700 struct partition *pinfo; 701 daddr_t bn; 702 int sz, s; 703 int offset; 704 705 #ifdef DEBUG 706 if (rddebug & RDB_FOLLOW) 707 printf("rdstrategy(%p): dev %x, bn %llx, bcount %x, %c\n", 708 bp, bp->b_dev, bp->b_blkno, bp->b_bcount, 709 (bp->b_flags & B_READ) ? 'R' : 'W'); 710 #endif 711 bn = bp->b_blkno; 712 sz = howmany(bp->b_bcount, DEV_BSIZE); 713 pinfo = &sc->sc_dkdev.dk_label->d_partitions[rdpart(bp->b_dev)]; 714 715 /* Don't perform partition translation on RAW_PART. */ 716 offset = (rdpart(bp->b_dev) == RAW_PART) ? 0 : pinfo->p_offset; 717 718 if (rdpart(bp->b_dev) != RAW_PART) { 719 /* 720 * XXX This block of code belongs in 721 * XXX bounds_check_with_label() 722 */ 723 724 if (bn < 0 || bn + sz > pinfo->p_size) { 725 sz = pinfo->p_size - bn; 726 if (sz == 0) { 727 bp->b_resid = bp->b_bcount; 728 goto done; 729 } 730 if (sz < 0) { 731 bp->b_error = EINVAL; 732 goto done; 733 } 734 bp->b_bcount = dbtob(sz); 735 } 736 /* 737 * Check for write to write protected label 738 */ 739 if (bn + offset <= LABELSECTOR && 740 #if LABELSECTOR != 0 741 bn + offset + sz > LABELSECTOR && 742 #endif 743 !(bp->b_flags & B_READ) && !(sc->sc_flags & RDF_WLABEL)) { 744 bp->b_error = EROFS; 745 goto done; 746 } 747 } 748 bp->b_rawblkno = bn + offset; 749 s = splbio(); 750 BUFQ_PUT(sc->sc_tab, bp); 751 if (sc->sc_active == 0) { 752 sc->sc_active = 1; 753 rdustart(sc); 754 } 755 splx(s); 756 return; 757 done: 758 biodone(bp); 759 } 760 761 /* 762 * Called from timeout() when handling maintenance releases 763 */ 764 static void 765 rdrestart(void *arg) 766 { 767 int s = splbio(); 768 rdustart((struct rd_softc *)arg); 769 splx(s); 770 } 771 772 static void 773 rdustart(struct rd_softc *sc) 774 { 775 struct buf *bp; 776 777 bp = BUFQ_PEEK(sc->sc_tab); 778 sc->sc_addr = bp->b_data; 779 sc->sc_resid = bp->b_bcount; 780 if (hpibreq(device_parent(sc->sc_dev), &sc->sc_hq)) 781 rdstart(sc); 782 } 783 784 static struct buf * 785 rdfinish(struct rd_softc *sc, struct buf *bp) 786 { 787 788 sc->sc_errcnt = 0; 789 (void)BUFQ_GET(sc->sc_tab); 790 bp->b_resid = 0; 791 biodone(bp); 792 hpibfree(device_parent(sc->sc_dev), &sc->sc_hq); 793 if ((bp = BUFQ_PEEK(sc->sc_tab)) != NULL) 794 return bp; 795 sc->sc_active = 0; 796 if (sc->sc_flags & RDF_WANTED) { 797 sc->sc_flags &= ~RDF_WANTED; 798 wakeup((void *)&sc->sc_tab); 799 } 800 return NULL; 801 } 802 803 static void 804 rdstart(void *arg) 805 { 806 struct rd_softc *sc = arg; 807 struct buf *bp = BUFQ_PEEK(sc->sc_tab); 808 int part, ctlr, slave; 809 810 ctlr = device_unit(device_parent(sc->sc_dev)); 811 slave = sc->sc_slave; 812 813 again: 814 #ifdef DEBUG 815 if (rddebug & RDB_FOLLOW) 816 printf("rdstart(%s): bp %p, %c\n", device_xname(sc->sc_dev), bp, 817 (bp->b_flags & B_READ) ? 'R' : 'W'); 818 #endif 819 part = rdpart(bp->b_dev); 820 sc->sc_flags |= RDF_SEEK; 821 sc->sc_ioc.c_unit = C_SUNIT(sc->sc_punit); 822 sc->sc_ioc.c_volume = C_SVOL(0); 823 sc->sc_ioc.c_saddr = C_SADDR; 824 sc->sc_ioc.c_hiaddr = 0; 825 sc->sc_ioc.c_addr = RDBTOS(bp->b_rawblkno); 826 sc->sc_ioc.c_nop2 = C_NOP; 827 sc->sc_ioc.c_slen = C_SLEN; 828 sc->sc_ioc.c_len = sc->sc_resid; 829 sc->sc_ioc.c_cmd = bp->b_flags & B_READ ? C_READ : C_WRITE; 830 #ifdef DEBUG 831 if (rddebug & RDB_IO) 832 printf("rdstart: hpibsend(%x, %x, %x, %p, %x)\n", 833 ctlr, slave, C_CMD, 834 &sc->sc_ioc.c_unit, sizeof(sc->sc_ioc) - 2); 835 #endif 836 if (hpibsend(ctlr, slave, C_CMD, &sc->sc_ioc.c_unit, 837 sizeof(sc->sc_ioc) - 2) == sizeof(sc->sc_ioc) - 2) { 838 839 /* Instrumentation. */ 840 disk_busy(&sc->sc_dkdev); 841 iostat_seek(sc->sc_dkdev.dk_stats); 842 843 #ifdef DEBUG 844 if (rddebug & RDB_IO) 845 printf("rdstart: hpibawait(%x)\n", ctlr); 846 #endif 847 hpibawait(ctlr); 848 return; 849 } 850 /* 851 * Experience has shown that the hpibwait in this hpibsend will 852 * occasionally timeout. It appears to occur mostly on old 7914 853 * drives with full maintenance tracks. We should probably 854 * integrate this with the backoff code in rderror. 855 */ 856 #ifdef DEBUG 857 if (rddebug & RDB_ERROR) 858 printf("%s: rdstart: cmd %x adr %lx blk %lld len %d ecnt %d\n", 859 device_xname(sc->sc_dev), 860 sc->sc_ioc.c_cmd, sc->sc_ioc.c_addr, 861 bp->b_blkno, sc->sc_resid, sc->sc_errcnt); 862 sc->sc_stats.rdretries++; 863 #endif 864 sc->sc_flags &= ~RDF_SEEK; 865 rdreset(sc); 866 if (sc->sc_errcnt++ < RDRETRY) 867 goto again; 868 printf("%s: rdstart err: cmd 0x%x sect %ld blk %" PRId64 " len %d\n", 869 device_xname(sc->sc_dev), sc->sc_ioc.c_cmd, sc->sc_ioc.c_addr, 870 bp->b_blkno, sc->sc_resid); 871 bp->b_error = EIO; 872 bp = rdfinish(sc, bp); 873 if (bp) { 874 sc->sc_addr = bp->b_data; 875 sc->sc_resid = bp->b_bcount; 876 if (hpibreq(device_parent(sc->sc_dev), &sc->sc_hq)) 877 goto again; 878 } 879 } 880 881 static void 882 rdgo(void *arg) 883 { 884 struct rd_softc *sc = arg; 885 struct buf *bp = BUFQ_PEEK(sc->sc_tab); 886 int rw, ctlr, slave; 887 888 ctlr = device_unit(device_parent(sc->sc_dev)); 889 slave = sc->sc_slave; 890 891 rw = bp->b_flags & B_READ; 892 893 /* Instrumentation. */ 894 disk_busy(&sc->sc_dkdev); 895 896 #ifdef USELEDS 897 ledcontrol(0, 0, LED_DISK); 898 #endif 899 hpibgo(ctlr, slave, C_EXEC, sc->sc_addr, sc->sc_resid, rw, rw != 0); 900 } 901 902 /* ARGSUSED */ 903 static void 904 rdintr(void *arg) 905 { 906 struct rd_softc *sc = arg; 907 int unit = device_unit(sc->sc_dev); 908 struct buf *bp = BUFQ_PEEK(sc->sc_tab); 909 u_char stat = 13; /* in case hpibrecv fails */ 910 int rv, restart, ctlr, slave; 911 912 ctlr = device_unit(device_parent(sc->sc_dev)); 913 slave = sc->sc_slave; 914 915 #ifdef DEBUG 916 if (rddebug & RDB_FOLLOW) 917 printf("rdintr(%d): bp %p, %c, flags %x\n", unit, bp, 918 (bp->b_flags & B_READ) ? 'R' : 'W', sc->sc_flags); 919 if (bp == NULL) { 920 printf("%s: bp == NULL\n", device_xname(sc->sc_dev)); 921 return; 922 } 923 #endif 924 disk_unbusy(&sc->sc_dkdev, (bp->b_bcount - bp->b_resid), 925 (bp->b_flags & B_READ)); 926 927 if (sc->sc_flags & RDF_SEEK) { 928 sc->sc_flags &= ~RDF_SEEK; 929 if (hpibustart(ctlr)) 930 rdgo(sc); 931 return; 932 } 933 if ((sc->sc_flags & RDF_SWAIT) == 0) { 934 #ifdef DEBUG 935 sc->sc_stats.rdpolltries++; 936 #endif 937 if (hpibpptest(ctlr, slave) == 0) { 938 #ifdef DEBUG 939 sc->sc_stats.rdpollwaits++; 940 #endif 941 942 /* Instrumentation. */ 943 disk_busy(&sc->sc_dkdev); 944 sc->sc_flags |= RDF_SWAIT; 945 hpibawait(ctlr); 946 return; 947 } 948 } else 949 sc->sc_flags &= ~RDF_SWAIT; 950 rv = hpibrecv(ctlr, slave, C_QSTAT, &stat, 1); 951 if (rv != 1 || stat) { 952 #ifdef DEBUG 953 if (rddebug & RDB_ERROR) 954 printf("rdintr: recv failed or bad stat %d\n", stat); 955 #endif 956 restart = rderror(unit); 957 #ifdef DEBUG 958 sc->sc_stats.rdretries++; 959 #endif 960 if (sc->sc_errcnt++ < RDRETRY) { 961 if (restart) 962 rdstart(sc); 963 return; 964 } 965 bp->b_error = EIO; 966 } 967 if (rdfinish(sc, bp)) 968 rdustart(sc); 969 #if NRND > 0 970 rnd_add_uint32(&sc->rnd_source, bp->b_blkno); 971 #endif 972 } 973 974 static int 975 rdstatus(struct rd_softc *sc) 976 { 977 int c, s; 978 u_char stat; 979 int rv; 980 981 c = device_unit(device_parent(sc->sc_dev)); 982 s = sc->sc_slave; 983 sc->sc_rsc.c_unit = C_SUNIT(sc->sc_punit); 984 sc->sc_rsc.c_sram = C_SRAM; 985 sc->sc_rsc.c_ram = C_RAM; 986 sc->sc_rsc.c_cmd = C_STATUS; 987 memset((void *)&sc->sc_stat, 0, sizeof(sc->sc_stat)); 988 rv = hpibsend(c, s, C_CMD, &sc->sc_rsc, sizeof(sc->sc_rsc)); 989 if (rv != sizeof(sc->sc_rsc)) { 990 #ifdef DEBUG 991 if (rddebug & RDB_STATUS) 992 printf("rdstatus: send C_CMD failed %d != %d\n", 993 rv, sizeof(sc->sc_rsc)); 994 #endif 995 return 1; 996 } 997 rv = hpibrecv(c, s, C_EXEC, &sc->sc_stat, sizeof(sc->sc_stat)); 998 if (rv != sizeof(sc->sc_stat)) { 999 #ifdef DEBUG 1000 if (rddebug & RDB_STATUS) 1001 printf("rdstatus: send C_EXEC failed %d != %d\n", 1002 rv, sizeof(sc->sc_stat)); 1003 #endif 1004 return 1; 1005 } 1006 rv = hpibrecv(c, s, C_QSTAT, &stat, 1); 1007 if (rv != 1 || stat) { 1008 #ifdef DEBUG 1009 if (rddebug & RDB_STATUS) 1010 printf("rdstatus: recv failed %d or bad stat %d\n", 1011 rv, stat); 1012 #endif 1013 return 1; 1014 } 1015 return 0; 1016 } 1017 1018 /* 1019 * Deal with errors. 1020 * Returns 1 if request should be restarted, 1021 * 0 if we should just quietly give up. 1022 */ 1023 static int 1024 rderror(int unit) 1025 { 1026 struct rd_softc *sc = device_private(rd_cd.cd_devs[unit]); 1027 struct rd_stat *sp; 1028 struct buf *bp; 1029 daddr_t hwbn, pbn; 1030 char *hexstr(int, int); /* XXX */ 1031 1032 if (rdstatus(sc)) { 1033 #ifdef DEBUG 1034 printf("%s: couldn't get status\n", device_xname(sc->sc_dev)); 1035 #endif 1036 rdreset(sc); 1037 return 1; 1038 } 1039 sp = &sc->sc_stat; 1040 if (sp->c_fef & FEF_REXMT) 1041 return 1; 1042 if (sp->c_fef & FEF_PF) { 1043 rdreset(sc); 1044 return 1; 1045 } 1046 /* 1047 * Unit requests release for internal maintenance. 1048 * We just delay awhile and try again later. Use expontially 1049 * increasing backoff ala ethernet drivers since we don't really 1050 * know how long the maintenance will take. With RDWAITC and 1051 * RDRETRY as defined, the range is 1 to 32 seconds. 1052 */ 1053 if (sp->c_fef & FEF_IMR) { 1054 extern int hz; 1055 int rdtimo = RDWAITC << sc->sc_errcnt; 1056 #ifdef DEBUG 1057 printf("%s: internal maintenance, %d second timeout\n", 1058 device_xname(sc->sc_dev), rdtimo); 1059 sc->sc_stats.rdtimeouts++; 1060 #endif 1061 hpibfree(device_parent(sc->sc_dev), &sc->sc_hq); 1062 callout_reset(&sc->sc_restart_ch, rdtimo * hz, rdrestart, sc); 1063 return 0; 1064 } 1065 /* 1066 * Only report error if we have reached the error reporting 1067 * threshhold. By default, this will only report after the 1068 * retry limit has been exceeded. 1069 */ 1070 if (sc->sc_errcnt < rderrthresh) 1071 return 1; 1072 1073 /* 1074 * First conjure up the block number at which the error occurred. 1075 * Note that not all errors report a block number, in that case 1076 * we just use b_blkno. 1077 */ 1078 bp = BUFQ_PEEK(sc->sc_tab); 1079 pbn = sc->sc_dkdev.dk_label->d_partitions[rdpart(bp->b_dev)].p_offset; 1080 if ((sp->c_fef & FEF_CU) || (sp->c_fef & FEF_DR) || 1081 (sp->c_ief & IEF_RRMASK)) { 1082 hwbn = RDBTOS(pbn + bp->b_blkno); 1083 pbn = bp->b_blkno; 1084 } else { 1085 hwbn = sp->c_blk; 1086 pbn = RDSTOB(hwbn) - pbn; 1087 } 1088 /* 1089 * Now output a generic message suitable for badsect. 1090 * Note that we don't use harderr cuz it just prints 1091 * out b_blkno which is just the beginning block number 1092 * of the transfer, not necessary where the error occurred. 1093 */ 1094 printf("%s%c: hard error sn%" PRId64 "\n", device_xname(sc->sc_dev), 1095 'a'+rdpart(bp->b_dev), pbn); 1096 /* 1097 * Now report the status as returned by the hardware with 1098 * attempt at interpretation (unless debugging). 1099 */ 1100 printf("%s %s error:", device_xname(sc->sc_dev), 1101 (bp->b_flags & B_READ) ? "read" : "write"); 1102 #ifdef DEBUG 1103 if (rddebug & RDB_ERROR) { 1104 /* status info */ 1105 printf("\n volume: %d, unit: %d\n", 1106 (sp->c_vu>>4)&0xF, sp->c_vu&0xF); 1107 rdprinterr("reject", sp->c_ref, err_reject); 1108 rdprinterr("fault", sp->c_fef, err_fault); 1109 rdprinterr("access", sp->c_aef, err_access); 1110 rdprinterr("info", sp->c_ief, err_info); 1111 printf(" block: %lld, P1-P10: ", hwbn); 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 /* command */ 1116 printf(" ioc: "); 1117 printf("0x%x", *(u_int *)&sc->sc_ioc.c_pad); 1118 printf("0x%x", *(u_short *)&sc->sc_ioc.c_hiaddr); 1119 printf("0x%x", *(u_int *)&sc->sc_ioc.c_addr); 1120 printf("0x%x", *(u_short *)&sc->sc_ioc.c_nop2); 1121 printf("0x%x", *(u_int *)&sc->sc_ioc.c_len); 1122 printf("0x%x\n", *(u_short *)&sc->sc_ioc.c_cmd); 1123 return 1; 1124 } 1125 #endif 1126 printf(" v%d u%d, R0x%x F0x%x A0x%x I0x%x\n", 1127 (sp->c_vu>>4)&0xF, sp->c_vu&0xF, 1128 sp->c_ref, sp->c_fef, sp->c_aef, sp->c_ief); 1129 printf("P1-P10: "); 1130 printf("0x%x", *(u_int *)&sp->c_raw[0]); 1131 printf("0x%x", *(u_int *)&sp->c_raw[4]); 1132 printf("0x%x\n", *(u_short *)&sp->c_raw[8]); 1133 return 1; 1134 } 1135 1136 static int 1137 rdread(dev_t dev, struct uio *uio, int flags) 1138 { 1139 1140 return physio(rdstrategy, NULL, dev, B_READ, minphys, uio); 1141 } 1142 1143 static int 1144 rdwrite(dev_t dev, struct uio *uio, int flags) 1145 { 1146 1147 return physio(rdstrategy, NULL, dev, B_WRITE, minphys, uio); 1148 } 1149 1150 static int 1151 rdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1152 { 1153 int unit = rdunit(dev); 1154 struct rd_softc *sc = device_private(rd_cd.cd_devs[unit]); 1155 struct disklabel *lp = sc->sc_dkdev.dk_label; 1156 int error, flags; 1157 1158 switch (cmd) { 1159 case DIOCGDINFO: 1160 *(struct disklabel *)data = *lp; 1161 return 0; 1162 1163 case DIOCGPART: 1164 ((struct partinfo *)data)->disklab = lp; 1165 ((struct partinfo *)data)->part = 1166 &lp->d_partitions[rdpart(dev)]; 1167 return 0; 1168 1169 case DIOCWLABEL: 1170 if ((flag & FWRITE) == 0) 1171 return EBADF; 1172 if (*(int *)data) 1173 sc->sc_flags |= RDF_WLABEL; 1174 else 1175 sc->sc_flags &= ~RDF_WLABEL; 1176 return 0; 1177 1178 case DIOCSDINFO: 1179 if ((flag & FWRITE) == 0) 1180 return EBADF; 1181 return setdisklabel(lp, (struct disklabel *)data, 1182 (sc->sc_flags & RDF_WLABEL) ? 0 : sc->sc_dkdev.dk_openmask, 1183 NULL); 1184 1185 case DIOCWDINFO: 1186 if ((flag & FWRITE) == 0) 1187 return EBADF; 1188 error = setdisklabel(lp, (struct disklabel *)data, 1189 (sc->sc_flags & RDF_WLABEL) ? 0 : sc->sc_dkdev.dk_openmask, 1190 NULL); 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, NULL); 1196 sc->sc_flags = flags; 1197 return error; 1198 1199 case DIOCGDEFLABEL: 1200 rdgetdefaultlabel(sc, (struct disklabel *)data); 1201 return 0; 1202 } 1203 return EINVAL; 1204 } 1205 1206 static void 1207 rdgetdefaultlabel(struct rd_softc *sc, struct disklabel *lp) 1208 { 1209 int type = sc->sc_type; 1210 1211 memset((void *)lp, 0, sizeof(struct disklabel)); 1212 1213 lp->d_type = DTYPE_HPIB; 1214 lp->d_secsize = DEV_BSIZE; 1215 lp->d_nsectors = rdidentinfo[type].ri_nbpt; 1216 lp->d_ntracks = rdidentinfo[type].ri_ntpc; 1217 lp->d_ncylinders = rdidentinfo[type].ri_ncyl; 1218 lp->d_secperunit = rdidentinfo[type].ri_nblocks; 1219 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 1220 1221 strlcpy(lp->d_typename, rdidentinfo[type].ri_desc, 1222 sizeof(lp->d_typename)); 1223 strlcpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 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 *sc; 1244 int psize, didopen = 0; 1245 1246 if (unit >= rd_cd.cd_ndevs || 1247 (sc = device_private(rd_cd.cd_devs[unit])) == NULL || 1248 (sc->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 (sc->sc_dkdev.dk_openmask == 0) { 1257 if (rdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) 1258 return -1; 1259 didopen = 1; 1260 } 1261 psize = sc->sc_dkdev.dk_label->d_partitions[rdpart(dev)].p_size * 1262 (sc->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, void *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 *sc; 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 (sc = device_private(rd_cd.cd_devs[unit])) == NULL || 1317 (sc->sc_flags & RDF_ALIVE) == 0) 1318 return ENXIO; 1319 1320 ctlr = device_unit(device_parent(sc->sc_dev)); 1321 slave = sc->sc_slave; 1322 1323 /* 1324 * Convert to disk sectors. Request must be a multiple of size. 1325 */ 1326 lp = sc->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 sc->sc_ioc.c_unit = C_SUNIT(sc->sc_punit); 1350 sc->sc_ioc.c_volume = C_SVOL(0); 1351 sc->sc_ioc.c_saddr = C_SADDR; 1352 sc->sc_ioc.c_hiaddr = 0; 1353 sc->sc_ioc.c_addr = RDBTOS(blkno); 1354 sc->sc_ioc.c_nop2 = C_NOP; 1355 sc->sc_ioc.c_slen = C_SLEN; 1356 sc->sc_ioc.c_len = nwrt * sectorsize; 1357 sc->sc_ioc.c_cmd = C_WRITE; 1358 hpibsend(ctlr, slave, C_CMD, &sc->sc_ioc.c_unit, 1359 sizeof(sc->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", device_xname(sc->sc_dev), 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 = (char *)va + sectorsize * nwrt; 1382 } 1383 rddoingadump = 0; 1384 return 0; 1385 } 1386