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*69452Smckusick * @(#)rd.c 8.5 (Berkeley) 05/14/95
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
39*69452Smckusick #include <vm/vm.h>
4045750Smckusick
4141480Smckusick int rdinit(), rdstart(), rdgo(), rdintr();
4257327Shibler void rdstrategy();
4341480Smckusick struct driver rddriver = {
4441480Smckusick rdinit, "rd", rdstart, rdgo, rdintr,
4541480Smckusick };
4641480Smckusick
4757327Shibler struct rd_softc rd_softc[NRD];
4857327Shibler struct buf rdtab[NRD];
4957327Shibler int rderrthresh = RDRETRY-1; /* when to start reporting errors */
5041480Smckusick
5141480Smckusick #ifdef DEBUG
5241480Smckusick /* error message tables */
5341480Smckusick char *err_reject[] = {
5441480Smckusick 0, 0,
5541480Smckusick "channel parity error", /* 0x2000 */
5641480Smckusick 0, 0,
5741480Smckusick "illegal opcode", /* 0x0400 */
5841480Smckusick "module addressing", /* 0x0200 */
5941480Smckusick "address bounds", /* 0x0100 */
6041480Smckusick "parameter bounds", /* 0x0080 */
6141480Smckusick "illegal parameter", /* 0x0040 */
6241480Smckusick "message sequence", /* 0x0020 */
6341480Smckusick 0,
6441480Smckusick "message length", /* 0x0008 */
6541480Smckusick 0, 0, 0
6641480Smckusick };
6741480Smckusick
6841480Smckusick char *err_fault[] = {
6941480Smckusick 0,
7041480Smckusick "cross unit", /* 0x4000 */
7141480Smckusick 0,
7241480Smckusick "controller fault", /* 0x1000 */
7341480Smckusick 0, 0,
7441480Smckusick "unit fault", /* 0x0200 */
7541480Smckusick 0,
7641480Smckusick "diagnostic result", /* 0x0080 */
7741480Smckusick 0,
7841480Smckusick "operator release request", /* 0x0020 */
7941480Smckusick "diagnostic release request", /* 0x0010 */
8041480Smckusick "internal maintenance release request", /* 0x0008 */
8141480Smckusick 0,
8241480Smckusick "power fail", /* 0x0002 */
8341480Smckusick "retransmit" /* 0x0001 */
8441480Smckusick };
8541480Smckusick
8641480Smckusick char *err_access[] = {
8741480Smckusick "illegal parallel operation", /* 0x8000 */
8841480Smckusick "uninitialized media", /* 0x4000 */
8941480Smckusick "no spares available", /* 0x2000 */
9041480Smckusick "not ready", /* 0x1000 */
9141480Smckusick "write protect", /* 0x0800 */
9241480Smckusick "no data found", /* 0x0400 */
9341480Smckusick 0, 0,
9441480Smckusick "unrecoverable data overflow", /* 0x0080 */
9541480Smckusick "unrecoverable data", /* 0x0040 */
9641480Smckusick 0,
9741480Smckusick "end of file", /* 0x0010 */
9841480Smckusick "end of volume", /* 0x0008 */
9941480Smckusick 0, 0, 0
10041480Smckusick };
10141480Smckusick
10241480Smckusick char *err_info[] = {
10341480Smckusick "operator release request", /* 0x8000 */
10441480Smckusick "diagnostic release request", /* 0x4000 */
10541480Smckusick "internal maintenance release request", /* 0x2000 */
10641480Smckusick "media wear", /* 0x1000 */
10741480Smckusick "latency induced", /* 0x0800 */
10841480Smckusick 0, 0,
10941480Smckusick "auto sparing invoked", /* 0x0100 */
11041480Smckusick 0,
11141480Smckusick "recoverable data overflow", /* 0x0040 */
11241480Smckusick "marginal data", /* 0x0020 */
11341480Smckusick "recoverable data", /* 0x0010 */
11441480Smckusick 0,
11541480Smckusick "maintenance track overflow", /* 0x0004 */
11641480Smckusick 0, 0
11741480Smckusick };
11857327Shibler
11957327Shibler struct rdstats rdstats[NRD];
12057327Shibler int rddebug = 0x80;
12157327Shibler #define RDB_FOLLOW 0x01
12257327Shibler #define RDB_STATUS 0x02
12357327Shibler #define RDB_IDENT 0x04
12457327Shibler #define RDB_IO 0x08
12557327Shibler #define RDB_ASYNC 0x10
12657327Shibler #define RDB_ERROR 0x80
12741480Smckusick #endif
12841480Smckusick
12941480Smckusick /*
13057327Shibler * Misc. HW description, indexed by sc_type.
13157327Shibler * Nothing really critical here, could do without it.
13241480Smckusick */
13357327Shibler struct rdidentinfo rdidentinfo[] = {
13457327Shibler { RD7946AID, 0, "7945A", 108416 },
13557327Shibler { RD9134DID, 1, "9134D", 29088 },
13657327Shibler { RD9134LID, 1, "9122S", 1232 },
13757327Shibler { RD7912PID, 0, "7912P", 128128 },
13857327Shibler { RD7914PID, 0, "7914P", 258048 },
13957327Shibler { RD7958AID, 0, "7958A", 255276 },
14057327Shibler { RD7957AID, 0, "7957A", 159544 },
14157327Shibler { RD7933HID, 0, "7933H", 789958 },
14257327Shibler { RD9134LID, 1, "9134L", 77840 },
14357327Shibler { RD7936HID, 0, "7936H", 600978 },
14457327Shibler { RD7937HID, 0, "7937H", 1116102 },
14557327Shibler { RD7914CTID, 0, "7914CT", 258048 },
14657327Shibler { RD7946AID, 0, "7946A", 108416 },
14757327Shibler { RD9134LID, 1, "9122D", 1232 },
14857327Shibler { RD7957BID, 0, "7957B", 159894 },
14957327Shibler { RD7958BID, 0, "7958B", 297108 },
15057327Shibler { RD7959BID, 0, "7959B", 594216 },
15157327Shibler { RD2200AID, 0, "2200A", 654948 },
15257327Shibler { RD2203AID, 0, "2203A", 1309896 }
15341480Smckusick };
15457327Shibler int numrdidentinfo = sizeof(rdidentinfo) / sizeof(rdidentinfo[0]);
15541480Smckusick
rdinit(hd)15641480Smckusick rdinit(hd)
15741480Smckusick register struct hp_device *hd;
15841480Smckusick {
15941480Smckusick register struct rd_softc *rs = &rd_softc[hd->hp_unit];
16041480Smckusick
16141480Smckusick rs->sc_hd = hd;
16241480Smckusick rs->sc_punit = rdpunit(hd->hp_flags);
16341480Smckusick rs->sc_type = rdident(rs, hd);
16441480Smckusick if (rs->sc_type < 0)
16541480Smckusick return(0);
16641480Smckusick rs->sc_dq.dq_ctlr = hd->hp_ctlr;
16741480Smckusick rs->sc_dq.dq_unit = hd->hp_unit;
16841480Smckusick rs->sc_dq.dq_slave = hd->hp_slave;
16941480Smckusick rs->sc_dq.dq_driver = &rddriver;
17041480Smckusick rs->sc_flags = RDF_ALIVE;
17142361Smckusick #ifdef DEBUG
17242361Smckusick /* always report errors */
17342361Smckusick if (rddebug & RDB_ERROR)
17442361Smckusick rderrthresh = 0;
17542361Smckusick #endif
17641480Smckusick return(1);
17741480Smckusick }
17841480Smckusick
17941480Smckusick rdident(rs, hd)
18041480Smckusick struct rd_softc *rs;
18141480Smckusick struct hp_device *hd;
18241480Smckusick {
18341480Smckusick struct rd_describe desc;
18441480Smckusick u_char stat, cmd[3];
18541480Smckusick int unit, lunit;
18641480Smckusick char name[7];
18741480Smckusick register int ctlr, slave, id, i;
18841480Smckusick
18941480Smckusick ctlr = hd->hp_ctlr;
19041480Smckusick slave = hd->hp_slave;
19141480Smckusick unit = rs->sc_punit;
19241480Smckusick lunit = hd->hp_unit;
19341480Smckusick
19441480Smckusick /*
19541480Smckusick * Grab device id and make sure:
19641480Smckusick * 1. It is a CS80 device.
19741480Smckusick * 2. It is one of the types we support.
19841480Smckusick * 3. If it is a 7946, we are accessing the disk unit (0)
19941480Smckusick */
20041480Smckusick id = hpibid(ctlr, slave);
20146681Smckusick #ifdef DEBUG
20246681Smckusick if (rddebug & RDB_IDENT)
20346681Smckusick printf("hpibid(%d, %d) -> %x\n", ctlr, slave, id);
20446681Smckusick #endif
20541480Smckusick if ((id & 0x200) == 0)
20641480Smckusick return(-1);
20757327Shibler for (i = 0; i < numrdidentinfo; i++)
20857327Shibler if (id == rdidentinfo[i].ri_hwid)
20941480Smckusick break;
21057327Shibler if (i == numrdidentinfo || unit > rdidentinfo[i].ri_maxunum)
21141480Smckusick return(-1);
21241480Smckusick id = i;
21341480Smckusick
21441480Smckusick /*
21541480Smckusick * Reset drive and collect device description.
21641480Smckusick * Don't really use the description info right now but
21741480Smckusick * might come in handy in the future (for disk labels).
21841480Smckusick */
21941480Smckusick rdreset(rs, hd);
22041480Smckusick cmd[0] = C_SUNIT(unit);
22141480Smckusick cmd[1] = C_SVOL(0);
22241480Smckusick cmd[2] = C_DESC;
22341480Smckusick hpibsend(ctlr, slave, C_CMD, cmd, sizeof(cmd));
22441480Smckusick hpibrecv(ctlr, slave, C_EXEC, &desc, 37);
22541480Smckusick hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
22641480Smckusick bzero(name, sizeof(name));
22741480Smckusick if (!stat) {
22841480Smckusick register int n = desc.d_name;
22941480Smckusick for (i = 5; i >= 0; i--) {
23041480Smckusick name[i] = (n & 0xf) + '0';
23141480Smckusick n >>= 4;
23241480Smckusick }
23342361Smckusick /* use drive characteristics to calculate xfer rate */
23442361Smckusick rs->sc_wpms = 1000000 * (desc.d_sectsize/2) / desc.d_blocktime;
23541480Smckusick }
23641480Smckusick #ifdef DEBUG
23741480Smckusick if (rddebug & RDB_IDENT) {
23841480Smckusick printf("rd%d: name: %x ('%s')\n",
23941480Smckusick lunit, desc.d_name, name);
24041480Smckusick printf(" iuw %x, maxxfr %d, ctype %d\n",
24141480Smckusick desc.d_iuw, desc.d_cmaxxfr, desc.d_ctype);
24241480Smckusick printf(" utype %d, bps %d, blkbuf %d, burst %d, blktime %d\n",
24341480Smckusick desc.d_utype, desc.d_sectsize,
24441480Smckusick desc.d_blkbuf, desc.d_burstsize, desc.d_blocktime);
24541480Smckusick printf(" avxfr %d, ort %d, atp %d, maxint %d, fv %x, rv %x\n",
24641480Smckusick desc.d_uavexfr, desc.d_retry, desc.d_access,
24741480Smckusick desc.d_maxint, desc.d_fvbyte, desc.d_rvbyte);
24841480Smckusick printf(" maxcyl/head/sect %d/%d/%d, maxvsect %d, inter %d\n",
24941480Smckusick desc.d_maxcyl, desc.d_maxhead, desc.d_maxsect,
25041480Smckusick desc.d_maxvsectl, desc.d_interleave);
25141480Smckusick }
25241480Smckusick #endif
25341480Smckusick /*
25441480Smckusick * Take care of a couple of anomolies:
25541480Smckusick * 1. 7945A and 7946A both return same HW id
25641480Smckusick * 2. 9122S and 9134D both return same HW id
25741480Smckusick * 3. 9122D and 9134L both return same HW id
25841480Smckusick */
25957327Shibler switch (rdidentinfo[id].ri_hwid) {
26041480Smckusick case RD7946AID:
26141480Smckusick if (bcmp(name, "079450", 6) == 0)
26241480Smckusick id = RD7945A;
26341480Smckusick else
26441480Smckusick id = RD7946A;
26541480Smckusick break;
26641480Smckusick
26741480Smckusick case RD9134LID:
26841480Smckusick if (bcmp(name, "091340", 6) == 0)
26941480Smckusick id = RD9134L;
27041480Smckusick else
27141480Smckusick id = RD9122D;
27241480Smckusick break;
27341480Smckusick
27441480Smckusick case RD9134DID:
27541480Smckusick if (bcmp(name, "091220", 6) == 0)
27641480Smckusick id = RD9122S;
27741480Smckusick else
27841480Smckusick id = RD9134D;
27941480Smckusick break;
28041480Smckusick }
28157327Shibler printf("rd%d: %s\n", lunit, rdidentinfo[id].ri_desc);
28241480Smckusick return(id);
28341480Smckusick }
28441480Smckusick
rdreset(rs,hd)28541480Smckusick rdreset(rs, hd)
28641480Smckusick register struct rd_softc *rs;
28741480Smckusick register struct hp_device *hd;
28841480Smckusick {
28941480Smckusick u_char stat;
29041480Smckusick
29141480Smckusick rs->sc_clear.c_unit = C_SUNIT(rs->sc_punit);
29241480Smckusick rs->sc_clear.c_cmd = C_CLEAR;
29341480Smckusick hpibsend(hd->hp_ctlr, hd->hp_slave, C_TCMD, &rs->sc_clear,
29441480Smckusick sizeof(rs->sc_clear));
29541480Smckusick hpibswait(hd->hp_ctlr, hd->hp_slave);
29641480Smckusick hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
29741480Smckusick rs->sc_src.c_unit = C_SUNIT(RDCTLR);
29841480Smckusick rs->sc_src.c_nop = C_NOP;
29941480Smckusick rs->sc_src.c_cmd = C_SREL;
30041480Smckusick rs->sc_src.c_param = C_REL;
30141480Smckusick hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_src,
30241480Smckusick sizeof(rs->sc_src));
30341480Smckusick hpibswait(hd->hp_ctlr, hd->hp_slave);
30441480Smckusick hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
30541480Smckusick rs->sc_ssmc.c_unit = C_SUNIT(rs->sc_punit);
30641480Smckusick rs->sc_ssmc.c_cmd = C_SSM;
30741480Smckusick rs->sc_ssmc.c_refm = REF_MASK;
30841480Smckusick rs->sc_ssmc.c_fefm = FEF_MASK;
30941480Smckusick rs->sc_ssmc.c_aefm = AEF_MASK;
31041480Smckusick rs->sc_ssmc.c_iefm = IEF_MASK;
31141480Smckusick hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_ssmc,
31241480Smckusick sizeof(rs->sc_ssmc));
31341480Smckusick hpibswait(hd->hp_ctlr, hd->hp_slave);
31441480Smckusick hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
31541480Smckusick #ifdef DEBUG
31641480Smckusick rdstats[hd->hp_unit].rdresets++;
31741480Smckusick #endif
31841480Smckusick }
31941480Smckusick
32057327Shibler /*
32157327Shibler * Read or constuct a disklabel
32257327Shibler */
32349303Shibler int
rdgetinfo(dev)32457327Shibler rdgetinfo(dev)
32557327Shibler dev_t dev;
32657327Shibler {
32757327Shibler int unit = rdunit(dev);
32857327Shibler register struct rd_softc *rs = &rd_softc[unit];
32957327Shibler register struct disklabel *lp = &rs->sc_info.ri_label;
33057327Shibler register struct partition *pi;
33157327Shibler char *msg, *readdisklabel();
33257327Shibler
33357327Shibler /*
33457327Shibler * Set some default values to use while reading the label
33557327Shibler * or to use if there isn't a label.
33657327Shibler */
33757327Shibler bzero((caddr_t)lp, sizeof *lp);
33857327Shibler lp->d_type = DTYPE_HPIB;
33957327Shibler lp->d_secsize = DEV_BSIZE;
34057327Shibler lp->d_nsectors = 32;
34157327Shibler lp->d_ntracks = 20;
34258054Shibler lp->d_ncylinders = 1;
34357327Shibler lp->d_secpercyl = 32*20;
34457327Shibler lp->d_npartitions = 3;
34557327Shibler lp->d_partitions[2].p_offset = 0;
34657327Shibler lp->d_partitions[2].p_size = LABELSECTOR+1;
34757327Shibler
34857327Shibler /*
34957327Shibler * Now try to read the disklabel
35057327Shibler */
35157327Shibler msg = readdisklabel(rdlabdev(dev), rdstrategy, lp);
35257327Shibler if (msg == NULL)
35357327Shibler return(0);
35457327Shibler
35557327Shibler pi = lp->d_partitions;
35657327Shibler printf("rd%d: WARNING: %s, ", unit, msg);
35757327Shibler #ifdef COMPAT_NOLABEL
35857327Shibler printf("using old default partitioning\n");
35957327Shibler rdmakedisklabel(unit, lp);
36057327Shibler #else
36157327Shibler printf("defining `c' partition as entire disk\n");
36257327Shibler pi[2].p_size = rdidentinfo[rs->sc_type].ri_nblocks;
36367184Shibler /* XXX reset other info since readdisklabel screws with it */
36467184Shibler lp->d_npartitions = 3;
36567184Shibler pi[0].p_size = 0;
36657327Shibler #endif
36757327Shibler return(0);
36857327Shibler }
36957327Shibler
37057327Shibler int
rdopen(dev,flags,mode,p)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
rdclose(dev,flag,mode,p)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
rdstrategy(bp)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
rdrestart(arg)51954770Storek rdrestart(arg)
52054770Storek void *arg;
52141480Smckusick {
52241480Smckusick int s = splbio();
52354770Storek rdustart((int)arg);
52441480Smckusick splx(s);
52541480Smckusick }
52641480Smckusick
rdustart(unit)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 *
rdfinish(unit,rs,bp)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
rdstart(unit)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
rdgo(unit)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
rdintr(unit)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
rdstatus(rs)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 */
rderror(unit)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
rdread(dev,uio,flags)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
rdwrite(dev,uio,flags)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
rdioctl(dev,cmd,data,flag,p)90449303Shibler rdioctl(dev, cmd, data, flag, p)
90541480Smckusick dev_t dev;
90668179Scgd u_long 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
rdsize(dev)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
rdprinterr(str,err,tab)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
rddump(dev)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