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