141480Smckusick /* 241480Smckusick * Copyright (c) 1988 University of Utah. 3*63151Sbostic * Copyright (c) 1982, 1990, 1993 4*63151Sbostic * The Regents of the University of California. 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 * 1257327Shibler * from: Utah $Hdr: rd.c 1.44 92/12/26$ 1341480Smckusick * 14*63151Sbostic * @(#)rd.c 8.1 (Berkeley) 06/10/93 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> 2557327Shibler #include <sys/buf.h> 2657327Shibler #include <sys/stat.h> 2756507Sbostic #include <sys/dkstat.h> 2856507Sbostic #include <sys/disklabel.h> 2957327Shibler #include <sys/ioctl.h> 3057327Shibler #include <sys/fcntl.h> 3141480Smckusick 3256507Sbostic #include <hp/dev/device.h> 3356507Sbostic #include <hp300/dev/rdreg.h> 3457327Shibler #include <hp300/dev/rdvar.h> 3557327Shibler #ifdef USELEDS 3657327Shibler #include <hp300/hp300/led.h> 3757327Shibler #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(); 4557327Shibler void rdstrategy(); 4641480Smckusick struct driver rddriver = { 4741480Smckusick rdinit, "rd", rdstart, rdgo, rdintr, 4841480Smckusick }; 4941480Smckusick 5057327Shibler struct rd_softc rd_softc[NRD]; 5157327Shibler struct buf rdtab[NRD]; 5257327Shibler 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 }; 12157327Shibler 12257327Shibler struct rdstats rdstats[NRD]; 12357327Shibler int rddebug = 0x80; 12457327Shibler #define RDB_FOLLOW 0x01 12557327Shibler #define RDB_STATUS 0x02 12657327Shibler #define RDB_IDENT 0x04 12757327Shibler #define RDB_IO 0x08 12857327Shibler #define RDB_ASYNC 0x10 12957327Shibler #define RDB_ERROR 0x80 13041480Smckusick #endif 13141480Smckusick 13241480Smckusick /* 13357327Shibler * Misc. HW description, indexed by sc_type. 13457327Shibler * Nothing really critical here, could do without it. 13541480Smckusick */ 13657327Shibler struct rdidentinfo rdidentinfo[] = { 13757327Shibler { RD7946AID, 0, "7945A", 108416 }, 13857327Shibler { RD9134DID, 1, "9134D", 29088 }, 13957327Shibler { RD9134LID, 1, "9122S", 1232 }, 14057327Shibler { RD7912PID, 0, "7912P", 128128 }, 14157327Shibler { RD7914PID, 0, "7914P", 258048 }, 14257327Shibler { RD7958AID, 0, "7958A", 255276 }, 14357327Shibler { RD7957AID, 0, "7957A", 159544 }, 14457327Shibler { RD7933HID, 0, "7933H", 789958 }, 14557327Shibler { RD9134LID, 1, "9134L", 77840 }, 14657327Shibler { RD7936HID, 0, "7936H", 600978 }, 14757327Shibler { RD7937HID, 0, "7937H", 1116102 }, 14857327Shibler { RD7914CTID, 0, "7914CT", 258048 }, 14957327Shibler { RD7946AID, 0, "7946A", 108416 }, 15057327Shibler { RD9134LID, 1, "9122D", 1232 }, 15157327Shibler { RD7957BID, 0, "7957B", 159894 }, 15257327Shibler { RD7958BID, 0, "7958B", 297108 }, 15357327Shibler { RD7959BID, 0, "7959B", 594216 }, 15457327Shibler { RD2200AID, 0, "2200A", 654948 }, 15557327Shibler { RD2203AID, 0, "2203A", 1309896 } 15641480Smckusick }; 15757327Shibler 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); 21057327Shibler for (i = 0; i < numrdidentinfo; i++) 21157327Shibler if (id == rdidentinfo[i].ri_hwid) 21241480Smckusick break; 21357327Shibler 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 */ 26257327Shibler 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 } 28457327Shibler 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 32357327Shibler /* 32457327Shibler * Read or constuct a disklabel 32557327Shibler */ 32649303Shibler int 32757327Shibler rdgetinfo(dev) 32857327Shibler dev_t dev; 32957327Shibler { 33057327Shibler int unit = rdunit(dev); 33157327Shibler register struct rd_softc *rs = &rd_softc[unit]; 33257327Shibler register struct disklabel *lp = &rs->sc_info.ri_label; 33357327Shibler register struct partition *pi; 33457327Shibler char *msg, *readdisklabel(); 33557327Shibler 33657327Shibler /* 33757327Shibler * Set some default values to use while reading the label 33857327Shibler * or to use if there isn't a label. 33957327Shibler */ 34057327Shibler bzero((caddr_t)lp, sizeof *lp); 34157327Shibler lp->d_type = DTYPE_HPIB; 34257327Shibler lp->d_secsize = DEV_BSIZE; 34357327Shibler lp->d_nsectors = 32; 34457327Shibler lp->d_ntracks = 20; 34558054Shibler lp->d_ncylinders = 1; 34657327Shibler lp->d_secpercyl = 32*20; 34757327Shibler lp->d_npartitions = 3; 34857327Shibler lp->d_partitions[2].p_offset = 0; 34957327Shibler lp->d_partitions[2].p_size = LABELSECTOR+1; 35057327Shibler 35157327Shibler /* 35257327Shibler * Now try to read the disklabel 35357327Shibler */ 35457327Shibler msg = readdisklabel(rdlabdev(dev), rdstrategy, lp); 35557327Shibler if (msg == NULL) 35657327Shibler return(0); 35757327Shibler 35857327Shibler pi = lp->d_partitions; 35957327Shibler printf("rd%d: WARNING: %s, ", unit, msg); 36057327Shibler #ifdef COMPAT_NOLABEL 36157327Shibler printf("using old default partitioning\n"); 36257327Shibler rdmakedisklabel(unit, lp); 36357327Shibler #else 36457327Shibler printf("defining `c' partition as entire disk\n"); 36557327Shibler pi[2].p_size = rdidentinfo[rs->sc_type].ri_nblocks; 36657327Shibler #endif 36757327Shibler return(0); 36857327Shibler } 36957327Shibler 37057327Shibler int 37149303Shibler rdopen(dev, flags, mode, p) 37241480Smckusick dev_t dev; 37349303Shibler int flags, mode; 37449303Shibler struct proc *p; 37541480Smckusick { 37641480Smckusick register int unit = rdunit(dev); 37741480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 37857327Shibler int error, mask; 37941480Smckusick 38041480Smckusick if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) 38141480Smckusick return(ENXIO); 38257327Shibler 38357327Shibler /* 38457327Shibler * Wait for any pending opens/closes to complete 38557327Shibler */ 38657327Shibler while (rs->sc_flags & (RDF_OPENING|RDF_CLOSING)) 38757327Shibler sleep((caddr_t)rs, PRIBIO); 38857327Shibler 38957327Shibler /* 39057327Shibler * On first open, get label and partition info. 39157327Shibler * We may block reading the label, so be careful 39257327Shibler * to stop any other opens. 39357327Shibler */ 39457327Shibler if (rs->sc_info.ri_open == 0) { 39557327Shibler rs->sc_flags |= RDF_OPENING; 39657327Shibler error = rdgetinfo(dev); 39757327Shibler rs->sc_flags &= ~RDF_OPENING; 39857327Shibler wakeup((caddr_t)rs); 39957327Shibler if (error) 40057327Shibler return(error); 40157327Shibler } 40242361Smckusick if (rs->sc_hd->hp_dk >= 0) { 40342361Smckusick /* guess at xfer rate based on 3600 rpm (60 rps) */ 40442361Smckusick if (rs->sc_wpms == 0) 40557327Shibler rs->sc_wpms = 60 * rs->sc_info.ri_label.d_nsectors 40657327Shibler * DEV_BSIZE / 2; 40742361Smckusick dk_wpms[rs->sc_hd->hp_dk] = rs->sc_wpms; 40842361Smckusick } 40957327Shibler 41057327Shibler mask = 1 << rdpart(dev); 41157327Shibler if (mode == S_IFCHR) 41257327Shibler rs->sc_info.ri_copen |= mask; 41357327Shibler else 41457327Shibler rs->sc_info.ri_bopen |= mask; 41557327Shibler rs->sc_info.ri_open |= mask; 41641480Smckusick return(0); 41741480Smckusick } 41841480Smckusick 41957327Shibler int 42057327Shibler rdclose(dev, flag, mode, p) 42157327Shibler dev_t dev; 42257327Shibler int flag, mode; 42357327Shibler struct proc *p; 42457327Shibler { 42557327Shibler int unit = rdunit(dev); 42657327Shibler register struct rd_softc *rs = &rd_softc[unit]; 42757327Shibler register struct rdinfo *ri = &rs->sc_info; 42857327Shibler int mask, s; 42957327Shibler 43057327Shibler mask = 1 << rdpart(dev); 43157327Shibler if (mode == S_IFCHR) 43257327Shibler ri->ri_copen &= ~mask; 43357327Shibler else 43457327Shibler ri->ri_bopen &= ~mask; 43557327Shibler ri->ri_open = ri->ri_bopen | ri->ri_copen; 43657327Shibler /* 43757327Shibler * On last close, we wait for all activity to cease since 43857327Shibler * the label/parition info will become invalid. Since we 43957327Shibler * might sleep, we must block any opens while we are here. 44057327Shibler * Note we don't have to about other closes since we know 44157327Shibler * we are the last one. 44257327Shibler */ 44357327Shibler if (ri->ri_open == 0) { 44457327Shibler rs->sc_flags |= RDF_CLOSING; 44557327Shibler s = splbio(); 44657327Shibler while (rdtab[unit].b_active) { 44757327Shibler rs->sc_flags |= RDF_WANTED; 44857327Shibler sleep((caddr_t)&rdtab[unit], PRIBIO); 44957327Shibler } 45057327Shibler splx(s); 45157327Shibler rs->sc_flags &= ~(RDF_CLOSING|RDF_WLABEL); 45257327Shibler wakeup((caddr_t)rs); 45357327Shibler } 45457327Shibler return(0); 45557327Shibler } 45657327Shibler 45757327Shibler void 45841480Smckusick rdstrategy(bp) 45941480Smckusick register struct buf *bp; 46041480Smckusick { 46157327Shibler int unit = rdunit(bp->b_dev); 46241480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 46341480Smckusick register struct buf *dp = &rdtab[unit]; 46457327Shibler register struct partition *pinfo; 46545750Smckusick register daddr_t bn; 46645750Smckusick register int sz, s; 46741480Smckusick 46841480Smckusick #ifdef DEBUG 46941480Smckusick if (rddebug & RDB_FOLLOW) 47041480Smckusick printf("rdstrategy(%x): dev %x, bn %x, bcount %x, %c\n", 47141480Smckusick bp, bp->b_dev, bp->b_blkno, bp->b_bcount, 47241480Smckusick (bp->b_flags & B_READ) ? 'R' : 'W'); 47341480Smckusick #endif 47441480Smckusick bn = bp->b_blkno; 47545750Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 47657327Shibler pinfo = &rs->sc_info.ri_label.d_partitions[rdpart(bp->b_dev)]; 47757327Shibler if (bn < 0 || bn + sz > pinfo->p_size) { 47857327Shibler sz = pinfo->p_size - bn; 47945750Smckusick if (sz == 0) { 48041480Smckusick bp->b_resid = bp->b_bcount; 48141480Smckusick goto done; 48241480Smckusick } 48345750Smckusick if (sz < 0) { 48445750Smckusick bp->b_error = EINVAL; 48557327Shibler goto bad; 48645750Smckusick } 48745750Smckusick bp->b_bcount = dbtob(sz); 48841480Smckusick } 48957327Shibler /* 49057327Shibler * Check for write to write protected label 49157327Shibler */ 49257327Shibler if (bn + pinfo->p_offset <= LABELSECTOR && 49357327Shibler #if LABELSECTOR != 0 49457327Shibler bn + pinfo->p_offset + sz > LABELSECTOR && 49557327Shibler #endif 49657327Shibler !(bp->b_flags & B_READ) && !(rs->sc_flags & RDF_WLABEL)) { 49757327Shibler bp->b_error = EROFS; 49857327Shibler goto bad; 49957327Shibler } 50057327Shibler bp->b_cylin = bn + pinfo->p_offset; 50141480Smckusick s = splbio(); 50241480Smckusick disksort(dp, bp); 50341480Smckusick if (dp->b_active == 0) { 50441480Smckusick dp->b_active = 1; 50541480Smckusick rdustart(unit); 50641480Smckusick } 50741480Smckusick splx(s); 50841480Smckusick return; 50957327Shibler bad: 51057327Shibler bp->b_flags |= B_ERROR; 51141480Smckusick done: 51241480Smckusick biodone(bp); 51341480Smckusick } 51441480Smckusick 51541480Smckusick /* 51641480Smckusick * Called from timeout() when handling maintenance releases 51741480Smckusick */ 51854770Storek void 51954770Storek rdrestart(arg) 52054770Storek void *arg; 52141480Smckusick { 52241480Smckusick int s = splbio(); 52354770Storek rdustart((int)arg); 52441480Smckusick splx(s); 52541480Smckusick } 52641480Smckusick 52741480Smckusick rdustart(unit) 52841480Smckusick register int unit; 52941480Smckusick { 53041480Smckusick register struct buf *bp; 53141480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 53241480Smckusick 53341480Smckusick bp = rdtab[unit].b_actf; 53441480Smckusick rs->sc_addr = bp->b_un.b_addr; 53541480Smckusick rs->sc_resid = bp->b_bcount; 53641480Smckusick if (hpibreq(&rs->sc_dq)) 53741480Smckusick rdstart(unit); 53841480Smckusick } 53941480Smckusick 54057327Shibler struct buf * 54157327Shibler rdfinish(unit, rs, bp) 54257327Shibler int unit; 54357327Shibler register struct rd_softc *rs; 54457327Shibler register struct buf *bp; 54557327Shibler { 54657327Shibler register struct buf *dp = &rdtab[unit]; 54757327Shibler 54857327Shibler dp->b_errcnt = 0; 54957327Shibler dp->b_actf = bp->b_actf; 55057327Shibler bp->b_resid = 0; 55157327Shibler biodone(bp); 55257327Shibler hpibfree(&rs->sc_dq); 55357327Shibler if (dp->b_actf) 55457327Shibler return(dp->b_actf); 55557327Shibler dp->b_active = 0; 55657327Shibler if (rs->sc_flags & RDF_WANTED) { 55757327Shibler rs->sc_flags &= ~RDF_WANTED; 55857327Shibler wakeup((caddr_t)dp); 55957327Shibler } 56057327Shibler return(NULL); 56157327Shibler } 56257327Shibler 56341480Smckusick rdstart(unit) 56441480Smckusick register int unit; 56541480Smckusick { 56641480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 56741480Smckusick register struct buf *bp = rdtab[unit].b_actf; 56841480Smckusick register struct hp_device *hp = rs->sc_hd; 56941480Smckusick register int part; 57041480Smckusick 57141480Smckusick again: 57241480Smckusick #ifdef DEBUG 57341480Smckusick if (rddebug & RDB_FOLLOW) 57441480Smckusick printf("rdstart(%d): bp %x, %c\n", unit, bp, 57541480Smckusick (bp->b_flags & B_READ) ? 'R' : 'W'); 57641480Smckusick #endif 57741480Smckusick part = rdpart(bp->b_dev); 57841480Smckusick rs->sc_flags |= RDF_SEEK; 57941480Smckusick rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); 58041480Smckusick rs->sc_ioc.c_volume = C_SVOL(0); 58141480Smckusick rs->sc_ioc.c_saddr = C_SADDR; 58241480Smckusick rs->sc_ioc.c_hiaddr = 0; 58357327Shibler rs->sc_ioc.c_addr = RDBTOS(bp->b_cylin); 58441480Smckusick rs->sc_ioc.c_nop2 = C_NOP; 58541480Smckusick rs->sc_ioc.c_slen = C_SLEN; 58641480Smckusick rs->sc_ioc.c_len = rs->sc_resid; 58741480Smckusick rs->sc_ioc.c_cmd = bp->b_flags & B_READ ? C_READ : C_WRITE; 58841480Smckusick #ifdef DEBUG 58941480Smckusick if (rddebug & RDB_IO) 59041480Smckusick printf("rdstart: hpibsend(%x, %x, %x, %x, %x)\n", 59141480Smckusick hp->hp_ctlr, hp->hp_slave, C_CMD, 59241480Smckusick &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2); 59341480Smckusick #endif 59441480Smckusick if (hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, &rs->sc_ioc.c_unit, 59541480Smckusick sizeof(rs->sc_ioc)-2) == sizeof(rs->sc_ioc)-2) { 59641480Smckusick if (hp->hp_dk >= 0) { 59741480Smckusick dk_busy |= 1 << hp->hp_dk; 59841480Smckusick dk_seek[hp->hp_dk]++; 59941480Smckusick } 60041480Smckusick #ifdef DEBUG 60141480Smckusick if (rddebug & RDB_IO) 60241480Smckusick printf("rdstart: hpibawait(%x)\n", hp->hp_ctlr); 60341480Smckusick #endif 60441480Smckusick hpibawait(hp->hp_ctlr); 60541480Smckusick return; 60641480Smckusick } 60741480Smckusick /* 60841480Smckusick * Experience has shown that the hpibwait in this hpibsend will 60941480Smckusick * occasionally timeout. It appears to occur mostly on old 7914 61041480Smckusick * drives with full maintenance tracks. We should probably 61141480Smckusick * integrate this with the backoff code in rderror. 61241480Smckusick */ 61341480Smckusick #ifdef DEBUG 61441480Smckusick if (rddebug & RDB_ERROR) 61541480Smckusick printf("rd%d: rdstart: cmd %x adr %d blk %d len %d ecnt %d\n", 61641480Smckusick unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, 61741480Smckusick bp->b_blkno, rs->sc_resid, rdtab[unit].b_errcnt); 61841480Smckusick rdstats[unit].rdretries++; 61941480Smckusick #endif 62041480Smckusick rs->sc_flags &= ~RDF_SEEK; 62141480Smckusick rdreset(rs, hp); 62241480Smckusick if (rdtab[unit].b_errcnt++ < RDRETRY) 62341480Smckusick goto again; 62441480Smckusick printf("rd%d: rdstart err: cmd 0x%x sect %d blk %d len %d\n", 62541480Smckusick unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, 62641480Smckusick bp->b_blkno, rs->sc_resid); 62741480Smckusick bp->b_flags |= B_ERROR; 62841480Smckusick bp->b_error = EIO; 62957327Shibler bp = rdfinish(unit, rs, bp); 63057327Shibler if (bp) { 63157327Shibler rs->sc_addr = bp->b_un.b_addr; 63257327Shibler rs->sc_resid = bp->b_bcount; 63357327Shibler if (hpibreq(&rs->sc_dq)) 63457327Shibler goto again; 63541480Smckusick } 63641480Smckusick } 63741480Smckusick 63841480Smckusick rdgo(unit) 63941480Smckusick register int unit; 64041480Smckusick { 64141480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 64241480Smckusick register struct hp_device *hp = rs->sc_hd; 64341480Smckusick struct buf *bp = rdtab[unit].b_actf; 64441480Smckusick 64541480Smckusick if (hp->hp_dk >= 0) { 64641480Smckusick dk_busy |= 1 << hp->hp_dk; 64741480Smckusick dk_xfer[hp->hp_dk]++; 64841480Smckusick dk_wds[hp->hp_dk] += rs->sc_resid >> 6; 64941480Smckusick } 65057327Shibler #ifdef USELEDS 65157327Shibler if (inledcontrol == 0) 65257327Shibler ledcontrol(0, 0, LED_DISK); 65357327Shibler #endif 65441480Smckusick hpibgo(hp->hp_ctlr, hp->hp_slave, C_EXEC, 65541480Smckusick rs->sc_addr, rs->sc_resid, bp->b_flags & B_READ); 65641480Smckusick } 65741480Smckusick 65841480Smckusick rdintr(unit) 65941480Smckusick register int unit; 66041480Smckusick { 66141480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 66241480Smckusick register struct buf *bp = rdtab[unit].b_actf; 66341480Smckusick register struct hp_device *hp = rs->sc_hd; 66441480Smckusick u_char stat = 13; /* in case hpibrecv fails */ 66545750Smckusick int rv, restart; 66641480Smckusick 66741480Smckusick #ifdef DEBUG 66841480Smckusick if (rddebug & RDB_FOLLOW) 66941480Smckusick printf("rdintr(%d): bp %x, %c, flags %x\n", unit, bp, 67041480Smckusick (bp->b_flags & B_READ) ? 'R' : 'W', rs->sc_flags); 67141480Smckusick if (bp == NULL) { 67241480Smckusick printf("rd%d: bp == NULL\n", unit); 67341480Smckusick return; 67441480Smckusick } 67541480Smckusick #endif 67641480Smckusick if (hp->hp_dk >= 0) 67741480Smckusick dk_busy &= ~(1 << hp->hp_dk); 67841480Smckusick if (rs->sc_flags & RDF_SEEK) { 67941480Smckusick rs->sc_flags &= ~RDF_SEEK; 68041480Smckusick if (hpibustart(hp->hp_ctlr)) 68141480Smckusick rdgo(unit); 68241480Smckusick return; 68341480Smckusick } 68441480Smckusick if ((rs->sc_flags & RDF_SWAIT) == 0) { 68541480Smckusick #ifdef DEBUG 68641480Smckusick rdstats[unit].rdpolltries++; 68741480Smckusick #endif 68841480Smckusick if (hpibpptest(hp->hp_ctlr, hp->hp_slave) == 0) { 68941480Smckusick #ifdef DEBUG 69041480Smckusick rdstats[unit].rdpollwaits++; 69141480Smckusick #endif 69241480Smckusick if (hp->hp_dk >= 0) 69341480Smckusick dk_busy |= 1 << hp->hp_dk; 69441480Smckusick rs->sc_flags |= RDF_SWAIT; 69541480Smckusick hpibawait(hp->hp_ctlr); 69641480Smckusick return; 69741480Smckusick } 69841480Smckusick } else 69941480Smckusick rs->sc_flags &= ~RDF_SWAIT; 70045750Smckusick rv = hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1); 70145750Smckusick if (rv != 1 || stat) { 70241480Smckusick #ifdef DEBUG 70341480Smckusick if (rddebug & RDB_ERROR) 70441480Smckusick printf("rdintr: recv failed or bad stat %d\n", stat); 70541480Smckusick #endif 70641480Smckusick restart = rderror(unit); 70741480Smckusick #ifdef DEBUG 70841480Smckusick rdstats[unit].rdretries++; 70941480Smckusick #endif 71041480Smckusick if (rdtab[unit].b_errcnt++ < RDRETRY) { 71141480Smckusick if (restart) 71241480Smckusick rdstart(unit); 71341480Smckusick return; 71441480Smckusick } 71541480Smckusick bp->b_flags |= B_ERROR; 71641480Smckusick bp->b_error = EIO; 71741480Smckusick } 71857327Shibler if (rdfinish(unit, rs, bp)) 71941480Smckusick rdustart(unit); 72041480Smckusick } 72141480Smckusick 72241480Smckusick rdstatus(rs) 72341480Smckusick register struct rd_softc *rs; 72441480Smckusick { 72541480Smckusick register int c, s; 72641480Smckusick u_char stat; 72741480Smckusick int rv; 72841480Smckusick 72941480Smckusick c = rs->sc_hd->hp_ctlr; 73041480Smckusick s = rs->sc_hd->hp_slave; 73141480Smckusick rs->sc_rsc.c_unit = C_SUNIT(rs->sc_punit); 73241480Smckusick rs->sc_rsc.c_sram = C_SRAM; 73341480Smckusick rs->sc_rsc.c_ram = C_RAM; 73441480Smckusick rs->sc_rsc.c_cmd = C_STATUS; 73541480Smckusick bzero((caddr_t)&rs->sc_stat, sizeof(rs->sc_stat)); 73641480Smckusick rv = hpibsend(c, s, C_CMD, &rs->sc_rsc, sizeof(rs->sc_rsc)); 73741480Smckusick if (rv != sizeof(rs->sc_rsc)) { 73841480Smckusick #ifdef DEBUG 73941480Smckusick if (rddebug & RDB_STATUS) 74041480Smckusick printf("rdstatus: send C_CMD failed %d != %d\n", 74141480Smckusick rv, sizeof(rs->sc_rsc)); 74241480Smckusick #endif 74341480Smckusick return(1); 74441480Smckusick } 74541480Smckusick rv = hpibrecv(c, s, C_EXEC, &rs->sc_stat, sizeof(rs->sc_stat)); 74641480Smckusick if (rv != sizeof(rs->sc_stat)) { 74741480Smckusick #ifdef DEBUG 74841480Smckusick if (rddebug & RDB_STATUS) 74941480Smckusick printf("rdstatus: send C_EXEC failed %d != %d\n", 75041480Smckusick rv, sizeof(rs->sc_stat)); 75141480Smckusick #endif 75241480Smckusick return(1); 75341480Smckusick } 75441480Smckusick rv = hpibrecv(c, s, C_QSTAT, &stat, 1); 75541480Smckusick if (rv != 1 || stat) { 75641480Smckusick #ifdef DEBUG 75741480Smckusick if (rddebug & RDB_STATUS) 75841480Smckusick printf("rdstatus: recv failed %d or bad stat %d\n", 75941480Smckusick rv, stat); 76041480Smckusick #endif 76141480Smckusick return(1); 76241480Smckusick } 76341480Smckusick return(0); 76441480Smckusick } 76541480Smckusick 76641480Smckusick /* 76741480Smckusick * Deal with errors. 76841480Smckusick * Returns 1 if request should be restarted, 76941480Smckusick * 0 if we should just quietly give up. 77041480Smckusick */ 77141480Smckusick rderror(unit) 77241480Smckusick int unit; 77341480Smckusick { 77441480Smckusick struct rd_softc *rs = &rd_softc[unit]; 77541480Smckusick register struct rd_stat *sp; 77641480Smckusick struct buf *bp; 77742361Smckusick daddr_t hwbn, pbn; 77841480Smckusick 77941480Smckusick if (rdstatus(rs)) { 78041480Smckusick #ifdef DEBUG 78141480Smckusick printf("rd%d: couldn't get status\n", unit); 78241480Smckusick #endif 78341480Smckusick rdreset(rs, rs->sc_hd); 78441480Smckusick return(1); 78541480Smckusick } 78641480Smckusick sp = &rs->sc_stat; 78741480Smckusick if (sp->c_fef & FEF_REXMT) 78841480Smckusick return(1); 78941480Smckusick if (sp->c_fef & FEF_PF) { 79041480Smckusick rdreset(rs, rs->sc_hd); 79141480Smckusick return(1); 79241480Smckusick } 79341480Smckusick /* 79441480Smckusick * Unit requests release for internal maintenance. 79541480Smckusick * We just delay awhile and try again later. Use expontially 79641480Smckusick * increasing backoff ala ethernet drivers since we don't really 79741480Smckusick * know how long the maintenance will take. With RDWAITC and 79841480Smckusick * RDRETRY as defined, the range is 1 to 32 seconds. 79941480Smckusick */ 80041480Smckusick if (sp->c_fef & FEF_IMR) { 80141480Smckusick extern int hz; 80241480Smckusick int rdtimo = RDWAITC << rdtab[unit].b_errcnt; 80341480Smckusick #ifdef DEBUG 80441480Smckusick printf("rd%d: internal maintenance, %d second timeout\n", 80541480Smckusick unit, rdtimo); 80641480Smckusick rdstats[unit].rdtimeouts++; 80741480Smckusick #endif 80841480Smckusick hpibfree(&rs->sc_dq); 80954770Storek timeout(rdrestart, (void *)unit, rdtimo * hz); 81041480Smckusick return(0); 81141480Smckusick } 81241480Smckusick /* 81342361Smckusick * Only report error if we have reached the error reporting 81442361Smckusick * threshhold. By default, this will only report after the 81542361Smckusick * retry limit has been exceeded. 81642361Smckusick */ 81742361Smckusick if (rdtab[unit].b_errcnt < rderrthresh) 81842361Smckusick return(1); 81942361Smckusick 82042361Smckusick /* 82141480Smckusick * First conjure up the block number at which the error occured. 82241480Smckusick * Note that not all errors report a block number, in that case 82341480Smckusick * we just use b_blkno. 82441480Smckusick */ 82542361Smckusick bp = rdtab[unit].b_actf; 82657327Shibler pbn = rs->sc_info.ri_label.d_partitions[rdpart(bp->b_dev)].p_offset; 82741480Smckusick if ((sp->c_fef & FEF_CU) || (sp->c_fef & FEF_DR) || 82841480Smckusick (sp->c_ief & IEF_RRMASK)) { 82942361Smckusick hwbn = RDBTOS(pbn + bp->b_blkno); 83041480Smckusick pbn = bp->b_blkno; 83141480Smckusick } else { 83242361Smckusick hwbn = sp->c_blk; 83342361Smckusick pbn = RDSTOB(hwbn) - pbn; 83441480Smckusick } 83541480Smckusick /* 83641480Smckusick * Now output a generic message suitable for badsect. 83741480Smckusick * Note that we don't use harderr cuz it just prints 83841480Smckusick * out b_blkno which is just the beginning block number 83941480Smckusick * of the transfer, not necessary where the error occured. 84041480Smckusick */ 84141480Smckusick printf("rd%d%c: hard error sn%d\n", 84241480Smckusick rdunit(bp->b_dev), 'a'+rdpart(bp->b_dev), pbn); 84341480Smckusick /* 84441480Smckusick * Now report the status as returned by the hardware with 84541480Smckusick * attempt at interpretation (unless debugging). 84641480Smckusick */ 84741480Smckusick printf("rd%d %s error:", 84841480Smckusick unit, (bp->b_flags & B_READ) ? "read" : "write"); 84941480Smckusick #ifdef DEBUG 85041480Smckusick if (rddebug & RDB_ERROR) { 85141480Smckusick /* status info */ 85241480Smckusick printf("\n volume: %d, unit: %d\n", 85341480Smckusick (sp->c_vu>>4)&0xF, sp->c_vu&0xF); 85441480Smckusick rdprinterr("reject", sp->c_ref, err_reject); 85541480Smckusick rdprinterr("fault", sp->c_fef, err_fault); 85641480Smckusick rdprinterr("access", sp->c_aef, err_access); 85741480Smckusick rdprinterr("info", sp->c_ief, err_info); 85842361Smckusick printf(" block: %d, P1-P10: ", hwbn); 85941480Smckusick printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8)); 86041480Smckusick printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8)); 86141480Smckusick printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4)); 86241480Smckusick /* command */ 86341480Smckusick printf(" ioc: "); 86441480Smckusick printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_pad, 8)); 86541480Smckusick printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_hiaddr, 4)); 86641480Smckusick printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_addr, 8)); 86741480Smckusick printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_nop2, 4)); 86841480Smckusick printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_len, 8)); 86941480Smckusick printf("%s\n", hexstr(*(u_short *)&rs->sc_ioc.c_cmd, 4)); 87041480Smckusick return(1); 87141480Smckusick } 87241480Smckusick #endif 87341480Smckusick printf(" v%d u%d, R0x%x F0x%x A0x%x I0x%x\n", 87441480Smckusick (sp->c_vu>>4)&0xF, sp->c_vu&0xF, 87541480Smckusick sp->c_ref, sp->c_fef, sp->c_aef, sp->c_ief); 87641480Smckusick printf("P1-P10: "); 87741480Smckusick printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8)); 87841480Smckusick printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8)); 87941480Smckusick printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4)); 88041480Smckusick return(1); 88141480Smckusick } 88241480Smckusick 88349303Shibler int 88449303Shibler rdread(dev, uio, flags) 88541480Smckusick dev_t dev; 88641480Smckusick struct uio *uio; 88749303Shibler int flags; 88841480Smckusick { 88941480Smckusick 89049303Shibler return (physio(rdstrategy, NULL, dev, B_READ, minphys, uio)); 89141480Smckusick } 89241480Smckusick 89349303Shibler int 89449303Shibler rdwrite(dev, uio, flags) 89541480Smckusick dev_t dev; 89641480Smckusick struct uio *uio; 89749303Shibler int flags; 89841480Smckusick { 89941480Smckusick 90049303Shibler return (physio(rdstrategy, NULL, dev, B_WRITE, minphys, uio)); 90141480Smckusick } 90241480Smckusick 90349303Shibler int 90449303Shibler rdioctl(dev, cmd, data, flag, p) 90541480Smckusick dev_t dev; 90641480Smckusick int cmd; 90741480Smckusick caddr_t data; 90841480Smckusick int flag; 90949303Shibler struct proc *p; 91041480Smckusick { 91157327Shibler int unit = rdunit(dev); 91257327Shibler register struct rd_softc *sc = &rd_softc[unit]; 91357327Shibler register struct disklabel *lp = &sc->sc_info.ri_label; 91457327Shibler int error, flags; 91557327Shibler 91657327Shibler switch (cmd) { 91757327Shibler case DIOCGDINFO: 91857327Shibler *(struct disklabel *)data = *lp; 91957327Shibler return (0); 92057327Shibler 92157327Shibler case DIOCGPART: 92257327Shibler ((struct partinfo *)data)->disklab = lp; 92357327Shibler ((struct partinfo *)data)->part = 92457327Shibler &lp->d_partitions[rdpart(dev)]; 92557327Shibler return (0); 92657327Shibler 92757327Shibler case DIOCWLABEL: 92857327Shibler if ((flag & FWRITE) == 0) 92957327Shibler return (EBADF); 93057327Shibler if (*(int *)data) 93157327Shibler sc->sc_flags |= RDF_WLABEL; 93257327Shibler else 93357327Shibler sc->sc_flags &= ~RDF_WLABEL; 93457327Shibler return (0); 93557327Shibler 93657327Shibler case DIOCSDINFO: 93757327Shibler if ((flag & FWRITE) == 0) 93857327Shibler return (EBADF); 93957327Shibler return (setdisklabel(lp, (struct disklabel *)data, 94057327Shibler (sc->sc_flags & RDF_WLABEL) ? 0 94157327Shibler : sc->sc_info.ri_open)); 94257327Shibler 94357327Shibler case DIOCWDINFO: 94457327Shibler if ((flag & FWRITE) == 0) 94557327Shibler return (EBADF); 94657327Shibler error = setdisklabel(lp, (struct disklabel *)data, 94757327Shibler (sc->sc_flags & RDF_WLABEL) ? 0 94857327Shibler : sc->sc_info.ri_open); 94957327Shibler if (error) 95057327Shibler return (error); 95157327Shibler flags = sc->sc_flags; 95257327Shibler sc->sc_flags = RDF_ALIVE | RDF_WLABEL; 95357327Shibler error = writedisklabel(rdlabdev(dev), rdstrategy, lp); 95457327Shibler sc->sc_flags = flags; 95557327Shibler return (error); 95657327Shibler } 95741480Smckusick return(EINVAL); 95841480Smckusick } 95941480Smckusick 96049303Shibler int 96141480Smckusick rdsize(dev) 96241480Smckusick dev_t dev; 96341480Smckusick { 96441480Smckusick register int unit = rdunit(dev); 96541480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 96657327Shibler int psize, didopen = 0; 96741480Smckusick 96841480Smckusick if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) 96941480Smckusick return(-1); 97057327Shibler 97157327Shibler /* 97257327Shibler * We get called very early on (via swapconf) 97357327Shibler * without the device being open so we may need 97457327Shibler * to handle it here. 97557327Shibler */ 97657327Shibler if (rs->sc_info.ri_open == 0) { 97757327Shibler if (rdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) 97857327Shibler return(-1); 97957327Shibler didopen = 1; 98057327Shibler } 98157327Shibler psize = rs->sc_info.ri_label.d_partitions[rdpart(dev)].p_size; 98257327Shibler if (didopen) 98357327Shibler (void) rdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); 98457327Shibler return (psize); 98541480Smckusick } 98641480Smckusick 98741480Smckusick #ifdef DEBUG 98841480Smckusick rdprinterr(str, err, tab) 98941480Smckusick char *str; 99041480Smckusick short err; 99141480Smckusick char *tab[]; 99241480Smckusick { 99341480Smckusick register int i; 99441480Smckusick int printed; 99541480Smckusick 99641480Smckusick if (err == 0) 99741480Smckusick return; 99841480Smckusick printf(" %s error field:", str, err); 99941480Smckusick printed = 0; 100041480Smckusick for (i = 0; i < 16; i++) 100141480Smckusick if (err & (0x8000 >> i)) 100241480Smckusick printf("%s%s", printed++ ? " + " : " ", tab[i]); 100341480Smckusick printf("\n"); 100441480Smckusick } 100541480Smckusick #endif 100641480Smckusick 100741480Smckusick /* 100841480Smckusick * Non-interrupt driven, non-dma dump routine. 100941480Smckusick */ 101049303Shibler int 101141480Smckusick rddump(dev) 101241480Smckusick dev_t dev; 101341480Smckusick { 101441480Smckusick int part = rdpart(dev); 101541480Smckusick int unit = rdunit(dev); 101641480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 101741480Smckusick register struct hp_device *hp = rs->sc_hd; 101857327Shibler register struct partition *pinfo; 101941480Smckusick register daddr_t baddr; 102045750Smckusick register int maddr, pages, i; 102141480Smckusick char stat; 102241480Smckusick extern int lowram, dumpsize; 102345750Smckusick #ifdef DEBUG 102445750Smckusick extern int pmapdebug; 102545750Smckusick pmapdebug = 0; 102645750Smckusick #endif 102741480Smckusick 102841480Smckusick /* is drive ok? */ 102941480Smckusick if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) 103041480Smckusick return (ENXIO); 103157327Shibler pinfo = &rs->sc_info.ri_label.d_partitions[part]; 103257327Shibler /* dump parameters in range? */ 103357327Shibler if (dumplo < 0 || dumplo >= pinfo->p_size || 103457327Shibler pinfo->p_fstype != FS_SWAP) 103557327Shibler return (EINVAL); 103657327Shibler pages = dumpsize; 103757327Shibler if (dumplo + ctod(pages) > pinfo->p_size) 103857327Shibler pages = dtoc(pinfo->p_size - dumplo); 103957327Shibler maddr = lowram; 104057327Shibler baddr = dumplo + pinfo->p_offset; 104141480Smckusick /* HPIB idle? */ 104241480Smckusick if (!hpibreq(&rs->sc_dq)) { 104341480Smckusick hpibreset(hp->hp_ctlr); 104441480Smckusick rdreset(rs, rs->sc_hd); 104541480Smckusick printf("[ drive %d reset ] ", unit); 104641480Smckusick } 104741480Smckusick for (i = 0; i < pages; i++) { 104841480Smckusick #define NPGMB (1024*1024/NBPG) 104941480Smckusick /* print out how many Mbs we have dumped */ 105041480Smckusick if (i && (i % NPGMB) == 0) 105141480Smckusick printf("%d ", i / NPGMB); 105241480Smckusick #undef NPBMG 105341480Smckusick rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); 105441480Smckusick rs->sc_ioc.c_volume = C_SVOL(0); 105541480Smckusick rs->sc_ioc.c_saddr = C_SADDR; 105641480Smckusick rs->sc_ioc.c_hiaddr = 0; 105741480Smckusick rs->sc_ioc.c_addr = RDBTOS(baddr); 105841480Smckusick rs->sc_ioc.c_nop2 = C_NOP; 105941480Smckusick rs->sc_ioc.c_slen = C_SLEN; 106041480Smckusick rs->sc_ioc.c_len = NBPG; 106141480Smckusick rs->sc_ioc.c_cmd = C_WRITE; 106241480Smckusick hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, 106341480Smckusick &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2); 106457327Shibler if (hpibswait(hp->hp_ctlr, hp->hp_slave)) 106541480Smckusick return (EIO); 106652614Smckusick pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr, 106751576Smckusick VM_PROT_READ, TRUE); 106841480Smckusick hpibsend(hp->hp_ctlr, hp->hp_slave, C_EXEC, vmmap, NBPG); 106957327Shibler (void) hpibswait(hp->hp_ctlr, hp->hp_slave); 107041480Smckusick hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1); 107157327Shibler if (stat) 107241480Smckusick return (EIO); 107341480Smckusick maddr += NBPG; 107441480Smckusick baddr += ctod(1); 107541480Smckusick } 107641480Smckusick return (0); 107741480Smckusick } 107841480Smckusick #endif 1079