141480Smckusick /* 241480Smckusick * Copyright (c) 1988 University of Utah. 341480Smckusick * Copyright (c) 1982, 1990 The Regents of the University of California. 441480Smckusick * All rights reserved. 541480Smckusick * 641480Smckusick * This code is derived from software contributed to Berkeley by 741480Smckusick * the Systems Programming Group of the University of Utah Computer 841480Smckusick * Science Department. 941480Smckusick * 1041480Smckusick * %sccs.include.redist.c% 1141480Smckusick * 12*57327Shibler * from: Utah $Hdr: rd.c 1.44 92/12/26$ 1341480Smckusick * 14*57327Shibler * @(#)rd.c 7.18 (Berkeley) 12/27/92 1541480Smckusick */ 1641480Smckusick 1741480Smckusick /* 1841480Smckusick * CS80/SS80 disk driver 1941480Smckusick */ 2041480Smckusick #include "rd.h" 2141480Smckusick #if NRD > 0 2241480Smckusick 2356507Sbostic #include <sys/param.h> 2456507Sbostic #include <sys/systm.h> 25*57327Shibler #include <sys/buf.h> 26*57327Shibler #include <sys/stat.h> 2756507Sbostic #include <sys/dkstat.h> 2856507Sbostic #include <sys/disklabel.h> 29*57327Shibler #include <sys/ioctl.h> 30*57327Shibler #include <sys/fcntl.h> 3141480Smckusick 3256507Sbostic #include <hp/dev/device.h> 3356507Sbostic #include <hp300/dev/rdreg.h> 34*57327Shibler #include <hp300/dev/rdvar.h> 35*57327Shibler #ifdef USELEDS 36*57327Shibler #include <hp300/hp300/led.h> 37*57327Shibler #endif 3841480Smckusick 3956507Sbostic #include <vm/vm_param.h> 4056507Sbostic #include <vm/lock.h> 4156507Sbostic #include <vm/vm_prot.h> 4256507Sbostic #include <vm/pmap.h> 4345750Smckusick 4441480Smckusick int rdinit(), rdstart(), rdgo(), rdintr(); 45*57327Shibler void rdstrategy(); 4641480Smckusick struct driver rddriver = { 4741480Smckusick rdinit, "rd", rdstart, rdgo, rdintr, 4841480Smckusick }; 4941480Smckusick 50*57327Shibler struct rd_softc rd_softc[NRD]; 51*57327Shibler struct buf rdtab[NRD]; 52*57327Shibler int rderrthresh = RDRETRY-1; /* when to start reporting errors */ 5341480Smckusick 5441480Smckusick #ifdef DEBUG 5541480Smckusick /* error message tables */ 5641480Smckusick char *err_reject[] = { 5741480Smckusick 0, 0, 5841480Smckusick "channel parity error", /* 0x2000 */ 5941480Smckusick 0, 0, 6041480Smckusick "illegal opcode", /* 0x0400 */ 6141480Smckusick "module addressing", /* 0x0200 */ 6241480Smckusick "address bounds", /* 0x0100 */ 6341480Smckusick "parameter bounds", /* 0x0080 */ 6441480Smckusick "illegal parameter", /* 0x0040 */ 6541480Smckusick "message sequence", /* 0x0020 */ 6641480Smckusick 0, 6741480Smckusick "message length", /* 0x0008 */ 6841480Smckusick 0, 0, 0 6941480Smckusick }; 7041480Smckusick 7141480Smckusick char *err_fault[] = { 7241480Smckusick 0, 7341480Smckusick "cross unit", /* 0x4000 */ 7441480Smckusick 0, 7541480Smckusick "controller fault", /* 0x1000 */ 7641480Smckusick 0, 0, 7741480Smckusick "unit fault", /* 0x0200 */ 7841480Smckusick 0, 7941480Smckusick "diagnostic result", /* 0x0080 */ 8041480Smckusick 0, 8141480Smckusick "operator release request", /* 0x0020 */ 8241480Smckusick "diagnostic release request", /* 0x0010 */ 8341480Smckusick "internal maintenance release request", /* 0x0008 */ 8441480Smckusick 0, 8541480Smckusick "power fail", /* 0x0002 */ 8641480Smckusick "retransmit" /* 0x0001 */ 8741480Smckusick }; 8841480Smckusick 8941480Smckusick char *err_access[] = { 9041480Smckusick "illegal parallel operation", /* 0x8000 */ 9141480Smckusick "uninitialized media", /* 0x4000 */ 9241480Smckusick "no spares available", /* 0x2000 */ 9341480Smckusick "not ready", /* 0x1000 */ 9441480Smckusick "write protect", /* 0x0800 */ 9541480Smckusick "no data found", /* 0x0400 */ 9641480Smckusick 0, 0, 9741480Smckusick "unrecoverable data overflow", /* 0x0080 */ 9841480Smckusick "unrecoverable data", /* 0x0040 */ 9941480Smckusick 0, 10041480Smckusick "end of file", /* 0x0010 */ 10141480Smckusick "end of volume", /* 0x0008 */ 10241480Smckusick 0, 0, 0 10341480Smckusick }; 10441480Smckusick 10541480Smckusick char *err_info[] = { 10641480Smckusick "operator release request", /* 0x8000 */ 10741480Smckusick "diagnostic release request", /* 0x4000 */ 10841480Smckusick "internal maintenance release request", /* 0x2000 */ 10941480Smckusick "media wear", /* 0x1000 */ 11041480Smckusick "latency induced", /* 0x0800 */ 11141480Smckusick 0, 0, 11241480Smckusick "auto sparing invoked", /* 0x0100 */ 11341480Smckusick 0, 11441480Smckusick "recoverable data overflow", /* 0x0040 */ 11541480Smckusick "marginal data", /* 0x0020 */ 11641480Smckusick "recoverable data", /* 0x0010 */ 11741480Smckusick 0, 11841480Smckusick "maintenance track overflow", /* 0x0004 */ 11941480Smckusick 0, 0 12041480Smckusick }; 121*57327Shibler 122*57327Shibler struct rdstats rdstats[NRD]; 123*57327Shibler int rddebug = 0x80; 124*57327Shibler #define RDB_FOLLOW 0x01 125*57327Shibler #define RDB_STATUS 0x02 126*57327Shibler #define RDB_IDENT 0x04 127*57327Shibler #define RDB_IO 0x08 128*57327Shibler #define RDB_ASYNC 0x10 129*57327Shibler #define RDB_ERROR 0x80 13041480Smckusick #endif 13141480Smckusick 13241480Smckusick /* 133*57327Shibler * Misc. HW description, indexed by sc_type. 134*57327Shibler * Nothing really critical here, could do without it. 13541480Smckusick */ 136*57327Shibler struct rdidentinfo rdidentinfo[] = { 137*57327Shibler { RD7946AID, 0, "7945A", 108416 }, 138*57327Shibler { RD9134DID, 1, "9134D", 29088 }, 139*57327Shibler { RD9134LID, 1, "9122S", 1232 }, 140*57327Shibler { RD7912PID, 0, "7912P", 128128 }, 141*57327Shibler { RD7914PID, 0, "7914P", 258048 }, 142*57327Shibler { RD7958AID, 0, "7958A", 255276 }, 143*57327Shibler { RD7957AID, 0, "7957A", 159544 }, 144*57327Shibler { RD7933HID, 0, "7933H", 789958 }, 145*57327Shibler { RD9134LID, 1, "9134L", 77840 }, 146*57327Shibler { RD7936HID, 0, "7936H", 600978 }, 147*57327Shibler { RD7937HID, 0, "7937H", 1116102 }, 148*57327Shibler { RD7914CTID, 0, "7914CT", 258048 }, 149*57327Shibler { RD7946AID, 0, "7946A", 108416 }, 150*57327Shibler { RD9134LID, 1, "9122D", 1232 }, 151*57327Shibler { RD7957BID, 0, "7957B", 159894 }, 152*57327Shibler { RD7958BID, 0, "7958B", 297108 }, 153*57327Shibler { RD7959BID, 0, "7959B", 594216 }, 154*57327Shibler { RD2200AID, 0, "2200A", 654948 }, 155*57327Shibler { RD2203AID, 0, "2203A", 1309896 } 15641480Smckusick }; 157*57327Shibler int numrdidentinfo = sizeof(rdidentinfo) / sizeof(rdidentinfo[0]); 15841480Smckusick 15941480Smckusick rdinit(hd) 16041480Smckusick register struct hp_device *hd; 16141480Smckusick { 16241480Smckusick register struct rd_softc *rs = &rd_softc[hd->hp_unit]; 16341480Smckusick 16441480Smckusick rs->sc_hd = hd; 16541480Smckusick rs->sc_punit = rdpunit(hd->hp_flags); 16641480Smckusick rs->sc_type = rdident(rs, hd); 16741480Smckusick if (rs->sc_type < 0) 16841480Smckusick return(0); 16941480Smckusick rs->sc_dq.dq_ctlr = hd->hp_ctlr; 17041480Smckusick rs->sc_dq.dq_unit = hd->hp_unit; 17141480Smckusick rs->sc_dq.dq_slave = hd->hp_slave; 17241480Smckusick rs->sc_dq.dq_driver = &rddriver; 17341480Smckusick rs->sc_flags = RDF_ALIVE; 17442361Smckusick #ifdef DEBUG 17542361Smckusick /* always report errors */ 17642361Smckusick if (rddebug & RDB_ERROR) 17742361Smckusick rderrthresh = 0; 17842361Smckusick #endif 17941480Smckusick return(1); 18041480Smckusick } 18141480Smckusick 18241480Smckusick rdident(rs, hd) 18341480Smckusick struct rd_softc *rs; 18441480Smckusick struct hp_device *hd; 18541480Smckusick { 18641480Smckusick struct rd_describe desc; 18741480Smckusick u_char stat, cmd[3]; 18841480Smckusick int unit, lunit; 18941480Smckusick char name[7]; 19041480Smckusick register int ctlr, slave, id, i; 19141480Smckusick 19241480Smckusick ctlr = hd->hp_ctlr; 19341480Smckusick slave = hd->hp_slave; 19441480Smckusick unit = rs->sc_punit; 19541480Smckusick lunit = hd->hp_unit; 19641480Smckusick 19741480Smckusick /* 19841480Smckusick * Grab device id and make sure: 19941480Smckusick * 1. It is a CS80 device. 20041480Smckusick * 2. It is one of the types we support. 20141480Smckusick * 3. If it is a 7946, we are accessing the disk unit (0) 20241480Smckusick */ 20341480Smckusick id = hpibid(ctlr, slave); 20446681Smckusick #ifdef DEBUG 20546681Smckusick if (rddebug & RDB_IDENT) 20646681Smckusick printf("hpibid(%d, %d) -> %x\n", ctlr, slave, id); 20746681Smckusick #endif 20841480Smckusick if ((id & 0x200) == 0) 20941480Smckusick return(-1); 210*57327Shibler for (i = 0; i < numrdidentinfo; i++) 211*57327Shibler if (id == rdidentinfo[i].ri_hwid) 21241480Smckusick break; 213*57327Shibler if (i == numrdidentinfo || unit > rdidentinfo[i].ri_maxunum) 21441480Smckusick return(-1); 21541480Smckusick id = i; 21641480Smckusick 21741480Smckusick /* 21841480Smckusick * Reset drive and collect device description. 21941480Smckusick * Don't really use the description info right now but 22041480Smckusick * might come in handy in the future (for disk labels). 22141480Smckusick */ 22241480Smckusick rdreset(rs, hd); 22341480Smckusick cmd[0] = C_SUNIT(unit); 22441480Smckusick cmd[1] = C_SVOL(0); 22541480Smckusick cmd[2] = C_DESC; 22641480Smckusick hpibsend(ctlr, slave, C_CMD, cmd, sizeof(cmd)); 22741480Smckusick hpibrecv(ctlr, slave, C_EXEC, &desc, 37); 22841480Smckusick hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); 22941480Smckusick bzero(name, sizeof(name)); 23041480Smckusick if (!stat) { 23141480Smckusick register int n = desc.d_name; 23241480Smckusick for (i = 5; i >= 0; i--) { 23341480Smckusick name[i] = (n & 0xf) + '0'; 23441480Smckusick n >>= 4; 23541480Smckusick } 23642361Smckusick /* use drive characteristics to calculate xfer rate */ 23742361Smckusick rs->sc_wpms = 1000000 * (desc.d_sectsize/2) / desc.d_blocktime; 23841480Smckusick } 23941480Smckusick #ifdef DEBUG 24041480Smckusick if (rddebug & RDB_IDENT) { 24141480Smckusick printf("rd%d: name: %x ('%s')\n", 24241480Smckusick lunit, desc.d_name, name); 24341480Smckusick printf(" iuw %x, maxxfr %d, ctype %d\n", 24441480Smckusick desc.d_iuw, desc.d_cmaxxfr, desc.d_ctype); 24541480Smckusick printf(" utype %d, bps %d, blkbuf %d, burst %d, blktime %d\n", 24641480Smckusick desc.d_utype, desc.d_sectsize, 24741480Smckusick desc.d_blkbuf, desc.d_burstsize, desc.d_blocktime); 24841480Smckusick printf(" avxfr %d, ort %d, atp %d, maxint %d, fv %x, rv %x\n", 24941480Smckusick desc.d_uavexfr, desc.d_retry, desc.d_access, 25041480Smckusick desc.d_maxint, desc.d_fvbyte, desc.d_rvbyte); 25141480Smckusick printf(" maxcyl/head/sect %d/%d/%d, maxvsect %d, inter %d\n", 25241480Smckusick desc.d_maxcyl, desc.d_maxhead, desc.d_maxsect, 25341480Smckusick desc.d_maxvsectl, desc.d_interleave); 25441480Smckusick } 25541480Smckusick #endif 25641480Smckusick /* 25741480Smckusick * Take care of a couple of anomolies: 25841480Smckusick * 1. 7945A and 7946A both return same HW id 25941480Smckusick * 2. 9122S and 9134D both return same HW id 26041480Smckusick * 3. 9122D and 9134L both return same HW id 26141480Smckusick */ 262*57327Shibler switch (rdidentinfo[id].ri_hwid) { 26341480Smckusick case RD7946AID: 26441480Smckusick if (bcmp(name, "079450", 6) == 0) 26541480Smckusick id = RD7945A; 26641480Smckusick else 26741480Smckusick id = RD7946A; 26841480Smckusick break; 26941480Smckusick 27041480Smckusick case RD9134LID: 27141480Smckusick if (bcmp(name, "091340", 6) == 0) 27241480Smckusick id = RD9134L; 27341480Smckusick else 27441480Smckusick id = RD9122D; 27541480Smckusick break; 27641480Smckusick 27741480Smckusick case RD9134DID: 27841480Smckusick if (bcmp(name, "091220", 6) == 0) 27941480Smckusick id = RD9122S; 28041480Smckusick else 28141480Smckusick id = RD9134D; 28241480Smckusick break; 28341480Smckusick } 284*57327Shibler printf("rd%d: %s\n", lunit, rdidentinfo[id].ri_desc); 28541480Smckusick return(id); 28641480Smckusick } 28741480Smckusick 28841480Smckusick rdreset(rs, hd) 28941480Smckusick register struct rd_softc *rs; 29041480Smckusick register struct hp_device *hd; 29141480Smckusick { 29241480Smckusick u_char stat; 29341480Smckusick 29441480Smckusick rs->sc_clear.c_unit = C_SUNIT(rs->sc_punit); 29541480Smckusick rs->sc_clear.c_cmd = C_CLEAR; 29641480Smckusick hpibsend(hd->hp_ctlr, hd->hp_slave, C_TCMD, &rs->sc_clear, 29741480Smckusick sizeof(rs->sc_clear)); 29841480Smckusick hpibswait(hd->hp_ctlr, hd->hp_slave); 29941480Smckusick hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat)); 30041480Smckusick rs->sc_src.c_unit = C_SUNIT(RDCTLR); 30141480Smckusick rs->sc_src.c_nop = C_NOP; 30241480Smckusick rs->sc_src.c_cmd = C_SREL; 30341480Smckusick rs->sc_src.c_param = C_REL; 30441480Smckusick hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_src, 30541480Smckusick sizeof(rs->sc_src)); 30641480Smckusick hpibswait(hd->hp_ctlr, hd->hp_slave); 30741480Smckusick hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat)); 30841480Smckusick rs->sc_ssmc.c_unit = C_SUNIT(rs->sc_punit); 30941480Smckusick rs->sc_ssmc.c_cmd = C_SSM; 31041480Smckusick rs->sc_ssmc.c_refm = REF_MASK; 31141480Smckusick rs->sc_ssmc.c_fefm = FEF_MASK; 31241480Smckusick rs->sc_ssmc.c_aefm = AEF_MASK; 31341480Smckusick rs->sc_ssmc.c_iefm = IEF_MASK; 31441480Smckusick hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_ssmc, 31541480Smckusick sizeof(rs->sc_ssmc)); 31641480Smckusick hpibswait(hd->hp_ctlr, hd->hp_slave); 31741480Smckusick hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat)); 31841480Smckusick #ifdef DEBUG 31941480Smckusick rdstats[hd->hp_unit].rdresets++; 32041480Smckusick #endif 32141480Smckusick } 32241480Smckusick 323*57327Shibler /* 324*57327Shibler * Read or constuct a disklabel 325*57327Shibler */ 32649303Shibler int 327*57327Shibler rdgetinfo(dev) 328*57327Shibler dev_t dev; 329*57327Shibler { 330*57327Shibler int unit = rdunit(dev); 331*57327Shibler register struct rd_softc *rs = &rd_softc[unit]; 332*57327Shibler register struct disklabel *lp = &rs->sc_info.ri_label; 333*57327Shibler register struct partition *pi; 334*57327Shibler char *msg, *readdisklabel(); 335*57327Shibler 336*57327Shibler /* 337*57327Shibler * Set some default values to use while reading the label 338*57327Shibler * or to use if there isn't a label. 339*57327Shibler */ 340*57327Shibler bzero((caddr_t)lp, sizeof *lp); 341*57327Shibler lp->d_type = DTYPE_HPIB; 342*57327Shibler lp->d_secsize = DEV_BSIZE; 343*57327Shibler lp->d_nsectors = 32; 344*57327Shibler lp->d_ntracks = 20; 345*57327Shibler lp->d_secpercyl = 32*20; 346*57327Shibler lp->d_npartitions = 3; 347*57327Shibler lp->d_partitions[2].p_offset = 0; 348*57327Shibler lp->d_partitions[2].p_size = LABELSECTOR+1; 349*57327Shibler 350*57327Shibler /* 351*57327Shibler * Now try to read the disklabel 352*57327Shibler */ 353*57327Shibler msg = readdisklabel(rdlabdev(dev), rdstrategy, lp); 354*57327Shibler if (msg == NULL) 355*57327Shibler return(0); 356*57327Shibler 357*57327Shibler pi = lp->d_partitions; 358*57327Shibler printf("rd%d: WARNING: %s, ", unit, msg); 359*57327Shibler #ifdef COMPAT_NOLABEL 360*57327Shibler printf("using old default partitioning\n"); 361*57327Shibler rdmakedisklabel(unit, lp); 362*57327Shibler #else 363*57327Shibler printf("defining `c' partition as entire disk\n"); 364*57327Shibler pi[2].p_size = rdidentinfo[rs->sc_type].ri_nblocks; 365*57327Shibler #endif 366*57327Shibler return(0); 367*57327Shibler } 368*57327Shibler 369*57327Shibler int 37049303Shibler rdopen(dev, flags, mode, p) 37141480Smckusick dev_t dev; 37249303Shibler int flags, mode; 37349303Shibler struct proc *p; 37441480Smckusick { 37541480Smckusick register int unit = rdunit(dev); 37641480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 377*57327Shibler int error, mask; 37841480Smckusick 37941480Smckusick if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) 38041480Smckusick return(ENXIO); 381*57327Shibler 382*57327Shibler /* 383*57327Shibler * Wait for any pending opens/closes to complete 384*57327Shibler */ 385*57327Shibler while (rs->sc_flags & (RDF_OPENING|RDF_CLOSING)) 386*57327Shibler sleep((caddr_t)rs, PRIBIO); 387*57327Shibler 388*57327Shibler /* 389*57327Shibler * On first open, get label and partition info. 390*57327Shibler * We may block reading the label, so be careful 391*57327Shibler * to stop any other opens. 392*57327Shibler */ 393*57327Shibler if (rs->sc_info.ri_open == 0) { 394*57327Shibler rs->sc_flags |= RDF_OPENING; 395*57327Shibler error = rdgetinfo(dev); 396*57327Shibler rs->sc_flags &= ~RDF_OPENING; 397*57327Shibler wakeup((caddr_t)rs); 398*57327Shibler if (error) 399*57327Shibler return(error); 400*57327Shibler } 40142361Smckusick if (rs->sc_hd->hp_dk >= 0) { 40242361Smckusick /* guess at xfer rate based on 3600 rpm (60 rps) */ 40342361Smckusick if (rs->sc_wpms == 0) 404*57327Shibler rs->sc_wpms = 60 * rs->sc_info.ri_label.d_nsectors 405*57327Shibler * DEV_BSIZE / 2; 40642361Smckusick dk_wpms[rs->sc_hd->hp_dk] = rs->sc_wpms; 40742361Smckusick } 408*57327Shibler 409*57327Shibler mask = 1 << rdpart(dev); 410*57327Shibler if (mode == S_IFCHR) 411*57327Shibler rs->sc_info.ri_copen |= mask; 412*57327Shibler else 413*57327Shibler rs->sc_info.ri_bopen |= mask; 414*57327Shibler rs->sc_info.ri_open |= mask; 41541480Smckusick return(0); 41641480Smckusick } 41741480Smckusick 418*57327Shibler int 419*57327Shibler rdclose(dev, flag, mode, p) 420*57327Shibler dev_t dev; 421*57327Shibler int flag, mode; 422*57327Shibler struct proc *p; 423*57327Shibler { 424*57327Shibler int unit = rdunit(dev); 425*57327Shibler register struct rd_softc *rs = &rd_softc[unit]; 426*57327Shibler register struct rdinfo *ri = &rs->sc_info; 427*57327Shibler int mask, s; 428*57327Shibler 429*57327Shibler mask = 1 << rdpart(dev); 430*57327Shibler if (mode == S_IFCHR) 431*57327Shibler ri->ri_copen &= ~mask; 432*57327Shibler else 433*57327Shibler ri->ri_bopen &= ~mask; 434*57327Shibler ri->ri_open = ri->ri_bopen | ri->ri_copen; 435*57327Shibler /* 436*57327Shibler * On last close, we wait for all activity to cease since 437*57327Shibler * the label/parition info will become invalid. Since we 438*57327Shibler * might sleep, we must block any opens while we are here. 439*57327Shibler * Note we don't have to about other closes since we know 440*57327Shibler * we are the last one. 441*57327Shibler */ 442*57327Shibler if (ri->ri_open == 0) { 443*57327Shibler rs->sc_flags |= RDF_CLOSING; 444*57327Shibler s = splbio(); 445*57327Shibler while (rdtab[unit].b_active) { 446*57327Shibler rs->sc_flags |= RDF_WANTED; 447*57327Shibler sleep((caddr_t)&rdtab[unit], PRIBIO); 448*57327Shibler } 449*57327Shibler splx(s); 450*57327Shibler rs->sc_flags &= ~(RDF_CLOSING|RDF_WLABEL); 451*57327Shibler wakeup((caddr_t)rs); 452*57327Shibler } 453*57327Shibler return(0); 454*57327Shibler } 455*57327Shibler 456*57327Shibler void 45741480Smckusick rdstrategy(bp) 45841480Smckusick register struct buf *bp; 45941480Smckusick { 460*57327Shibler int unit = rdunit(bp->b_dev); 46141480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 46241480Smckusick register struct buf *dp = &rdtab[unit]; 463*57327Shibler register struct partition *pinfo; 46445750Smckusick register daddr_t bn; 46545750Smckusick register int sz, s; 46641480Smckusick 46741480Smckusick #ifdef DEBUG 46841480Smckusick if (rddebug & RDB_FOLLOW) 46941480Smckusick printf("rdstrategy(%x): dev %x, bn %x, bcount %x, %c\n", 47041480Smckusick bp, bp->b_dev, bp->b_blkno, bp->b_bcount, 47141480Smckusick (bp->b_flags & B_READ) ? 'R' : 'W'); 47241480Smckusick #endif 47341480Smckusick bn = bp->b_blkno; 47445750Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 475*57327Shibler pinfo = &rs->sc_info.ri_label.d_partitions[rdpart(bp->b_dev)]; 476*57327Shibler if (bn < 0 || bn + sz > pinfo->p_size) { 477*57327Shibler sz = pinfo->p_size - bn; 47845750Smckusick if (sz == 0) { 47941480Smckusick bp->b_resid = bp->b_bcount; 48041480Smckusick goto done; 48141480Smckusick } 48245750Smckusick if (sz < 0) { 48345750Smckusick bp->b_error = EINVAL; 484*57327Shibler goto bad; 48545750Smckusick } 48645750Smckusick bp->b_bcount = dbtob(sz); 48741480Smckusick } 488*57327Shibler /* 489*57327Shibler * Check for write to write protected label 490*57327Shibler */ 491*57327Shibler if (bn + pinfo->p_offset <= LABELSECTOR && 492*57327Shibler #if LABELSECTOR != 0 493*57327Shibler bn + pinfo->p_offset + sz > LABELSECTOR && 494*57327Shibler #endif 495*57327Shibler !(bp->b_flags & B_READ) && !(rs->sc_flags & RDF_WLABEL)) { 496*57327Shibler bp->b_error = EROFS; 497*57327Shibler goto bad; 498*57327Shibler } 499*57327Shibler bp->b_cylin = bn + pinfo->p_offset; 50041480Smckusick s = splbio(); 50141480Smckusick disksort(dp, bp); 50241480Smckusick if (dp->b_active == 0) { 50341480Smckusick dp->b_active = 1; 50441480Smckusick rdustart(unit); 50541480Smckusick } 50641480Smckusick splx(s); 50741480Smckusick return; 508*57327Shibler bad: 509*57327Shibler bp->b_flags |= B_ERROR; 51041480Smckusick done: 51141480Smckusick biodone(bp); 51241480Smckusick } 51341480Smckusick 51441480Smckusick /* 51541480Smckusick * Called from timeout() when handling maintenance releases 51641480Smckusick */ 51754770Storek void 51854770Storek rdrestart(arg) 51954770Storek void *arg; 52041480Smckusick { 52141480Smckusick int s = splbio(); 52254770Storek rdustart((int)arg); 52341480Smckusick splx(s); 52441480Smckusick } 52541480Smckusick 52641480Smckusick rdustart(unit) 52741480Smckusick register int unit; 52841480Smckusick { 52941480Smckusick register struct buf *bp; 53041480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 53141480Smckusick 53241480Smckusick bp = rdtab[unit].b_actf; 53341480Smckusick rs->sc_addr = bp->b_un.b_addr; 53441480Smckusick rs->sc_resid = bp->b_bcount; 53541480Smckusick if (hpibreq(&rs->sc_dq)) 53641480Smckusick rdstart(unit); 53741480Smckusick } 53841480Smckusick 539*57327Shibler struct buf * 540*57327Shibler rdfinish(unit, rs, bp) 541*57327Shibler int unit; 542*57327Shibler register struct rd_softc *rs; 543*57327Shibler register struct buf *bp; 544*57327Shibler { 545*57327Shibler register struct buf *dp = &rdtab[unit]; 546*57327Shibler 547*57327Shibler dp->b_errcnt = 0; 548*57327Shibler dp->b_actf = bp->b_actf; 549*57327Shibler bp->b_resid = 0; 550*57327Shibler biodone(bp); 551*57327Shibler hpibfree(&rs->sc_dq); 552*57327Shibler if (dp->b_actf) 553*57327Shibler return(dp->b_actf); 554*57327Shibler dp->b_active = 0; 555*57327Shibler if (rs->sc_flags & RDF_WANTED) { 556*57327Shibler rs->sc_flags &= ~RDF_WANTED; 557*57327Shibler wakeup((caddr_t)dp); 558*57327Shibler } 559*57327Shibler return(NULL); 560*57327Shibler } 561*57327Shibler 56241480Smckusick rdstart(unit) 56341480Smckusick register int unit; 56441480Smckusick { 56541480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 56641480Smckusick register struct buf *bp = rdtab[unit].b_actf; 56741480Smckusick register struct hp_device *hp = rs->sc_hd; 56841480Smckusick register int part; 56941480Smckusick 57041480Smckusick again: 57141480Smckusick #ifdef DEBUG 57241480Smckusick if (rddebug & RDB_FOLLOW) 57341480Smckusick printf("rdstart(%d): bp %x, %c\n", unit, bp, 57441480Smckusick (bp->b_flags & B_READ) ? 'R' : 'W'); 57541480Smckusick #endif 57641480Smckusick part = rdpart(bp->b_dev); 57741480Smckusick rs->sc_flags |= RDF_SEEK; 57841480Smckusick rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); 57941480Smckusick rs->sc_ioc.c_volume = C_SVOL(0); 58041480Smckusick rs->sc_ioc.c_saddr = C_SADDR; 58141480Smckusick rs->sc_ioc.c_hiaddr = 0; 582*57327Shibler rs->sc_ioc.c_addr = RDBTOS(bp->b_cylin); 58341480Smckusick rs->sc_ioc.c_nop2 = C_NOP; 58441480Smckusick rs->sc_ioc.c_slen = C_SLEN; 58541480Smckusick rs->sc_ioc.c_len = rs->sc_resid; 58641480Smckusick rs->sc_ioc.c_cmd = bp->b_flags & B_READ ? C_READ : C_WRITE; 58741480Smckusick #ifdef DEBUG 58841480Smckusick if (rddebug & RDB_IO) 58941480Smckusick printf("rdstart: hpibsend(%x, %x, %x, %x, %x)\n", 59041480Smckusick hp->hp_ctlr, hp->hp_slave, C_CMD, 59141480Smckusick &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2); 59241480Smckusick #endif 59341480Smckusick if (hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, &rs->sc_ioc.c_unit, 59441480Smckusick sizeof(rs->sc_ioc)-2) == sizeof(rs->sc_ioc)-2) { 59541480Smckusick if (hp->hp_dk >= 0) { 59641480Smckusick dk_busy |= 1 << hp->hp_dk; 59741480Smckusick dk_seek[hp->hp_dk]++; 59841480Smckusick } 59941480Smckusick #ifdef DEBUG 60041480Smckusick if (rddebug & RDB_IO) 60141480Smckusick printf("rdstart: hpibawait(%x)\n", hp->hp_ctlr); 60241480Smckusick #endif 60341480Smckusick hpibawait(hp->hp_ctlr); 60441480Smckusick return; 60541480Smckusick } 60641480Smckusick /* 60741480Smckusick * Experience has shown that the hpibwait in this hpibsend will 60841480Smckusick * occasionally timeout. It appears to occur mostly on old 7914 60941480Smckusick * drives with full maintenance tracks. We should probably 61041480Smckusick * integrate this with the backoff code in rderror. 61141480Smckusick */ 61241480Smckusick #ifdef DEBUG 61341480Smckusick if (rddebug & RDB_ERROR) 61441480Smckusick printf("rd%d: rdstart: cmd %x adr %d blk %d len %d ecnt %d\n", 61541480Smckusick unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, 61641480Smckusick bp->b_blkno, rs->sc_resid, rdtab[unit].b_errcnt); 61741480Smckusick rdstats[unit].rdretries++; 61841480Smckusick #endif 61941480Smckusick rs->sc_flags &= ~RDF_SEEK; 62041480Smckusick rdreset(rs, hp); 62141480Smckusick if (rdtab[unit].b_errcnt++ < RDRETRY) 62241480Smckusick goto again; 62341480Smckusick printf("rd%d: rdstart err: cmd 0x%x sect %d blk %d len %d\n", 62441480Smckusick unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, 62541480Smckusick bp->b_blkno, rs->sc_resid); 62641480Smckusick bp->b_flags |= B_ERROR; 62741480Smckusick bp->b_error = EIO; 628*57327Shibler bp = rdfinish(unit, rs, bp); 629*57327Shibler if (bp) { 630*57327Shibler rs->sc_addr = bp->b_un.b_addr; 631*57327Shibler rs->sc_resid = bp->b_bcount; 632*57327Shibler if (hpibreq(&rs->sc_dq)) 633*57327Shibler goto again; 63441480Smckusick } 63541480Smckusick } 63641480Smckusick 63741480Smckusick rdgo(unit) 63841480Smckusick register int unit; 63941480Smckusick { 64041480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 64141480Smckusick register struct hp_device *hp = rs->sc_hd; 64241480Smckusick struct buf *bp = rdtab[unit].b_actf; 64341480Smckusick 64441480Smckusick if (hp->hp_dk >= 0) { 64541480Smckusick dk_busy |= 1 << hp->hp_dk; 64641480Smckusick dk_xfer[hp->hp_dk]++; 64741480Smckusick dk_wds[hp->hp_dk] += rs->sc_resid >> 6; 64841480Smckusick } 649*57327Shibler #ifdef USELEDS 650*57327Shibler if (inledcontrol == 0) 651*57327Shibler ledcontrol(0, 0, LED_DISK); 652*57327Shibler #endif 65341480Smckusick hpibgo(hp->hp_ctlr, hp->hp_slave, C_EXEC, 65441480Smckusick rs->sc_addr, rs->sc_resid, bp->b_flags & B_READ); 65541480Smckusick } 65641480Smckusick 65741480Smckusick rdintr(unit) 65841480Smckusick register int unit; 65941480Smckusick { 66041480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 66141480Smckusick register struct buf *bp = rdtab[unit].b_actf; 66241480Smckusick register struct hp_device *hp = rs->sc_hd; 66341480Smckusick u_char stat = 13; /* in case hpibrecv fails */ 66445750Smckusick int rv, restart; 66541480Smckusick 66641480Smckusick #ifdef DEBUG 66741480Smckusick if (rddebug & RDB_FOLLOW) 66841480Smckusick printf("rdintr(%d): bp %x, %c, flags %x\n", unit, bp, 66941480Smckusick (bp->b_flags & B_READ) ? 'R' : 'W', rs->sc_flags); 67041480Smckusick if (bp == NULL) { 67141480Smckusick printf("rd%d: bp == NULL\n", unit); 67241480Smckusick return; 67341480Smckusick } 67441480Smckusick #endif 67541480Smckusick if (hp->hp_dk >= 0) 67641480Smckusick dk_busy &= ~(1 << hp->hp_dk); 67741480Smckusick if (rs->sc_flags & RDF_SEEK) { 67841480Smckusick rs->sc_flags &= ~RDF_SEEK; 67941480Smckusick if (hpibustart(hp->hp_ctlr)) 68041480Smckusick rdgo(unit); 68141480Smckusick return; 68241480Smckusick } 68341480Smckusick if ((rs->sc_flags & RDF_SWAIT) == 0) { 68441480Smckusick #ifdef DEBUG 68541480Smckusick rdstats[unit].rdpolltries++; 68641480Smckusick #endif 68741480Smckusick if (hpibpptest(hp->hp_ctlr, hp->hp_slave) == 0) { 68841480Smckusick #ifdef DEBUG 68941480Smckusick rdstats[unit].rdpollwaits++; 69041480Smckusick #endif 69141480Smckusick if (hp->hp_dk >= 0) 69241480Smckusick dk_busy |= 1 << hp->hp_dk; 69341480Smckusick rs->sc_flags |= RDF_SWAIT; 69441480Smckusick hpibawait(hp->hp_ctlr); 69541480Smckusick return; 69641480Smckusick } 69741480Smckusick } else 69841480Smckusick rs->sc_flags &= ~RDF_SWAIT; 69945750Smckusick rv = hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1); 70045750Smckusick if (rv != 1 || stat) { 70141480Smckusick #ifdef DEBUG 70241480Smckusick if (rddebug & RDB_ERROR) 70341480Smckusick printf("rdintr: recv failed or bad stat %d\n", stat); 70441480Smckusick #endif 70541480Smckusick restart = rderror(unit); 70641480Smckusick #ifdef DEBUG 70741480Smckusick rdstats[unit].rdretries++; 70841480Smckusick #endif 70941480Smckusick if (rdtab[unit].b_errcnt++ < RDRETRY) { 71041480Smckusick if (restart) 71141480Smckusick rdstart(unit); 71241480Smckusick return; 71341480Smckusick } 71441480Smckusick bp->b_flags |= B_ERROR; 71541480Smckusick bp->b_error = EIO; 71641480Smckusick } 717*57327Shibler if (rdfinish(unit, rs, bp)) 71841480Smckusick rdustart(unit); 71941480Smckusick } 72041480Smckusick 72141480Smckusick rdstatus(rs) 72241480Smckusick register struct rd_softc *rs; 72341480Smckusick { 72441480Smckusick register int c, s; 72541480Smckusick u_char stat; 72641480Smckusick int rv; 72741480Smckusick 72841480Smckusick c = rs->sc_hd->hp_ctlr; 72941480Smckusick s = rs->sc_hd->hp_slave; 73041480Smckusick rs->sc_rsc.c_unit = C_SUNIT(rs->sc_punit); 73141480Smckusick rs->sc_rsc.c_sram = C_SRAM; 73241480Smckusick rs->sc_rsc.c_ram = C_RAM; 73341480Smckusick rs->sc_rsc.c_cmd = C_STATUS; 73441480Smckusick bzero((caddr_t)&rs->sc_stat, sizeof(rs->sc_stat)); 73541480Smckusick rv = hpibsend(c, s, C_CMD, &rs->sc_rsc, sizeof(rs->sc_rsc)); 73641480Smckusick if (rv != sizeof(rs->sc_rsc)) { 73741480Smckusick #ifdef DEBUG 73841480Smckusick if (rddebug & RDB_STATUS) 73941480Smckusick printf("rdstatus: send C_CMD failed %d != %d\n", 74041480Smckusick rv, sizeof(rs->sc_rsc)); 74141480Smckusick #endif 74241480Smckusick return(1); 74341480Smckusick } 74441480Smckusick rv = hpibrecv(c, s, C_EXEC, &rs->sc_stat, sizeof(rs->sc_stat)); 74541480Smckusick if (rv != sizeof(rs->sc_stat)) { 74641480Smckusick #ifdef DEBUG 74741480Smckusick if (rddebug & RDB_STATUS) 74841480Smckusick printf("rdstatus: send C_EXEC failed %d != %d\n", 74941480Smckusick rv, sizeof(rs->sc_stat)); 75041480Smckusick #endif 75141480Smckusick return(1); 75241480Smckusick } 75341480Smckusick rv = hpibrecv(c, s, C_QSTAT, &stat, 1); 75441480Smckusick if (rv != 1 || stat) { 75541480Smckusick #ifdef DEBUG 75641480Smckusick if (rddebug & RDB_STATUS) 75741480Smckusick printf("rdstatus: recv failed %d or bad stat %d\n", 75841480Smckusick rv, stat); 75941480Smckusick #endif 76041480Smckusick return(1); 76141480Smckusick } 76241480Smckusick return(0); 76341480Smckusick } 76441480Smckusick 76541480Smckusick /* 76641480Smckusick * Deal with errors. 76741480Smckusick * Returns 1 if request should be restarted, 76841480Smckusick * 0 if we should just quietly give up. 76941480Smckusick */ 77041480Smckusick rderror(unit) 77141480Smckusick int unit; 77241480Smckusick { 77341480Smckusick struct rd_softc *rs = &rd_softc[unit]; 77441480Smckusick register struct rd_stat *sp; 77541480Smckusick struct buf *bp; 77642361Smckusick daddr_t hwbn, pbn; 77741480Smckusick 77841480Smckusick if (rdstatus(rs)) { 77941480Smckusick #ifdef DEBUG 78041480Smckusick printf("rd%d: couldn't get status\n", unit); 78141480Smckusick #endif 78241480Smckusick rdreset(rs, rs->sc_hd); 78341480Smckusick return(1); 78441480Smckusick } 78541480Smckusick sp = &rs->sc_stat; 78641480Smckusick if (sp->c_fef & FEF_REXMT) 78741480Smckusick return(1); 78841480Smckusick if (sp->c_fef & FEF_PF) { 78941480Smckusick rdreset(rs, rs->sc_hd); 79041480Smckusick return(1); 79141480Smckusick } 79241480Smckusick /* 79341480Smckusick * Unit requests release for internal maintenance. 79441480Smckusick * We just delay awhile and try again later. Use expontially 79541480Smckusick * increasing backoff ala ethernet drivers since we don't really 79641480Smckusick * know how long the maintenance will take. With RDWAITC and 79741480Smckusick * RDRETRY as defined, the range is 1 to 32 seconds. 79841480Smckusick */ 79941480Smckusick if (sp->c_fef & FEF_IMR) { 80041480Smckusick extern int hz; 80141480Smckusick int rdtimo = RDWAITC << rdtab[unit].b_errcnt; 80241480Smckusick #ifdef DEBUG 80341480Smckusick printf("rd%d: internal maintenance, %d second timeout\n", 80441480Smckusick unit, rdtimo); 80541480Smckusick rdstats[unit].rdtimeouts++; 80641480Smckusick #endif 80741480Smckusick hpibfree(&rs->sc_dq); 80854770Storek timeout(rdrestart, (void *)unit, rdtimo * hz); 80941480Smckusick return(0); 81041480Smckusick } 81141480Smckusick /* 81242361Smckusick * Only report error if we have reached the error reporting 81342361Smckusick * threshhold. By default, this will only report after the 81442361Smckusick * retry limit has been exceeded. 81542361Smckusick */ 81642361Smckusick if (rdtab[unit].b_errcnt < rderrthresh) 81742361Smckusick return(1); 81842361Smckusick 81942361Smckusick /* 82041480Smckusick * First conjure up the block number at which the error occured. 82141480Smckusick * Note that not all errors report a block number, in that case 82241480Smckusick * we just use b_blkno. 82341480Smckusick */ 82442361Smckusick bp = rdtab[unit].b_actf; 825*57327Shibler pbn = rs->sc_info.ri_label.d_partitions[rdpart(bp->b_dev)].p_offset; 82641480Smckusick if ((sp->c_fef & FEF_CU) || (sp->c_fef & FEF_DR) || 82741480Smckusick (sp->c_ief & IEF_RRMASK)) { 82842361Smckusick hwbn = RDBTOS(pbn + bp->b_blkno); 82941480Smckusick pbn = bp->b_blkno; 83041480Smckusick } else { 83142361Smckusick hwbn = sp->c_blk; 83242361Smckusick pbn = RDSTOB(hwbn) - pbn; 83341480Smckusick } 83441480Smckusick /* 83541480Smckusick * Now output a generic message suitable for badsect. 83641480Smckusick * Note that we don't use harderr cuz it just prints 83741480Smckusick * out b_blkno which is just the beginning block number 83841480Smckusick * of the transfer, not necessary where the error occured. 83941480Smckusick */ 84041480Smckusick printf("rd%d%c: hard error sn%d\n", 84141480Smckusick rdunit(bp->b_dev), 'a'+rdpart(bp->b_dev), pbn); 84241480Smckusick /* 84341480Smckusick * Now report the status as returned by the hardware with 84441480Smckusick * attempt at interpretation (unless debugging). 84541480Smckusick */ 84641480Smckusick printf("rd%d %s error:", 84741480Smckusick unit, (bp->b_flags & B_READ) ? "read" : "write"); 84841480Smckusick #ifdef DEBUG 84941480Smckusick if (rddebug & RDB_ERROR) { 85041480Smckusick /* status info */ 85141480Smckusick printf("\n volume: %d, unit: %d\n", 85241480Smckusick (sp->c_vu>>4)&0xF, sp->c_vu&0xF); 85341480Smckusick rdprinterr("reject", sp->c_ref, err_reject); 85441480Smckusick rdprinterr("fault", sp->c_fef, err_fault); 85541480Smckusick rdprinterr("access", sp->c_aef, err_access); 85641480Smckusick rdprinterr("info", sp->c_ief, err_info); 85742361Smckusick printf(" block: %d, P1-P10: ", hwbn); 85841480Smckusick printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8)); 85941480Smckusick printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8)); 86041480Smckusick printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4)); 86141480Smckusick /* command */ 86241480Smckusick printf(" ioc: "); 86341480Smckusick printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_pad, 8)); 86441480Smckusick printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_hiaddr, 4)); 86541480Smckusick printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_addr, 8)); 86641480Smckusick printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_nop2, 4)); 86741480Smckusick printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_len, 8)); 86841480Smckusick printf("%s\n", hexstr(*(u_short *)&rs->sc_ioc.c_cmd, 4)); 86941480Smckusick return(1); 87041480Smckusick } 87141480Smckusick #endif 87241480Smckusick printf(" v%d u%d, R0x%x F0x%x A0x%x I0x%x\n", 87341480Smckusick (sp->c_vu>>4)&0xF, sp->c_vu&0xF, 87441480Smckusick sp->c_ref, sp->c_fef, sp->c_aef, sp->c_ief); 87541480Smckusick printf("P1-P10: "); 87641480Smckusick printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8)); 87741480Smckusick printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8)); 87841480Smckusick printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4)); 87941480Smckusick return(1); 88041480Smckusick } 88141480Smckusick 88249303Shibler int 88349303Shibler rdread(dev, uio, flags) 88441480Smckusick dev_t dev; 88541480Smckusick struct uio *uio; 88649303Shibler int flags; 88741480Smckusick { 88841480Smckusick 88949303Shibler return (physio(rdstrategy, NULL, dev, B_READ, minphys, uio)); 89041480Smckusick } 89141480Smckusick 89249303Shibler int 89349303Shibler rdwrite(dev, uio, flags) 89441480Smckusick dev_t dev; 89541480Smckusick struct uio *uio; 89649303Shibler int flags; 89741480Smckusick { 89841480Smckusick 89949303Shibler return (physio(rdstrategy, NULL, dev, B_WRITE, minphys, uio)); 90041480Smckusick } 90141480Smckusick 90249303Shibler int 90349303Shibler rdioctl(dev, cmd, data, flag, p) 90441480Smckusick dev_t dev; 90541480Smckusick int cmd; 90641480Smckusick caddr_t data; 90741480Smckusick int flag; 90849303Shibler struct proc *p; 90941480Smckusick { 910*57327Shibler int unit = rdunit(dev); 911*57327Shibler register struct rd_softc *sc = &rd_softc[unit]; 912*57327Shibler register struct disklabel *lp = &sc->sc_info.ri_label; 913*57327Shibler int error, flags; 914*57327Shibler 915*57327Shibler switch (cmd) { 916*57327Shibler case DIOCGDINFO: 917*57327Shibler *(struct disklabel *)data = *lp; 918*57327Shibler return (0); 919*57327Shibler 920*57327Shibler case DIOCGPART: 921*57327Shibler ((struct partinfo *)data)->disklab = lp; 922*57327Shibler ((struct partinfo *)data)->part = 923*57327Shibler &lp->d_partitions[rdpart(dev)]; 924*57327Shibler return (0); 925*57327Shibler 926*57327Shibler case DIOCWLABEL: 927*57327Shibler if ((flag & FWRITE) == 0) 928*57327Shibler return (EBADF); 929*57327Shibler if (*(int *)data) 930*57327Shibler sc->sc_flags |= RDF_WLABEL; 931*57327Shibler else 932*57327Shibler sc->sc_flags &= ~RDF_WLABEL; 933*57327Shibler return (0); 934*57327Shibler 935*57327Shibler case DIOCSDINFO: 936*57327Shibler if ((flag & FWRITE) == 0) 937*57327Shibler return (EBADF); 938*57327Shibler return (setdisklabel(lp, (struct disklabel *)data, 939*57327Shibler (sc->sc_flags & RDF_WLABEL) ? 0 940*57327Shibler : sc->sc_info.ri_open)); 941*57327Shibler 942*57327Shibler case DIOCWDINFO: 943*57327Shibler if ((flag & FWRITE) == 0) 944*57327Shibler return (EBADF); 945*57327Shibler error = setdisklabel(lp, (struct disklabel *)data, 946*57327Shibler (sc->sc_flags & RDF_WLABEL) ? 0 947*57327Shibler : sc->sc_info.ri_open); 948*57327Shibler if (error) 949*57327Shibler return (error); 950*57327Shibler flags = sc->sc_flags; 951*57327Shibler sc->sc_flags = RDF_ALIVE | RDF_WLABEL; 952*57327Shibler error = writedisklabel(rdlabdev(dev), rdstrategy, lp); 953*57327Shibler sc->sc_flags = flags; 954*57327Shibler return (error); 955*57327Shibler } 95641480Smckusick return(EINVAL); 95741480Smckusick } 95841480Smckusick 95949303Shibler int 96041480Smckusick rdsize(dev) 96141480Smckusick dev_t dev; 96241480Smckusick { 96341480Smckusick register int unit = rdunit(dev); 96441480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 965*57327Shibler int psize, didopen = 0; 96641480Smckusick 96741480Smckusick if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) 96841480Smckusick return(-1); 969*57327Shibler 970*57327Shibler /* 971*57327Shibler * We get called very early on (via swapconf) 972*57327Shibler * without the device being open so we may need 973*57327Shibler * to handle it here. 974*57327Shibler */ 975*57327Shibler if (rs->sc_info.ri_open == 0) { 976*57327Shibler if (rdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) 977*57327Shibler return(-1); 978*57327Shibler didopen = 1; 979*57327Shibler } 980*57327Shibler psize = rs->sc_info.ri_label.d_partitions[rdpart(dev)].p_size; 981*57327Shibler if (didopen) 982*57327Shibler (void) rdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); 983*57327Shibler return (psize); 98441480Smckusick } 98541480Smckusick 98641480Smckusick #ifdef DEBUG 98741480Smckusick rdprinterr(str, err, tab) 98841480Smckusick char *str; 98941480Smckusick short err; 99041480Smckusick char *tab[]; 99141480Smckusick { 99241480Smckusick register int i; 99341480Smckusick int printed; 99441480Smckusick 99541480Smckusick if (err == 0) 99641480Smckusick return; 99741480Smckusick printf(" %s error field:", str, err); 99841480Smckusick printed = 0; 99941480Smckusick for (i = 0; i < 16; i++) 100041480Smckusick if (err & (0x8000 >> i)) 100141480Smckusick printf("%s%s", printed++ ? " + " : " ", tab[i]); 100241480Smckusick printf("\n"); 100341480Smckusick } 100441480Smckusick #endif 100541480Smckusick 100641480Smckusick /* 100741480Smckusick * Non-interrupt driven, non-dma dump routine. 100841480Smckusick */ 100949303Shibler int 101041480Smckusick rddump(dev) 101141480Smckusick dev_t dev; 101241480Smckusick { 101341480Smckusick int part = rdpart(dev); 101441480Smckusick int unit = rdunit(dev); 101541480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 101641480Smckusick register struct hp_device *hp = rs->sc_hd; 1017*57327Shibler register struct partition *pinfo; 101841480Smckusick register daddr_t baddr; 101945750Smckusick register int maddr, pages, i; 102041480Smckusick char stat; 102141480Smckusick extern int lowram, dumpsize; 102245750Smckusick #ifdef DEBUG 102345750Smckusick extern int pmapdebug; 102445750Smckusick pmapdebug = 0; 102545750Smckusick #endif 102641480Smckusick 102741480Smckusick /* is drive ok? */ 102841480Smckusick if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) 102941480Smckusick return (ENXIO); 1030*57327Shibler pinfo = &rs->sc_info.ri_label.d_partitions[part]; 1031*57327Shibler /* dump parameters in range? */ 1032*57327Shibler if (dumplo < 0 || dumplo >= pinfo->p_size || 1033*57327Shibler pinfo->p_fstype != FS_SWAP) 1034*57327Shibler return (EINVAL); 1035*57327Shibler pages = dumpsize; 1036*57327Shibler if (dumplo + ctod(pages) > pinfo->p_size) 1037*57327Shibler pages = dtoc(pinfo->p_size - dumplo); 1038*57327Shibler maddr = lowram; 1039*57327Shibler baddr = dumplo + pinfo->p_offset; 104041480Smckusick /* HPIB idle? */ 104141480Smckusick if (!hpibreq(&rs->sc_dq)) { 104241480Smckusick hpibreset(hp->hp_ctlr); 104341480Smckusick rdreset(rs, rs->sc_hd); 104441480Smckusick printf("[ drive %d reset ] ", unit); 104541480Smckusick } 104641480Smckusick for (i = 0; i < pages; i++) { 104741480Smckusick #define NPGMB (1024*1024/NBPG) 104841480Smckusick /* print out how many Mbs we have dumped */ 104941480Smckusick if (i && (i % NPGMB) == 0) 105041480Smckusick printf("%d ", i / NPGMB); 105141480Smckusick #undef NPBMG 105241480Smckusick rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); 105341480Smckusick rs->sc_ioc.c_volume = C_SVOL(0); 105441480Smckusick rs->sc_ioc.c_saddr = C_SADDR; 105541480Smckusick rs->sc_ioc.c_hiaddr = 0; 105641480Smckusick rs->sc_ioc.c_addr = RDBTOS(baddr); 105741480Smckusick rs->sc_ioc.c_nop2 = C_NOP; 105841480Smckusick rs->sc_ioc.c_slen = C_SLEN; 105941480Smckusick rs->sc_ioc.c_len = NBPG; 106041480Smckusick rs->sc_ioc.c_cmd = C_WRITE; 106141480Smckusick hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, 106241480Smckusick &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2); 1063*57327Shibler if (hpibswait(hp->hp_ctlr, hp->hp_slave)) 106441480Smckusick return (EIO); 106552614Smckusick pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr, 106651576Smckusick VM_PROT_READ, TRUE); 106741480Smckusick hpibsend(hp->hp_ctlr, hp->hp_slave, C_EXEC, vmmap, NBPG); 1068*57327Shibler (void) hpibswait(hp->hp_ctlr, hp->hp_slave); 106941480Smckusick hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1); 1070*57327Shibler if (stat) 107141480Smckusick return (EIO); 107241480Smckusick maddr += NBPG; 107341480Smckusick baddr += ctod(1); 107441480Smckusick } 107541480Smckusick return (0); 107641480Smckusick } 107741480Smckusick #endif 1078