141480Smckusick /* 241480Smckusick * Copyright (c) 1988 University of Utah. 363151Sbostic * Copyright (c) 1982, 1990, 1993 463151Sbostic * 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*67184Shibler * @(#)rd.c 8.2 (Berkeley) 05/19/94 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; 366*67184Shibler /* XXX reset other info since readdisklabel screws with it */ 367*67184Shibler lp->d_npartitions = 3; 368*67184Shibler pi[0].p_size = 0; 36957327Shibler #endif 37057327Shibler return(0); 37157327Shibler } 37257327Shibler 37357327Shibler int 37449303Shibler rdopen(dev, flags, mode, p) 37541480Smckusick dev_t dev; 37649303Shibler int flags, mode; 37749303Shibler struct proc *p; 37841480Smckusick { 37941480Smckusick register int unit = rdunit(dev); 38041480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 38157327Shibler int error, mask; 38241480Smckusick 38341480Smckusick if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) 38441480Smckusick return(ENXIO); 38557327Shibler 38657327Shibler /* 38757327Shibler * Wait for any pending opens/closes to complete 38857327Shibler */ 38957327Shibler while (rs->sc_flags & (RDF_OPENING|RDF_CLOSING)) 39057327Shibler sleep((caddr_t)rs, PRIBIO); 39157327Shibler 39257327Shibler /* 39357327Shibler * On first open, get label and partition info. 39457327Shibler * We may block reading the label, so be careful 39557327Shibler * to stop any other opens. 39657327Shibler */ 39757327Shibler if (rs->sc_info.ri_open == 0) { 39857327Shibler rs->sc_flags |= RDF_OPENING; 39957327Shibler error = rdgetinfo(dev); 40057327Shibler rs->sc_flags &= ~RDF_OPENING; 40157327Shibler wakeup((caddr_t)rs); 40257327Shibler if (error) 40357327Shibler return(error); 40457327Shibler } 40542361Smckusick if (rs->sc_hd->hp_dk >= 0) { 40642361Smckusick /* guess at xfer rate based on 3600 rpm (60 rps) */ 40742361Smckusick if (rs->sc_wpms == 0) 40857327Shibler rs->sc_wpms = 60 * rs->sc_info.ri_label.d_nsectors 40957327Shibler * DEV_BSIZE / 2; 41042361Smckusick dk_wpms[rs->sc_hd->hp_dk] = rs->sc_wpms; 41142361Smckusick } 41257327Shibler 41357327Shibler mask = 1 << rdpart(dev); 41457327Shibler if (mode == S_IFCHR) 41557327Shibler rs->sc_info.ri_copen |= mask; 41657327Shibler else 41757327Shibler rs->sc_info.ri_bopen |= mask; 41857327Shibler rs->sc_info.ri_open |= mask; 41941480Smckusick return(0); 42041480Smckusick } 42141480Smckusick 42257327Shibler int 42357327Shibler rdclose(dev, flag, mode, p) 42457327Shibler dev_t dev; 42557327Shibler int flag, mode; 42657327Shibler struct proc *p; 42757327Shibler { 42857327Shibler int unit = rdunit(dev); 42957327Shibler register struct rd_softc *rs = &rd_softc[unit]; 43057327Shibler register struct rdinfo *ri = &rs->sc_info; 43157327Shibler int mask, s; 43257327Shibler 43357327Shibler mask = 1 << rdpart(dev); 43457327Shibler if (mode == S_IFCHR) 43557327Shibler ri->ri_copen &= ~mask; 43657327Shibler else 43757327Shibler ri->ri_bopen &= ~mask; 43857327Shibler ri->ri_open = ri->ri_bopen | ri->ri_copen; 43957327Shibler /* 44057327Shibler * On last close, we wait for all activity to cease since 44157327Shibler * the label/parition info will become invalid. Since we 44257327Shibler * might sleep, we must block any opens while we are here. 44357327Shibler * Note we don't have to about other closes since we know 44457327Shibler * we are the last one. 44557327Shibler */ 44657327Shibler if (ri->ri_open == 0) { 44757327Shibler rs->sc_flags |= RDF_CLOSING; 44857327Shibler s = splbio(); 44957327Shibler while (rdtab[unit].b_active) { 45057327Shibler rs->sc_flags |= RDF_WANTED; 45157327Shibler sleep((caddr_t)&rdtab[unit], PRIBIO); 45257327Shibler } 45357327Shibler splx(s); 45457327Shibler rs->sc_flags &= ~(RDF_CLOSING|RDF_WLABEL); 45557327Shibler wakeup((caddr_t)rs); 45657327Shibler } 45757327Shibler return(0); 45857327Shibler } 45957327Shibler 46057327Shibler void 46141480Smckusick rdstrategy(bp) 46241480Smckusick register struct buf *bp; 46341480Smckusick { 46457327Shibler int unit = rdunit(bp->b_dev); 46541480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 46641480Smckusick register struct buf *dp = &rdtab[unit]; 46757327Shibler register struct partition *pinfo; 46845750Smckusick register daddr_t bn; 46945750Smckusick register int sz, s; 47041480Smckusick 47141480Smckusick #ifdef DEBUG 47241480Smckusick if (rddebug & RDB_FOLLOW) 47341480Smckusick printf("rdstrategy(%x): dev %x, bn %x, bcount %x, %c\n", 47441480Smckusick bp, bp->b_dev, bp->b_blkno, bp->b_bcount, 47541480Smckusick (bp->b_flags & B_READ) ? 'R' : 'W'); 47641480Smckusick #endif 47741480Smckusick bn = bp->b_blkno; 47845750Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 47957327Shibler pinfo = &rs->sc_info.ri_label.d_partitions[rdpart(bp->b_dev)]; 48057327Shibler if (bn < 0 || bn + sz > pinfo->p_size) { 48157327Shibler sz = pinfo->p_size - bn; 48245750Smckusick if (sz == 0) { 48341480Smckusick bp->b_resid = bp->b_bcount; 48441480Smckusick goto done; 48541480Smckusick } 48645750Smckusick if (sz < 0) { 48745750Smckusick bp->b_error = EINVAL; 48857327Shibler goto bad; 48945750Smckusick } 49045750Smckusick bp->b_bcount = dbtob(sz); 49141480Smckusick } 49257327Shibler /* 49357327Shibler * Check for write to write protected label 49457327Shibler */ 49557327Shibler if (bn + pinfo->p_offset <= LABELSECTOR && 49657327Shibler #if LABELSECTOR != 0 49757327Shibler bn + pinfo->p_offset + sz > LABELSECTOR && 49857327Shibler #endif 49957327Shibler !(bp->b_flags & B_READ) && !(rs->sc_flags & RDF_WLABEL)) { 50057327Shibler bp->b_error = EROFS; 50157327Shibler goto bad; 50257327Shibler } 50357327Shibler bp->b_cylin = bn + pinfo->p_offset; 50441480Smckusick s = splbio(); 50541480Smckusick disksort(dp, bp); 50641480Smckusick if (dp->b_active == 0) { 50741480Smckusick dp->b_active = 1; 50841480Smckusick rdustart(unit); 50941480Smckusick } 51041480Smckusick splx(s); 51141480Smckusick return; 51257327Shibler bad: 51357327Shibler bp->b_flags |= B_ERROR; 51441480Smckusick done: 51541480Smckusick biodone(bp); 51641480Smckusick } 51741480Smckusick 51841480Smckusick /* 51941480Smckusick * Called from timeout() when handling maintenance releases 52041480Smckusick */ 52154770Storek void 52254770Storek rdrestart(arg) 52354770Storek void *arg; 52441480Smckusick { 52541480Smckusick int s = splbio(); 52654770Storek rdustart((int)arg); 52741480Smckusick splx(s); 52841480Smckusick } 52941480Smckusick 53041480Smckusick rdustart(unit) 53141480Smckusick register int unit; 53241480Smckusick { 53341480Smckusick register struct buf *bp; 53441480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 53541480Smckusick 53641480Smckusick bp = rdtab[unit].b_actf; 53741480Smckusick rs->sc_addr = bp->b_un.b_addr; 53841480Smckusick rs->sc_resid = bp->b_bcount; 53941480Smckusick if (hpibreq(&rs->sc_dq)) 54041480Smckusick rdstart(unit); 54141480Smckusick } 54241480Smckusick 54357327Shibler struct buf * 54457327Shibler rdfinish(unit, rs, bp) 54557327Shibler int unit; 54657327Shibler register struct rd_softc *rs; 54757327Shibler register struct buf *bp; 54857327Shibler { 54957327Shibler register struct buf *dp = &rdtab[unit]; 55057327Shibler 55157327Shibler dp->b_errcnt = 0; 55257327Shibler dp->b_actf = bp->b_actf; 55357327Shibler bp->b_resid = 0; 55457327Shibler biodone(bp); 55557327Shibler hpibfree(&rs->sc_dq); 55657327Shibler if (dp->b_actf) 55757327Shibler return(dp->b_actf); 55857327Shibler dp->b_active = 0; 55957327Shibler if (rs->sc_flags & RDF_WANTED) { 56057327Shibler rs->sc_flags &= ~RDF_WANTED; 56157327Shibler wakeup((caddr_t)dp); 56257327Shibler } 56357327Shibler return(NULL); 56457327Shibler } 56557327Shibler 56641480Smckusick rdstart(unit) 56741480Smckusick register int unit; 56841480Smckusick { 56941480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 57041480Smckusick register struct buf *bp = rdtab[unit].b_actf; 57141480Smckusick register struct hp_device *hp = rs->sc_hd; 57241480Smckusick register int part; 57341480Smckusick 57441480Smckusick again: 57541480Smckusick #ifdef DEBUG 57641480Smckusick if (rddebug & RDB_FOLLOW) 57741480Smckusick printf("rdstart(%d): bp %x, %c\n", unit, bp, 57841480Smckusick (bp->b_flags & B_READ) ? 'R' : 'W'); 57941480Smckusick #endif 58041480Smckusick part = rdpart(bp->b_dev); 58141480Smckusick rs->sc_flags |= RDF_SEEK; 58241480Smckusick rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); 58341480Smckusick rs->sc_ioc.c_volume = C_SVOL(0); 58441480Smckusick rs->sc_ioc.c_saddr = C_SADDR; 58541480Smckusick rs->sc_ioc.c_hiaddr = 0; 58657327Shibler rs->sc_ioc.c_addr = RDBTOS(bp->b_cylin); 58741480Smckusick rs->sc_ioc.c_nop2 = C_NOP; 58841480Smckusick rs->sc_ioc.c_slen = C_SLEN; 58941480Smckusick rs->sc_ioc.c_len = rs->sc_resid; 59041480Smckusick rs->sc_ioc.c_cmd = bp->b_flags & B_READ ? C_READ : C_WRITE; 59141480Smckusick #ifdef DEBUG 59241480Smckusick if (rddebug & RDB_IO) 59341480Smckusick printf("rdstart: hpibsend(%x, %x, %x, %x, %x)\n", 59441480Smckusick hp->hp_ctlr, hp->hp_slave, C_CMD, 59541480Smckusick &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2); 59641480Smckusick #endif 59741480Smckusick if (hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, &rs->sc_ioc.c_unit, 59841480Smckusick sizeof(rs->sc_ioc)-2) == sizeof(rs->sc_ioc)-2) { 59941480Smckusick if (hp->hp_dk >= 0) { 60041480Smckusick dk_busy |= 1 << hp->hp_dk; 60141480Smckusick dk_seek[hp->hp_dk]++; 60241480Smckusick } 60341480Smckusick #ifdef DEBUG 60441480Smckusick if (rddebug & RDB_IO) 60541480Smckusick printf("rdstart: hpibawait(%x)\n", hp->hp_ctlr); 60641480Smckusick #endif 60741480Smckusick hpibawait(hp->hp_ctlr); 60841480Smckusick return; 60941480Smckusick } 61041480Smckusick /* 61141480Smckusick * Experience has shown that the hpibwait in this hpibsend will 61241480Smckusick * occasionally timeout. It appears to occur mostly on old 7914 61341480Smckusick * drives with full maintenance tracks. We should probably 61441480Smckusick * integrate this with the backoff code in rderror. 61541480Smckusick */ 61641480Smckusick #ifdef DEBUG 61741480Smckusick if (rddebug & RDB_ERROR) 61841480Smckusick printf("rd%d: rdstart: cmd %x adr %d blk %d len %d ecnt %d\n", 61941480Smckusick unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, 62041480Smckusick bp->b_blkno, rs->sc_resid, rdtab[unit].b_errcnt); 62141480Smckusick rdstats[unit].rdretries++; 62241480Smckusick #endif 62341480Smckusick rs->sc_flags &= ~RDF_SEEK; 62441480Smckusick rdreset(rs, hp); 62541480Smckusick if (rdtab[unit].b_errcnt++ < RDRETRY) 62641480Smckusick goto again; 62741480Smckusick printf("rd%d: rdstart err: cmd 0x%x sect %d blk %d len %d\n", 62841480Smckusick unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, 62941480Smckusick bp->b_blkno, rs->sc_resid); 63041480Smckusick bp->b_flags |= B_ERROR; 63141480Smckusick bp->b_error = EIO; 63257327Shibler bp = rdfinish(unit, rs, bp); 63357327Shibler if (bp) { 63457327Shibler rs->sc_addr = bp->b_un.b_addr; 63557327Shibler rs->sc_resid = bp->b_bcount; 63657327Shibler if (hpibreq(&rs->sc_dq)) 63757327Shibler goto again; 63841480Smckusick } 63941480Smckusick } 64041480Smckusick 64141480Smckusick rdgo(unit) 64241480Smckusick register int unit; 64341480Smckusick { 64441480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 64541480Smckusick register struct hp_device *hp = rs->sc_hd; 64641480Smckusick struct buf *bp = rdtab[unit].b_actf; 64741480Smckusick 64841480Smckusick if (hp->hp_dk >= 0) { 64941480Smckusick dk_busy |= 1 << hp->hp_dk; 65041480Smckusick dk_xfer[hp->hp_dk]++; 65141480Smckusick dk_wds[hp->hp_dk] += rs->sc_resid >> 6; 65241480Smckusick } 65357327Shibler #ifdef USELEDS 65457327Shibler if (inledcontrol == 0) 65557327Shibler ledcontrol(0, 0, LED_DISK); 65657327Shibler #endif 65741480Smckusick hpibgo(hp->hp_ctlr, hp->hp_slave, C_EXEC, 65841480Smckusick rs->sc_addr, rs->sc_resid, bp->b_flags & B_READ); 65941480Smckusick } 66041480Smckusick 66141480Smckusick rdintr(unit) 66241480Smckusick register int unit; 66341480Smckusick { 66441480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 66541480Smckusick register struct buf *bp = rdtab[unit].b_actf; 66641480Smckusick register struct hp_device *hp = rs->sc_hd; 66741480Smckusick u_char stat = 13; /* in case hpibrecv fails */ 66845750Smckusick int rv, restart; 66941480Smckusick 67041480Smckusick #ifdef DEBUG 67141480Smckusick if (rddebug & RDB_FOLLOW) 67241480Smckusick printf("rdintr(%d): bp %x, %c, flags %x\n", unit, bp, 67341480Smckusick (bp->b_flags & B_READ) ? 'R' : 'W', rs->sc_flags); 67441480Smckusick if (bp == NULL) { 67541480Smckusick printf("rd%d: bp == NULL\n", unit); 67641480Smckusick return; 67741480Smckusick } 67841480Smckusick #endif 67941480Smckusick if (hp->hp_dk >= 0) 68041480Smckusick dk_busy &= ~(1 << hp->hp_dk); 68141480Smckusick if (rs->sc_flags & RDF_SEEK) { 68241480Smckusick rs->sc_flags &= ~RDF_SEEK; 68341480Smckusick if (hpibustart(hp->hp_ctlr)) 68441480Smckusick rdgo(unit); 68541480Smckusick return; 68641480Smckusick } 68741480Smckusick if ((rs->sc_flags & RDF_SWAIT) == 0) { 68841480Smckusick #ifdef DEBUG 68941480Smckusick rdstats[unit].rdpolltries++; 69041480Smckusick #endif 69141480Smckusick if (hpibpptest(hp->hp_ctlr, hp->hp_slave) == 0) { 69241480Smckusick #ifdef DEBUG 69341480Smckusick rdstats[unit].rdpollwaits++; 69441480Smckusick #endif 69541480Smckusick if (hp->hp_dk >= 0) 69641480Smckusick dk_busy |= 1 << hp->hp_dk; 69741480Smckusick rs->sc_flags |= RDF_SWAIT; 69841480Smckusick hpibawait(hp->hp_ctlr); 69941480Smckusick return; 70041480Smckusick } 70141480Smckusick } else 70241480Smckusick rs->sc_flags &= ~RDF_SWAIT; 70345750Smckusick rv = hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1); 70445750Smckusick if (rv != 1 || stat) { 70541480Smckusick #ifdef DEBUG 70641480Smckusick if (rddebug & RDB_ERROR) 70741480Smckusick printf("rdintr: recv failed or bad stat %d\n", stat); 70841480Smckusick #endif 70941480Smckusick restart = rderror(unit); 71041480Smckusick #ifdef DEBUG 71141480Smckusick rdstats[unit].rdretries++; 71241480Smckusick #endif 71341480Smckusick if (rdtab[unit].b_errcnt++ < RDRETRY) { 71441480Smckusick if (restart) 71541480Smckusick rdstart(unit); 71641480Smckusick return; 71741480Smckusick } 71841480Smckusick bp->b_flags |= B_ERROR; 71941480Smckusick bp->b_error = EIO; 72041480Smckusick } 72157327Shibler if (rdfinish(unit, rs, bp)) 72241480Smckusick rdustart(unit); 72341480Smckusick } 72441480Smckusick 72541480Smckusick rdstatus(rs) 72641480Smckusick register struct rd_softc *rs; 72741480Smckusick { 72841480Smckusick register int c, s; 72941480Smckusick u_char stat; 73041480Smckusick int rv; 73141480Smckusick 73241480Smckusick c = rs->sc_hd->hp_ctlr; 73341480Smckusick s = rs->sc_hd->hp_slave; 73441480Smckusick rs->sc_rsc.c_unit = C_SUNIT(rs->sc_punit); 73541480Smckusick rs->sc_rsc.c_sram = C_SRAM; 73641480Smckusick rs->sc_rsc.c_ram = C_RAM; 73741480Smckusick rs->sc_rsc.c_cmd = C_STATUS; 73841480Smckusick bzero((caddr_t)&rs->sc_stat, sizeof(rs->sc_stat)); 73941480Smckusick rv = hpibsend(c, s, C_CMD, &rs->sc_rsc, sizeof(rs->sc_rsc)); 74041480Smckusick if (rv != sizeof(rs->sc_rsc)) { 74141480Smckusick #ifdef DEBUG 74241480Smckusick if (rddebug & RDB_STATUS) 74341480Smckusick printf("rdstatus: send C_CMD failed %d != %d\n", 74441480Smckusick rv, sizeof(rs->sc_rsc)); 74541480Smckusick #endif 74641480Smckusick return(1); 74741480Smckusick } 74841480Smckusick rv = hpibrecv(c, s, C_EXEC, &rs->sc_stat, sizeof(rs->sc_stat)); 74941480Smckusick if (rv != sizeof(rs->sc_stat)) { 75041480Smckusick #ifdef DEBUG 75141480Smckusick if (rddebug & RDB_STATUS) 75241480Smckusick printf("rdstatus: send C_EXEC failed %d != %d\n", 75341480Smckusick rv, sizeof(rs->sc_stat)); 75441480Smckusick #endif 75541480Smckusick return(1); 75641480Smckusick } 75741480Smckusick rv = hpibrecv(c, s, C_QSTAT, &stat, 1); 75841480Smckusick if (rv != 1 || stat) { 75941480Smckusick #ifdef DEBUG 76041480Smckusick if (rddebug & RDB_STATUS) 76141480Smckusick printf("rdstatus: recv failed %d or bad stat %d\n", 76241480Smckusick rv, stat); 76341480Smckusick #endif 76441480Smckusick return(1); 76541480Smckusick } 76641480Smckusick return(0); 76741480Smckusick } 76841480Smckusick 76941480Smckusick /* 77041480Smckusick * Deal with errors. 77141480Smckusick * Returns 1 if request should be restarted, 77241480Smckusick * 0 if we should just quietly give up. 77341480Smckusick */ 77441480Smckusick rderror(unit) 77541480Smckusick int unit; 77641480Smckusick { 77741480Smckusick struct rd_softc *rs = &rd_softc[unit]; 77841480Smckusick register struct rd_stat *sp; 77941480Smckusick struct buf *bp; 78042361Smckusick daddr_t hwbn, pbn; 78141480Smckusick 78241480Smckusick if (rdstatus(rs)) { 78341480Smckusick #ifdef DEBUG 78441480Smckusick printf("rd%d: couldn't get status\n", unit); 78541480Smckusick #endif 78641480Smckusick rdreset(rs, rs->sc_hd); 78741480Smckusick return(1); 78841480Smckusick } 78941480Smckusick sp = &rs->sc_stat; 79041480Smckusick if (sp->c_fef & FEF_REXMT) 79141480Smckusick return(1); 79241480Smckusick if (sp->c_fef & FEF_PF) { 79341480Smckusick rdreset(rs, rs->sc_hd); 79441480Smckusick return(1); 79541480Smckusick } 79641480Smckusick /* 79741480Smckusick * Unit requests release for internal maintenance. 79841480Smckusick * We just delay awhile and try again later. Use expontially 79941480Smckusick * increasing backoff ala ethernet drivers since we don't really 80041480Smckusick * know how long the maintenance will take. With RDWAITC and 80141480Smckusick * RDRETRY as defined, the range is 1 to 32 seconds. 80241480Smckusick */ 80341480Smckusick if (sp->c_fef & FEF_IMR) { 80441480Smckusick extern int hz; 80541480Smckusick int rdtimo = RDWAITC << rdtab[unit].b_errcnt; 80641480Smckusick #ifdef DEBUG 80741480Smckusick printf("rd%d: internal maintenance, %d second timeout\n", 80841480Smckusick unit, rdtimo); 80941480Smckusick rdstats[unit].rdtimeouts++; 81041480Smckusick #endif 81141480Smckusick hpibfree(&rs->sc_dq); 81254770Storek timeout(rdrestart, (void *)unit, rdtimo * hz); 81341480Smckusick return(0); 81441480Smckusick } 81541480Smckusick /* 81642361Smckusick * Only report error if we have reached the error reporting 81742361Smckusick * threshhold. By default, this will only report after the 81842361Smckusick * retry limit has been exceeded. 81942361Smckusick */ 82042361Smckusick if (rdtab[unit].b_errcnt < rderrthresh) 82142361Smckusick return(1); 82242361Smckusick 82342361Smckusick /* 82441480Smckusick * First conjure up the block number at which the error occured. 82541480Smckusick * Note that not all errors report a block number, in that case 82641480Smckusick * we just use b_blkno. 82741480Smckusick */ 82842361Smckusick bp = rdtab[unit].b_actf; 82957327Shibler pbn = rs->sc_info.ri_label.d_partitions[rdpart(bp->b_dev)].p_offset; 83041480Smckusick if ((sp->c_fef & FEF_CU) || (sp->c_fef & FEF_DR) || 83141480Smckusick (sp->c_ief & IEF_RRMASK)) { 83242361Smckusick hwbn = RDBTOS(pbn + bp->b_blkno); 83341480Smckusick pbn = bp->b_blkno; 83441480Smckusick } else { 83542361Smckusick hwbn = sp->c_blk; 83642361Smckusick pbn = RDSTOB(hwbn) - pbn; 83741480Smckusick } 83841480Smckusick /* 83941480Smckusick * Now output a generic message suitable for badsect. 84041480Smckusick * Note that we don't use harderr cuz it just prints 84141480Smckusick * out b_blkno which is just the beginning block number 84241480Smckusick * of the transfer, not necessary where the error occured. 84341480Smckusick */ 84441480Smckusick printf("rd%d%c: hard error sn%d\n", 84541480Smckusick rdunit(bp->b_dev), 'a'+rdpart(bp->b_dev), pbn); 84641480Smckusick /* 84741480Smckusick * Now report the status as returned by the hardware with 84841480Smckusick * attempt at interpretation (unless debugging). 84941480Smckusick */ 85041480Smckusick printf("rd%d %s error:", 85141480Smckusick unit, (bp->b_flags & B_READ) ? "read" : "write"); 85241480Smckusick #ifdef DEBUG 85341480Smckusick if (rddebug & RDB_ERROR) { 85441480Smckusick /* status info */ 85541480Smckusick printf("\n volume: %d, unit: %d\n", 85641480Smckusick (sp->c_vu>>4)&0xF, sp->c_vu&0xF); 85741480Smckusick rdprinterr("reject", sp->c_ref, err_reject); 85841480Smckusick rdprinterr("fault", sp->c_fef, err_fault); 85941480Smckusick rdprinterr("access", sp->c_aef, err_access); 86041480Smckusick rdprinterr("info", sp->c_ief, err_info); 86142361Smckusick printf(" block: %d, P1-P10: ", hwbn); 86241480Smckusick printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8)); 86341480Smckusick printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8)); 86441480Smckusick printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4)); 86541480Smckusick /* command */ 86641480Smckusick printf(" ioc: "); 86741480Smckusick printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_pad, 8)); 86841480Smckusick printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_hiaddr, 4)); 86941480Smckusick printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_addr, 8)); 87041480Smckusick printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_nop2, 4)); 87141480Smckusick printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_len, 8)); 87241480Smckusick printf("%s\n", hexstr(*(u_short *)&rs->sc_ioc.c_cmd, 4)); 87341480Smckusick return(1); 87441480Smckusick } 87541480Smckusick #endif 87641480Smckusick printf(" v%d u%d, R0x%x F0x%x A0x%x I0x%x\n", 87741480Smckusick (sp->c_vu>>4)&0xF, sp->c_vu&0xF, 87841480Smckusick sp->c_ref, sp->c_fef, sp->c_aef, sp->c_ief); 87941480Smckusick printf("P1-P10: "); 88041480Smckusick printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8)); 88141480Smckusick printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8)); 88241480Smckusick printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4)); 88341480Smckusick return(1); 88441480Smckusick } 88541480Smckusick 88649303Shibler int 88749303Shibler rdread(dev, uio, flags) 88841480Smckusick dev_t dev; 88941480Smckusick struct uio *uio; 89049303Shibler int flags; 89141480Smckusick { 89241480Smckusick 89349303Shibler return (physio(rdstrategy, NULL, dev, B_READ, minphys, uio)); 89441480Smckusick } 89541480Smckusick 89649303Shibler int 89749303Shibler rdwrite(dev, uio, flags) 89841480Smckusick dev_t dev; 89941480Smckusick struct uio *uio; 90049303Shibler int flags; 90141480Smckusick { 90241480Smckusick 90349303Shibler return (physio(rdstrategy, NULL, dev, B_WRITE, minphys, uio)); 90441480Smckusick } 90541480Smckusick 90649303Shibler int 90749303Shibler rdioctl(dev, cmd, data, flag, p) 90841480Smckusick dev_t dev; 90941480Smckusick int cmd; 91041480Smckusick caddr_t data; 91141480Smckusick int flag; 91249303Shibler struct proc *p; 91341480Smckusick { 91457327Shibler int unit = rdunit(dev); 91557327Shibler register struct rd_softc *sc = &rd_softc[unit]; 91657327Shibler register struct disklabel *lp = &sc->sc_info.ri_label; 91757327Shibler int error, flags; 91857327Shibler 91957327Shibler switch (cmd) { 92057327Shibler case DIOCGDINFO: 92157327Shibler *(struct disklabel *)data = *lp; 92257327Shibler return (0); 92357327Shibler 92457327Shibler case DIOCGPART: 92557327Shibler ((struct partinfo *)data)->disklab = lp; 92657327Shibler ((struct partinfo *)data)->part = 92757327Shibler &lp->d_partitions[rdpart(dev)]; 92857327Shibler return (0); 92957327Shibler 93057327Shibler case DIOCWLABEL: 93157327Shibler if ((flag & FWRITE) == 0) 93257327Shibler return (EBADF); 93357327Shibler if (*(int *)data) 93457327Shibler sc->sc_flags |= RDF_WLABEL; 93557327Shibler else 93657327Shibler sc->sc_flags &= ~RDF_WLABEL; 93757327Shibler return (0); 93857327Shibler 93957327Shibler case DIOCSDINFO: 94057327Shibler if ((flag & FWRITE) == 0) 94157327Shibler return (EBADF); 94257327Shibler return (setdisklabel(lp, (struct disklabel *)data, 94357327Shibler (sc->sc_flags & RDF_WLABEL) ? 0 94457327Shibler : sc->sc_info.ri_open)); 94557327Shibler 94657327Shibler case DIOCWDINFO: 94757327Shibler if ((flag & FWRITE) == 0) 94857327Shibler return (EBADF); 94957327Shibler error = setdisklabel(lp, (struct disklabel *)data, 95057327Shibler (sc->sc_flags & RDF_WLABEL) ? 0 95157327Shibler : sc->sc_info.ri_open); 95257327Shibler if (error) 95357327Shibler return (error); 95457327Shibler flags = sc->sc_flags; 95557327Shibler sc->sc_flags = RDF_ALIVE | RDF_WLABEL; 95657327Shibler error = writedisklabel(rdlabdev(dev), rdstrategy, lp); 95757327Shibler sc->sc_flags = flags; 95857327Shibler return (error); 95957327Shibler } 96041480Smckusick return(EINVAL); 96141480Smckusick } 96241480Smckusick 96349303Shibler int 96441480Smckusick rdsize(dev) 96541480Smckusick dev_t dev; 96641480Smckusick { 96741480Smckusick register int unit = rdunit(dev); 96841480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 96957327Shibler int psize, didopen = 0; 97041480Smckusick 97141480Smckusick if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) 97241480Smckusick return(-1); 97357327Shibler 97457327Shibler /* 97557327Shibler * We get called very early on (via swapconf) 97657327Shibler * without the device being open so we may need 97757327Shibler * to handle it here. 97857327Shibler */ 97957327Shibler if (rs->sc_info.ri_open == 0) { 98057327Shibler if (rdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) 98157327Shibler return(-1); 98257327Shibler didopen = 1; 98357327Shibler } 98457327Shibler psize = rs->sc_info.ri_label.d_partitions[rdpart(dev)].p_size; 98557327Shibler if (didopen) 98657327Shibler (void) rdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); 98757327Shibler return (psize); 98841480Smckusick } 98941480Smckusick 99041480Smckusick #ifdef DEBUG 99141480Smckusick rdprinterr(str, err, tab) 99241480Smckusick char *str; 99341480Smckusick short err; 99441480Smckusick char *tab[]; 99541480Smckusick { 99641480Smckusick register int i; 99741480Smckusick int printed; 99841480Smckusick 99941480Smckusick if (err == 0) 100041480Smckusick return; 100141480Smckusick printf(" %s error field:", str, err); 100241480Smckusick printed = 0; 100341480Smckusick for (i = 0; i < 16; i++) 100441480Smckusick if (err & (0x8000 >> i)) 100541480Smckusick printf("%s%s", printed++ ? " + " : " ", tab[i]); 100641480Smckusick printf("\n"); 100741480Smckusick } 100841480Smckusick #endif 100941480Smckusick 101041480Smckusick /* 101141480Smckusick * Non-interrupt driven, non-dma dump routine. 101241480Smckusick */ 101349303Shibler int 101441480Smckusick rddump(dev) 101541480Smckusick dev_t dev; 101641480Smckusick { 101741480Smckusick int part = rdpart(dev); 101841480Smckusick int unit = rdunit(dev); 101941480Smckusick register struct rd_softc *rs = &rd_softc[unit]; 102041480Smckusick register struct hp_device *hp = rs->sc_hd; 102157327Shibler register struct partition *pinfo; 102241480Smckusick register daddr_t baddr; 102345750Smckusick register int maddr, pages, i; 102441480Smckusick char stat; 102541480Smckusick extern int lowram, dumpsize; 102645750Smckusick #ifdef DEBUG 102745750Smckusick extern int pmapdebug; 102845750Smckusick pmapdebug = 0; 102945750Smckusick #endif 103041480Smckusick 103141480Smckusick /* is drive ok? */ 103241480Smckusick if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) 103341480Smckusick return (ENXIO); 103457327Shibler pinfo = &rs->sc_info.ri_label.d_partitions[part]; 103557327Shibler /* dump parameters in range? */ 103657327Shibler if (dumplo < 0 || dumplo >= pinfo->p_size || 103757327Shibler pinfo->p_fstype != FS_SWAP) 103857327Shibler return (EINVAL); 103957327Shibler pages = dumpsize; 104057327Shibler if (dumplo + ctod(pages) > pinfo->p_size) 104157327Shibler pages = dtoc(pinfo->p_size - dumplo); 104257327Shibler maddr = lowram; 104357327Shibler baddr = dumplo + pinfo->p_offset; 104441480Smckusick /* HPIB idle? */ 104541480Smckusick if (!hpibreq(&rs->sc_dq)) { 104641480Smckusick hpibreset(hp->hp_ctlr); 104741480Smckusick rdreset(rs, rs->sc_hd); 104841480Smckusick printf("[ drive %d reset ] ", unit); 104941480Smckusick } 105041480Smckusick for (i = 0; i < pages; i++) { 105141480Smckusick #define NPGMB (1024*1024/NBPG) 105241480Smckusick /* print out how many Mbs we have dumped */ 105341480Smckusick if (i && (i % NPGMB) == 0) 105441480Smckusick printf("%d ", i / NPGMB); 105541480Smckusick #undef NPBMG 105641480Smckusick rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); 105741480Smckusick rs->sc_ioc.c_volume = C_SVOL(0); 105841480Smckusick rs->sc_ioc.c_saddr = C_SADDR; 105941480Smckusick rs->sc_ioc.c_hiaddr = 0; 106041480Smckusick rs->sc_ioc.c_addr = RDBTOS(baddr); 106141480Smckusick rs->sc_ioc.c_nop2 = C_NOP; 106241480Smckusick rs->sc_ioc.c_slen = C_SLEN; 106341480Smckusick rs->sc_ioc.c_len = NBPG; 106441480Smckusick rs->sc_ioc.c_cmd = C_WRITE; 106541480Smckusick hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, 106641480Smckusick &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2); 106757327Shibler if (hpibswait(hp->hp_ctlr, hp->hp_slave)) 106841480Smckusick return (EIO); 106952614Smckusick pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr, 107051576Smckusick VM_PROT_READ, TRUE); 107141480Smckusick hpibsend(hp->hp_ctlr, hp->hp_slave, C_EXEC, vmmap, NBPG); 107257327Shibler (void) hpibswait(hp->hp_ctlr, hp->hp_slave); 107341480Smckusick hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1); 107457327Shibler if (stat) 107541480Smckusick return (EIO); 107641480Smckusick maddr += NBPG; 107741480Smckusick baddr += ctod(1); 107841480Smckusick } 107941480Smckusick return (0); 108041480Smckusick } 108141480Smckusick #endif 1082