Annotation of sys/arch/hp300/dev/hd.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: hd.c,v 1.53 2007/06/21 20:23:07 miod Exp $ */
! 2: /* $NetBSD: rd.c,v 1.33 1997/07/10 18:14:08 kleink Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1996, 1997 Jason R. Thorpe. All rights reserved.
! 6: * Copyright (c) 1988 University of Utah.
! 7: * Copyright (c) 1982, 1990, 1993
! 8: * The Regents of the University of California. All rights reserved.
! 9: *
! 10: * This code is derived from software contributed to Berkeley by
! 11: * the Systems Programming Group of the University of Utah Computer
! 12: * Science Department.
! 13: *
! 14: * Redistribution and use in source and binary forms, with or without
! 15: * modification, are permitted provided that the following conditions
! 16: * are met:
! 17: * 1. Redistributions of source code must retain the above copyright
! 18: * notice, this list of conditions and the following disclaimer.
! 19: * 2. Redistributions in binary form must reproduce the above copyright
! 20: * notice, this list of conditions and the following disclaimer in the
! 21: * documentation and/or other materials provided with the distribution.
! 22: * 3. Neither the name of the University nor the names of its contributors
! 23: * may be used to endorse or promote products derived from this software
! 24: * without specific prior written permission.
! 25: *
! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 36: * SUCH DAMAGE.
! 37: *
! 38: * from: Utah $Hdr: rd.c 1.44 92/12/26$
! 39: *
! 40: * @(#)rd.c 8.2 (Berkeley) 5/19/94
! 41: */
! 42:
! 43: /*
! 44: * CS80/SS80 disk driver
! 45: */
! 46:
! 47: #include <sys/param.h>
! 48: #include <sys/systm.h>
! 49: #include <sys/buf.h>
! 50: #include <sys/conf.h>
! 51: #include <sys/device.h>
! 52: #include <sys/disk.h>
! 53: #include <sys/disklabel.h>
! 54: #include <sys/fcntl.h>
! 55: #include <sys/ioctl.h>
! 56: #include <sys/kernel.h>
! 57: #include <sys/proc.h>
! 58: #include <sys/stat.h>
! 59: #include <sys/syslog.h>
! 60:
! 61: #include <ufs/ffs/fs.h> /* for BBSIZE and SBSIZE */
! 62:
! 63: #include <hp300/dev/hpibvar.h>
! 64:
! 65: #include <hp300/dev/hdreg.h>
! 66: #include <hp300/dev/hdvar.h>
! 67:
! 68: #ifdef USELEDS
! 69: #include <hp300/hp300/leds.h>
! 70: #endif
! 71:
! 72: #ifndef HDRETRY
! 73: #define HDRETRY 5
! 74: #endif
! 75:
! 76: #ifndef HDWAITC
! 77: #define HDWAITC 1 /* min time for timeout in seconds */
! 78: #endif
! 79:
! 80: int hderrthresh = HDRETRY - 1; /* when to start reporting errors */
! 81:
! 82: #ifdef DEBUG
! 83: /* error message tables */
! 84: const char *err_reject[16] = {
! 85: NULL,
! 86: NULL,
! 87: "channel parity error", /* 0x2000 */
! 88: NULL,
! 89: NULL,
! 90: "illegal opcode", /* 0x0400 */
! 91: "module addressing", /* 0x0200 */
! 92: "address bounds", /* 0x0100 */
! 93: "parameter bounds", /* 0x0080 */
! 94: "illegal parameter", /* 0x0040 */
! 95: "message sequence", /* 0x0020 */
! 96: NULL,
! 97: "message length", /* 0x0008 */
! 98: NULL,
! 99: NULL,
! 100: NULL
! 101: };
! 102:
! 103: const char *err_fault[16] = {
! 104: NULL,
! 105: "cross unit", /* 0x4000 */
! 106: NULL,
! 107: "controller fault", /* 0x1000 */
! 108: NULL,
! 109: NULL,
! 110: "unit fault", /* 0x0200 */
! 111: NULL,
! 112: "diagnostic result", /* 0x0080 */
! 113: NULL,
! 114: "operator release request", /* 0x0020 */
! 115: "diagnostic release request", /* 0x0010 */
! 116: "internal maintenance release request", /* 0x0008 */
! 117: NULL,
! 118: "power fail", /* 0x0002 */
! 119: "retransmit" /* 0x0001 */
! 120: };
! 121:
! 122: const char *err_access[16] = {
! 123: "illegal parallel operation", /* 0x8000 */
! 124: "uninitialized media", /* 0x4000 */
! 125: "no spares available", /* 0x2000 */
! 126: "not ready", /* 0x1000 */
! 127: "write protect", /* 0x0800 */
! 128: "no data found", /* 0x0400 */
! 129: NULL,
! 130: NULL,
! 131: "unrecoverable data overflow", /* 0x0080 */
! 132: "unrecoverable data", /* 0x0040 */
! 133: NULL,
! 134: "end of file", /* 0x0010 */
! 135: "end of volume", /* 0x0008 */
! 136: NULL,
! 137: NULL,
! 138: NULL
! 139: };
! 140:
! 141: const char *err_info[16] = {
! 142: "operator release request", /* 0x8000 */
! 143: "diagnostic release request", /* 0x4000 */
! 144: "internal maintenance release request", /* 0x2000 */
! 145: "media wear", /* 0x1000 */
! 146: "latency induced", /* 0x0800 */
! 147: NULL,
! 148: NULL,
! 149: "auto sparing invoked", /* 0x0100 */
! 150: NULL,
! 151: "recoverable data overflow", /* 0x0040 */
! 152: "marginal data", /* 0x0020 */
! 153: "recoverable data", /* 0x0010 */
! 154: NULL,
! 155: "maintenance track overflow", /* 0x0004 */
! 156: NULL,
! 157: NULL
! 158: };
! 159:
! 160: #define HDB_FOLLOW 0x01
! 161: #define HDB_STATUS 0x02
! 162: #define HDB_IDENT 0x04
! 163: #define HDB_IO 0x08
! 164: #define HDB_ASYNC 0x10
! 165: #define HDB_ERROR 0x80
! 166: int hddebug = HDB_ERROR | HDB_IDENT;
! 167: #endif
! 168:
! 169: /*
! 170: * Misc. HW description, indexed by sc_type.
! 171: * Nothing really critical here, could do without it.
! 172: */
! 173: const struct hdidentinfo hdidentinfo[] = {
! 174: { HD7946AID, 0, "7945A", NHD7945ABPT,
! 175: NHD7945ATRK, 968, 108416 },
! 176:
! 177: { HD9134DID, 1, "9134D", NHD9134DBPT,
! 178: NHD9134DTRK, 303, 29088 },
! 179:
! 180: { HD9134LID, 1, "9122S", NHD9122SBPT,
! 181: NHD9122STRK, 77, 1232 },
! 182:
! 183: { HD7912PID, 0, "7912P", NHD7912PBPT,
! 184: NHD7912PTRK, 572, 128128 },
! 185:
! 186: { HD7914PID, 0, "7914P", NHD7914PBPT,
! 187: NHD7914PTRK, 1152, 258048 },
! 188:
! 189: { HD7958AID, 0, "7958A", NHD7958ABPT,
! 190: NHD7958ATRK, 1013, 255276 },
! 191:
! 192: { HD7957AID, 0, "7957A", NHD7957ABPT,
! 193: NHD7957ATRK, 1036, 159544 },
! 194:
! 195: { HD7933HID, 0, "7933H", NHD7933HBPT,
! 196: NHD7933HTRK, 1321, 789958 },
! 197:
! 198: { HD9134LID, 1, "9134L", NHD9134LBPT,
! 199: NHD9134LTRK, 973, 77840 },
! 200:
! 201: { HD7936HID, 0, "7936H", NHD7936HBPT,
! 202: NHD7936HTRK, 698, 600978 },
! 203:
! 204: { HD7937HID, 0, "7937H", NHD7937HBPT,
! 205: NHD7937HTRK, 698, 1116102 },
! 206:
! 207: { HD7914CTID, 0, "7914CT", NHD7914PBPT,
! 208: NHD7914PTRK, 1152, 258048 },
! 209:
! 210: { HD7946AID, 0, "7946A", NHD7945ABPT,
! 211: NHD7945ATRK, 968, 108416 },
! 212:
! 213: { HD9134LID, 1, "9122D", NHD9122SBPT,
! 214: NHD9122STRK, 77, 1232 },
! 215:
! 216: { HD7957BID, 0, "7957B", NHD7957BBPT,
! 217: NHD7957BTRK, 1269, 159894 },
! 218:
! 219: { HD7958BID, 0, "7958B", NHD7958BBPT,
! 220: NHD7958BTRK, 786, 297108 },
! 221:
! 222: { HD7959BID, 0, "7959B", NHD7959BBPT,
! 223: NHD7959BTRK, 1572, 594216 },
! 224:
! 225: { HD2200AID, 0, "2200A", NHD2200ABPT,
! 226: NHD2200ATRK, 1449, 654948 },
! 227:
! 228: { HD2203AID, 0, "2203A", NHD2203ABPT,
! 229: NHD2203ATRK, 1449, 1309896 }
! 230: };
! 231: const int numhdidentinfo = sizeof(hdidentinfo) / sizeof(hdidentinfo[0]);
! 232:
! 233: bdev_decl(hd);
! 234: cdev_decl(hd);
! 235:
! 236: int hdident(struct device *, struct hd_softc *,
! 237: struct hpibbus_attach_args *);
! 238: void hdreset(int, int, int);
! 239: void hdustart(struct hd_softc *);
! 240: void hdgetdisklabel(dev_t, struct hd_softc *, struct disklabel *, int);
! 241: void hdrestart(void *);
! 242: struct buf *hdfinish(struct hd_softc *, struct buf *);
! 243:
! 244: void hdstart(void *);
! 245: void hdinterrupt(void *);
! 246: void hdgo(void *);
! 247: int hdstatus(struct hd_softc *);
! 248: int hderror(int);
! 249: #ifdef DEBUG
! 250: void hdprinterr(const char *, short, const char **);
! 251: #endif
! 252:
! 253: int hdmatch(struct device *, void *, void *);
! 254: void hdattach(struct device *, struct device *, void *);
! 255:
! 256: struct cfattach hd_ca = {
! 257: sizeof(struct hd_softc), hdmatch, hdattach
! 258: };
! 259:
! 260: struct cfdriver hd_cd = {
! 261: NULL, "hd", DV_DISK
! 262: };
! 263:
! 264: #define hdlock(rs) disk_lock(&(rs)->sc_dkdev)
! 265: #define hdunlock(rs) disk_unlock(&(rs)->sc_dkdev)
! 266: #define hdlookup(unit) (struct hd_softc *)device_lookup(&hd_cd, (unit))
! 267:
! 268: int
! 269: hdmatch(parent, match, aux)
! 270: struct device *parent;
! 271: void *match, *aux;
! 272: {
! 273: struct hpibbus_attach_args *ha = aux;
! 274:
! 275: return (hdident(parent, NULL, ha));
! 276: }
! 277:
! 278: void
! 279: hdattach(parent, self, aux)
! 280: struct device *parent, *self;
! 281: void *aux;
! 282: {
! 283: struct hd_softc *sc = (struct hd_softc *)self;
! 284: struct hpibbus_attach_args *ha = aux;
! 285:
! 286: if (hdident(parent, sc, ha) == 0) {
! 287: printf("\n%s: didn't respond to describe command!\n",
! 288: sc->sc_dev.dv_xname);
! 289: return;
! 290: }
! 291:
! 292: /*
! 293: * Initialize and attach the disk structure.
! 294: */
! 295: bzero(&sc->sc_dkdev, sizeof(sc->sc_dkdev));
! 296: sc->sc_dkdev.dk_name = sc->sc_dev.dv_xname;
! 297: disk_attach(&sc->sc_dkdev);
! 298:
! 299: sc->sc_slave = ha->ha_slave;
! 300: sc->sc_punit = ha->ha_punit;
! 301:
! 302: /* Initialize the hpib job queue entry */
! 303: sc->sc_hq.hq_softc = sc;
! 304: sc->sc_hq.hq_slave = sc->sc_slave;
! 305: sc->sc_hq.hq_start = hdstart;
! 306: sc->sc_hq.hq_go = hdgo;
! 307: sc->sc_hq.hq_intr = hdinterrupt;
! 308:
! 309: #ifdef DEBUG
! 310: /* always report errors */
! 311: if (hddebug & HDB_ERROR)
! 312: hderrthresh = 0;
! 313: #endif
! 314:
! 315: /* Initialize timeout structure */
! 316: timeout_set(&sc->sc_timeout, hdrestart, sc);
! 317: }
! 318:
! 319: int
! 320: hdident(parent, sc, ha)
! 321: struct device *parent;
! 322: struct hd_softc *sc;
! 323: struct hpibbus_attach_args *ha;
! 324: {
! 325: struct cs80_describe desc;
! 326: u_char stat, cmd[3];
! 327: char name[7];
! 328: int i, id, n, ctlr, slave;
! 329:
! 330: ctlr = parent->dv_unit;
! 331: slave = ha->ha_slave;
! 332:
! 333: /* Verify that we have a CS80 device. */
! 334: if ((ha->ha_id & 0x200) == 0)
! 335: return (0);
! 336:
! 337: /* Is it one of the disks we support? */
! 338: for (id = 0; id < numhdidentinfo; id++)
! 339: if (ha->ha_id == hdidentinfo[id].ri_hwid &&
! 340: ha->ha_punit <= hdidentinfo[id].ri_maxunum)
! 341: break;
! 342: if (id == numhdidentinfo)
! 343: return (0);
! 344:
! 345: /*
! 346: * Reset device and collect description
! 347: */
! 348: bzero(&desc, sizeof(desc));
! 349: stat = 0;
! 350: hdreset(ctlr, slave, ha->ha_punit);
! 351: cmd[0] = C_SUNIT(ha->ha_punit);
! 352: cmd[1] = C_SVOL(0);
! 353: cmd[2] = C_DESC;
! 354: hpibsend(ctlr, slave, C_CMD, cmd, sizeof(cmd));
! 355: hpibrecv(ctlr, slave, C_EXEC, &desc, sizeof(desc));
! 356: hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
! 357:
! 358: if (desc.d_name == 0 && stat != 0)
! 359: return (0);
! 360:
! 361: /*
! 362: * If we're just probing for the device, that's all the
! 363: * work we need to do.
! 364: */
! 365: if (sc == NULL)
! 366: return (1);
! 367:
! 368: bzero(name, sizeof(name));
! 369: n = desc.d_name;
! 370: for (i = 5; i >= 0; i--) {
! 371: name[i] = (n & 0xf) + '0';
! 372: n >>= 4;
! 373: }
! 374:
! 375: #ifdef DEBUG
! 376: if (hddebug & HDB_IDENT) {
! 377: printf(": stat %d name: %x ('%s')\n", stat, desc.d_name, name);
! 378: printf(" iuw %x, maxxfr %d, ctype %d\n",
! 379: desc.d_iuw, desc.d_cmaxxfr, desc.d_ctype);
! 380: printf(" utype %d, bps %d, blkbuf %d, burst %d, blktime %d\n",
! 381: desc.d_utype, desc.d_sectsize,
! 382: desc.d_blkbuf, desc.d_burstsize, desc.d_blocktime);
! 383: printf(" avxfr %d, ort %d, atp %d, maxint %d, fv %x, rv %x\n",
! 384: desc.d_uavexfr, desc.d_retry, desc.d_access,
! 385: desc.d_maxint, desc.d_fvbyte, desc.d_rvbyte);
! 386: printf(" maxcyl/head/sect %d/%d/%d, maxvsect %d, inter %d\n",
! 387: desc.d_maxcyl, desc.d_maxhead, desc.d_maxsect,
! 388: desc.d_maxvsectl, desc.d_interleave);
! 389: printf("%s:", sc->sc_dev.dv_xname);
! 390: }
! 391: #endif
! 392:
! 393: /*
! 394: * Take care of a couple of anomalies:
! 395: * 1. 7945A and 7946A both return same HW id
! 396: * 2. 9122S and 9134D both return same HW id
! 397: * 3. 9122D and 9134L both return same HW id
! 398: */
! 399: switch (ha->ha_id) {
! 400: case HD7946AID:
! 401: if (bcmp(name, "079450", 6) == 0)
! 402: id = HD7945A;
! 403: else
! 404: id = HD7946A;
! 405: break;
! 406:
! 407: case HD9134LID:
! 408: if (bcmp(name, "091340", 6) == 0)
! 409: id = HD9134L;
! 410: else
! 411: id = HD9122D;
! 412: break;
! 413:
! 414: case HD9134DID:
! 415: if (bcmp(name, "091220", 6) == 0)
! 416: id = HD9122S;
! 417: else
! 418: id = HD9134D;
! 419: break;
! 420: }
! 421:
! 422: sc->sc_type = id;
! 423:
! 424: /*
! 425: * XXX We use DEV_BSIZE instead of the sector size value pulled
! 426: * XXX off the driver because all of this code assumes 512 byte
! 427: * XXX blocks. ICK!
! 428: */
! 429: printf(": %s\n", hdidentinfo[id].ri_desc);
! 430: printf("%s: %luMB, %lu cyl, %lu head, %lu sec, %lu bytes/sec, %lu sec total\n",
! 431: sc->sc_dev.dv_xname,
! 432: hdidentinfo[id].ri_nblocks / (1048576 / DEV_BSIZE),
! 433: hdidentinfo[id].ri_ncyl, hdidentinfo[id].ri_ntpc,
! 434: hdidentinfo[id].ri_nbpt, DEV_BSIZE, hdidentinfo[id].ri_nblocks);
! 435:
! 436: return (1);
! 437: }
! 438:
! 439: void
! 440: hdreset(ctlr, slave, punit)
! 441: int ctlr, slave, punit;
! 442: {
! 443: struct hd_ssmcmd ssmc;
! 444: struct hd_srcmd src;
! 445: struct hd_clearcmd clear;
! 446: u_char stat;
! 447:
! 448: bzero(&clear, sizeof(clear));
! 449: clear.c_unit = C_SUNIT(punit);
! 450: clear.c_cmd = C_CLEAR;
! 451: hpibsend(ctlr, slave, C_TCMD, &clear, sizeof(clear));
! 452: hpibswait(ctlr, slave);
! 453: hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
! 454:
! 455: bzero(&src, sizeof(src));
! 456: src.c_unit = C_SUNIT(HDCTLR);
! 457: src.c_nop = C_NOP;
! 458: src.c_cmd = C_SREL;
! 459: src.c_param = C_REL;
! 460: hpibsend(ctlr, slave, C_CMD, &src, sizeof(src));
! 461: hpibswait(ctlr, slave);
! 462: hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
! 463:
! 464: bzero(&ssmc, sizeof(ssmc));
! 465: ssmc.c_unit = C_SUNIT(punit);
! 466: ssmc.c_cmd = C_SSM;
! 467: ssmc.c_refm = REF_MASK;
! 468: ssmc.c_fefm = FEF_MASK;
! 469: ssmc.c_aefm = AEF_MASK;
! 470: ssmc.c_iefm = IEF_MASK;
! 471: hpibsend(ctlr, slave, C_CMD, &ssmc, sizeof(ssmc));
! 472: hpibswait(ctlr, slave);
! 473: hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
! 474: }
! 475:
! 476: /*
! 477: * Read or construct a disklabel
! 478: */
! 479: void
! 480: hdgetdisklabel(dev, rs, lp, spoofonly)
! 481: dev_t dev;
! 482: struct hd_softc *rs;
! 483: struct disklabel *lp;
! 484: int spoofonly;
! 485: {
! 486: char *errstring;
! 487:
! 488: bzero(lp, sizeof(struct disklabel));
! 489:
! 490: /*
! 491: * Create a default disk label based on geometry.
! 492: * This will get overridden if there is a real label on the disk.
! 493: */
! 494: lp->d_secsize = DEV_BSIZE;
! 495: lp->d_ntracks = hdidentinfo[rs->sc_type].ri_ntpc;
! 496: lp->d_nsectors = hdidentinfo[rs->sc_type].ri_nbpt;
! 497: lp->d_ncylinders = hdidentinfo[rs->sc_type].ri_ncyl;
! 498: lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
! 499: if (lp->d_secpercyl == 0) {
! 500: lp->d_secpercyl = 100;
! 501: /* as long as it's not 0 - readdisklabel divides by it */
! 502: }
! 503:
! 504: lp->d_type = DTYPE_HPIB;
! 505: strncpy(lp->d_typename, hdidentinfo[rs->sc_type].ri_desc,
! 506: sizeof(lp->d_typename));
! 507: strncpy(lp->d_packname, "fictitious", sizeof lp->d_packname);
! 508:
! 509: DL_SETDSIZE(lp, hdidentinfo[rs->sc_type].ri_nblocks);
! 510: lp->d_rpm = 3600;
! 511: lp->d_interleave = 1;
! 512: lp->d_flags = 0;
! 513: lp->d_version = 1;
! 514:
! 515: /* XXX - these values for BBSIZE and SBSIZE assume ffs */
! 516: lp->d_bbsize = BBSIZE;
! 517: lp->d_sbsize = SBSIZE;
! 518:
! 519: lp->d_magic = DISKMAGIC;
! 520: lp->d_magic2 = DISKMAGIC;
! 521: lp->d_checksum = dkcksum(lp);
! 522:
! 523: /*
! 524: * Now try to read the disklabel
! 525: */
! 526: errstring = readdisklabel(DISKLABELDEV(dev), hdstrategy, lp,
! 527: spoofonly);
! 528: if (errstring) {
! 529: /* printf("%s: %s\n", rs->sc_dev.dv_xname, errstring); */
! 530: return;
! 531: }
! 532: }
! 533:
! 534: int
! 535: hdopen(dev, flags, mode, p)
! 536: dev_t dev;
! 537: int flags, mode;
! 538: struct proc *p;
! 539: {
! 540: int unit = DISKUNIT(dev);
! 541: struct hd_softc *rs;
! 542: int mask, part;
! 543: int error;
! 544:
! 545: rs = hdlookup(unit);
! 546: if (rs == NULL)
! 547: return (ENXIO);
! 548:
! 549: if ((error = hdlock(rs)) != 0) {
! 550: device_unref(&rs->sc_dev);
! 551: return (error);
! 552: }
! 553:
! 554: /*
! 555: * On first open, get label and partition info.
! 556: * We may block reading the label, so be careful
! 557: * to stop any other opens.
! 558: */
! 559: if (rs->sc_dkdev.dk_openmask == 0) {
! 560: rs->sc_flags |= HDF_OPENING;
! 561: hdgetdisklabel(dev, rs, rs->sc_dkdev.dk_label, 0);
! 562: rs->sc_flags &= ~HDF_OPENING;
! 563: }
! 564:
! 565: part = DISKPART(dev);
! 566: mask = 1 << part;
! 567:
! 568: /* Check that the partition exists. */
! 569: if (part != RAW_PART &&
! 570: (part > rs->sc_dkdev.dk_label->d_npartitions ||
! 571: rs->sc_dkdev.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
! 572: error = ENXIO;
! 573: goto out;
! 574: }
! 575:
! 576: /* Ensure only one open at a time. */
! 577: switch (mode) {
! 578: case S_IFCHR:
! 579: rs->sc_dkdev.dk_copenmask |= mask;
! 580: break;
! 581: case S_IFBLK:
! 582: rs->sc_dkdev.dk_bopenmask |= mask;
! 583: break;
! 584: }
! 585: rs->sc_dkdev.dk_openmask =
! 586: rs->sc_dkdev.dk_copenmask | rs->sc_dkdev.dk_bopenmask;
! 587:
! 588: error = 0;
! 589: out:
! 590: hdunlock(rs);
! 591: device_unref(&rs->sc_dev);
! 592: return (error);
! 593: }
! 594:
! 595: int
! 596: hdclose(dev, flag, mode, p)
! 597: dev_t dev;
! 598: int flag, mode;
! 599: struct proc *p;
! 600: {
! 601: int unit = DISKUNIT(dev);
! 602: struct hd_softc *rs;
! 603: struct disk *dk;
! 604: int mask, s;
! 605: int error;
! 606:
! 607: rs = hdlookup(unit);
! 608: if (rs == NULL)
! 609: return (ENXIO);
! 610:
! 611: if ((error = hdlock(rs)) != 0) {
! 612: device_unref(&rs->sc_dev);
! 613: return (error);
! 614: }
! 615:
! 616: mask = 1 << DISKPART(dev);
! 617: dk = &rs->sc_dkdev;
! 618: switch (mode) {
! 619: case S_IFCHR:
! 620: dk->dk_copenmask &= ~mask;
! 621: break;
! 622: case S_IFBLK:
! 623: dk->dk_bopenmask &= ~mask;
! 624: break;
! 625: }
! 626: dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
! 627:
! 628: /*
! 629: * On last close, we wait for all activity to cease since
! 630: * the label/parition info will become invalid.
! 631: * Note we don't have to about other closes since we know
! 632: * we are the last one.
! 633: */
! 634: if (dk->dk_openmask == 0) {
! 635: rs->sc_flags |= HDF_CLOSING;
! 636: s = splbio();
! 637: while (rs->sc_tab.b_active) {
! 638: rs->sc_flags |= HDF_WANTED;
! 639: tsleep((caddr_t)&rs->sc_tab, PRIBIO, "hdclose", 0);
! 640: }
! 641: splx(s);
! 642: rs->sc_flags &= ~(HDF_CLOSING);
! 643: }
! 644:
! 645: hdunlock(rs);
! 646: device_unref(&rs->sc_dev);
! 647: return (0);
! 648: }
! 649:
! 650: void
! 651: hdstrategy(bp)
! 652: struct buf *bp;
! 653: {
! 654: int unit = DISKUNIT(bp->b_dev);
! 655: struct hd_softc *rs;
! 656: struct buf *dp;
! 657: struct disklabel *lp;
! 658: int s;
! 659:
! 660: rs = hdlookup(unit);
! 661: if (rs == NULL) {
! 662: bp->b_error = ENXIO;
! 663: goto bad;
! 664: }
! 665:
! 666: #ifdef DEBUG
! 667: if (hddebug & HDB_FOLLOW)
! 668: printf("hdstrategy(%x): dev %x, bn %x, bcount %lx, %c\n",
! 669: bp, bp->b_dev, bp->b_blkno, bp->b_bcount,
! 670: (bp->b_flags & B_READ) ? 'R' : 'W');
! 671: #endif
! 672:
! 673: lp = rs->sc_dkdev.dk_label;
! 674:
! 675: /*
! 676: * If it's a null transfer, return immediately
! 677: */
! 678: if (bp->b_bcount == 0)
! 679: goto done;
! 680:
! 681: /*
! 682: * The transfer must be a whole number of blocks.
! 683: */
! 684: if ((bp->b_bcount % lp->d_secsize) != 0) {
! 685: bp->b_error = EINVAL;
! 686: goto bad;
! 687: }
! 688:
! 689: /*
! 690: * Do bounds checking, adjust transfer. if error, process;
! 691: * If end of partition, just return.
! 692: */
! 693: if (bounds_check_with_label(bp, lp,
! 694: (rs->sc_flags & HDF_WLABEL) != 0) <= 0)
! 695: goto done;
! 696:
! 697: s = splbio();
! 698: dp = &rs->sc_tab;
! 699: disksort(dp, bp);
! 700: if (dp->b_active == 0) {
! 701: dp->b_active = 1;
! 702: hdustart(rs);
! 703: }
! 704: splx(s);
! 705:
! 706: device_unref(&rs->sc_dev);
! 707: return;
! 708: bad:
! 709: bp->b_flags |= B_ERROR;
! 710: done:
! 711: /*
! 712: * Correctly set the buf to indicate a completed xfer
! 713: */
! 714: bp->b_resid = bp->b_bcount;
! 715: s = splbio();
! 716: biodone(bp);
! 717: splx(s);
! 718: if (rs != NULL)
! 719: device_unref(&rs->sc_dev);
! 720: }
! 721:
! 722: /*
! 723: * Called via timeout(9) when handling maintenance releases
! 724: */
! 725: void
! 726: hdrestart(arg)
! 727: void *arg;
! 728: {
! 729: int s = splbio();
! 730: hdustart((struct hd_softc *)arg);
! 731: splx(s);
! 732: }
! 733:
! 734: void
! 735: hdustart(rs)
! 736: struct hd_softc *rs;
! 737: {
! 738: struct buf *bp;
! 739:
! 740: bp = rs->sc_tab.b_actf;
! 741: rs->sc_addr = bp->b_data;
! 742: rs->sc_resid = bp->b_bcount;
! 743: if (hpibreq(rs->sc_dev.dv_parent, &rs->sc_hq))
! 744: hdstart(rs);
! 745: }
! 746:
! 747: struct buf *
! 748: hdfinish(rs, bp)
! 749: struct hd_softc *rs;
! 750: struct buf *bp;
! 751: {
! 752: struct buf *dp = &rs->sc_tab;
! 753: int s;
! 754:
! 755: rs->sc_errcnt = 0;
! 756: dp->b_actf = bp->b_actf;
! 757: bp->b_resid = 0;
! 758: s = splbio();
! 759: biodone(bp);
! 760: splx(s);
! 761: hpibfree(rs->sc_dev.dv_parent, &rs->sc_hq);
! 762: if (dp->b_actf)
! 763: return (dp->b_actf);
! 764: dp->b_active = 0;
! 765: if (rs->sc_flags & HDF_WANTED) {
! 766: rs->sc_flags &= ~HDF_WANTED;
! 767: wakeup((caddr_t)dp);
! 768: }
! 769: return (NULL);
! 770: }
! 771:
! 772: void
! 773: hdstart(arg)
! 774: void *arg;
! 775: {
! 776: struct hd_softc *rs = arg;
! 777: struct disklabel *lp;
! 778: struct buf *bp = rs->sc_tab.b_actf;
! 779: int ctlr, slave;
! 780: daddr64_t bn;
! 781:
! 782: ctlr = rs->sc_dev.dv_parent->dv_unit;
! 783: slave = rs->sc_slave;
! 784:
! 785: again:
! 786: #ifdef DEBUG
! 787: if (hddebug & HDB_FOLLOW)
! 788: printf("hdstart(%s): bp %p, %c\n", rs->sc_dev.dv_xname, bp,
! 789: (bp->b_flags & B_READ) ? 'R' : 'W');
! 790: #endif
! 791: lp = rs->sc_dkdev.dk_label;
! 792: bn = bp->b_blkno +
! 793: DL_GETPOFFSET(&lp->d_partitions[DISKPART(bp->b_dev)]);
! 794:
! 795: rs->sc_flags |= HDF_SEEK;
! 796: rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit);
! 797: rs->sc_ioc.c_volume = C_SVOL(0);
! 798: rs->sc_ioc.c_saddr = C_SADDR;
! 799: rs->sc_ioc.c_hiaddr = 0;
! 800: rs->sc_ioc.c_addr = HDBTOS(bn);
! 801: rs->sc_ioc.c_nop2 = C_NOP;
! 802: rs->sc_ioc.c_slen = C_SLEN;
! 803: rs->sc_ioc.c_len = rs->sc_resid;
! 804: rs->sc_ioc.c_cmd = bp->b_flags & B_READ ? C_READ : C_WRITE;
! 805: #ifdef DEBUG
! 806: if (hddebug & HDB_IO)
! 807: printf("hdstart: hpibsend(%x, %x, %x, %p, %x)\n",
! 808: ctlr, slave, C_CMD,
! 809: &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2);
! 810: #endif
! 811: if (hpibsend(ctlr, slave, C_CMD, &rs->sc_ioc.c_unit,
! 812: sizeof(rs->sc_ioc)-2) == sizeof(rs->sc_ioc)-2) {
! 813:
! 814: /* Instrumentation. */
! 815: disk_busy(&rs->sc_dkdev);
! 816: rs->sc_dkdev.dk_seek++;
! 817:
! 818: #ifdef DEBUG
! 819: if (hddebug & HDB_IO)
! 820: printf("hdstart: hpibawait(%x)\n", ctlr);
! 821: #endif
! 822: hpibawait(ctlr);
! 823: return;
! 824: }
! 825: /*
! 826: * Experience has shown that the hpibwait in this hpibsend will
! 827: * occasionally timeout. It appears to occur mostly on old 7914
! 828: * drives with full maintenance tracks. We should probably
! 829: * integrate this with the backoff code in hderror.
! 830: */
! 831: #ifdef DEBUG
! 832: if (hddebug & HDB_ERROR)
! 833: printf("%s: hdstart: cmd %x adr %lx blk %d len %d ecnt %ld\n",
! 834: rs->sc_dev.dv_xname, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr,
! 835: bp->b_blkno, rs->sc_resid, rs->sc_errcnt);
! 836: rs->sc_stats.hdretries++;
! 837: #endif
! 838: rs->sc_flags &= ~HDF_SEEK;
! 839: hdreset(rs->sc_dev.dv_parent->dv_unit, rs->sc_slave, rs->sc_punit);
! 840: if (rs->sc_errcnt++ < HDRETRY)
! 841: goto again;
! 842: printf("%s: hdstart err: err: cmd 0x%x sect %ld blk %d len %d\n",
! 843: rs->sc_dev.dv_xname, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr,
! 844: bp->b_blkno, rs->sc_resid);
! 845: bp->b_flags |= B_ERROR;
! 846: bp->b_error = EIO;
! 847: bp = hdfinish(rs, bp);
! 848: if (bp) {
! 849: rs->sc_addr = bp->b_data;
! 850: rs->sc_resid = bp->b_bcount;
! 851: if (hpibreq(rs->sc_dev.dv_parent, &rs->sc_hq))
! 852: goto again;
! 853: }
! 854: }
! 855:
! 856: void
! 857: hdgo(arg)
! 858: void *arg;
! 859: {
! 860: struct hd_softc *rs = arg;
! 861: struct buf *bp = rs->sc_tab.b_actf;
! 862: int rw, ctlr, slave;
! 863:
! 864: ctlr = rs->sc_dev.dv_parent->dv_unit;
! 865: slave = rs->sc_slave;
! 866:
! 867: rw = bp->b_flags & B_READ;
! 868:
! 869: /* Instrumentation. */
! 870: disk_busy(&rs->sc_dkdev);
! 871:
! 872: #ifdef USELEDS
! 873: ledcontrol(0, 0, LED_DISK);
! 874: #endif
! 875: hpibgo(ctlr, slave, C_EXEC, rs->sc_addr, rs->sc_resid, rw, rw != 0);
! 876: }
! 877:
! 878: /* ARGSUSED */
! 879: void
! 880: hdinterrupt(arg)
! 881: void *arg;
! 882: {
! 883: struct hd_softc *rs = arg;
! 884: int unit = rs->sc_dev.dv_unit;
! 885: struct buf *bp = rs->sc_tab.b_actf;
! 886: u_char stat = 13; /* in case hpibrecv fails */
! 887: int rv, restart, ctlr, slave;
! 888:
! 889: ctlr = rs->sc_dev.dv_parent->dv_unit;
! 890: slave = rs->sc_slave;
! 891:
! 892: #ifdef DEBUG
! 893: if (hddebug & HDB_FOLLOW)
! 894: printf("hdinterrupt(%d): bp %p, %c, flags %x\n", unit, bp,
! 895: (bp->b_flags & B_READ) ? 'R' : 'W', rs->sc_flags);
! 896: if (bp == NULL) {
! 897: printf("%s: bp == NULL\n", rs->sc_dev.dv_xname);
! 898: return;
! 899: }
! 900: #endif
! 901: disk_unbusy(&rs->sc_dkdev, (bp->b_bcount - bp->b_resid),
! 902: (bp->b_flags & B_READ));
! 903:
! 904: if (rs->sc_flags & HDF_SEEK) {
! 905: rs->sc_flags &= ~HDF_SEEK;
! 906: if (hpibustart(ctlr))
! 907: hdgo(rs);
! 908: return;
! 909: }
! 910: if ((rs->sc_flags & HDF_SWAIT) == 0) {
! 911: #ifdef DEBUG
! 912: rs->sc_stats.hdpolltries++;
! 913: #endif
! 914: if (hpibpptest(ctlr, slave) == 0) {
! 915: #ifdef DEBUG
! 916: rs->sc_stats.hdpollwaits++;
! 917: #endif
! 918:
! 919: /* Instrumentation. */
! 920: disk_busy(&rs->sc_dkdev);
! 921: rs->sc_flags |= HDF_SWAIT;
! 922: hpibawait(ctlr);
! 923: return;
! 924: }
! 925: } else
! 926: rs->sc_flags &= ~HDF_SWAIT;
! 927: rv = hpibrecv(ctlr, slave, C_QSTAT, &stat, 1);
! 928: if (rv != 1 || stat) {
! 929: #ifdef DEBUG
! 930: if (hddebug & HDB_ERROR)
! 931: printf("hdinterrupt: recv failed or bad stat %d\n", stat);
! 932: #endif
! 933: restart = hderror(unit);
! 934: #ifdef DEBUG
! 935: rs->sc_stats.hdretries++;
! 936: #endif
! 937: if (rs->sc_errcnt++ < HDRETRY) {
! 938: if (restart)
! 939: hdstart(rs);
! 940: return;
! 941: }
! 942: bp->b_flags |= B_ERROR;
! 943: bp->b_error = EIO;
! 944: }
! 945: if (hdfinish(rs, bp))
! 946: hdustart(rs);
! 947: }
! 948:
! 949: int
! 950: hdstatus(rs)
! 951: struct hd_softc *rs;
! 952: {
! 953: int c, s;
! 954: u_char stat;
! 955: int rv;
! 956:
! 957: c = rs->sc_dev.dv_parent->dv_unit;
! 958: s = rs->sc_slave;
! 959: rs->sc_rsc.c_unit = C_SUNIT(rs->sc_punit);
! 960: rs->sc_rsc.c_sram = C_SRAM;
! 961: rs->sc_rsc.c_ram = C_RAM;
! 962: rs->sc_rsc.c_cmd = C_STATUS;
! 963: bzero((caddr_t)&rs->sc_stat, sizeof(rs->sc_stat));
! 964: rv = hpibsend(c, s, C_CMD, &rs->sc_rsc, sizeof(rs->sc_rsc));
! 965: if (rv != sizeof(rs->sc_rsc)) {
! 966: #ifdef DEBUG
! 967: if (hddebug & HDB_STATUS)
! 968: printf("hdstatus: send C_CMD failed %d != %d\n",
! 969: rv, sizeof(rs->sc_rsc));
! 970: #endif
! 971: return(1);
! 972: }
! 973: rv = hpibrecv(c, s, C_EXEC, &rs->sc_stat, sizeof(rs->sc_stat));
! 974: if (rv != sizeof(rs->sc_stat)) {
! 975: #ifdef DEBUG
! 976: if (hddebug & HDB_STATUS)
! 977: printf("hdstatus: send C_EXEC failed %d != %d\n",
! 978: rv, sizeof(rs->sc_stat));
! 979: #endif
! 980: return(1);
! 981: }
! 982: rv = hpibrecv(c, s, C_QSTAT, &stat, 1);
! 983: if (rv != 1 || stat) {
! 984: #ifdef DEBUG
! 985: if (hddebug & HDB_STATUS)
! 986: printf("hdstatus: recv failed %d or bad stat %d\n",
! 987: rv, stat);
! 988: #endif
! 989: return(1);
! 990: }
! 991: return(0);
! 992: }
! 993:
! 994: /*
! 995: * Deal with errors.
! 996: * Returns 1 if request should be restarted,
! 997: * 0 if we should just quietly give up.
! 998: */
! 999: int
! 1000: hderror(unit)
! 1001: int unit;
! 1002: {
! 1003: struct hd_softc *rs = hd_cd.cd_devs[unit];
! 1004: struct hd_stat *sp;
! 1005: struct buf *bp;
! 1006: daddr64_t hwbn, pbn;
! 1007:
! 1008: if (hdstatus(rs)) {
! 1009: #ifdef DEBUG
! 1010: printf("%s: couldn't get status\n", rs->sc_dev.dv_xname);
! 1011: #endif
! 1012: hdreset(rs->sc_dev.dv_parent->dv_unit,
! 1013: rs->sc_slave, rs->sc_punit);
! 1014: return(1);
! 1015: }
! 1016: sp = &rs->sc_stat;
! 1017: if (sp->c_fef & FEF_REXMT)
! 1018: return(1);
! 1019: if (sp->c_fef & FEF_PF) {
! 1020: hdreset(rs->sc_dev.dv_parent->dv_unit,
! 1021: rs->sc_slave, rs->sc_punit);
! 1022: return(1);
! 1023: }
! 1024: /*
! 1025: * Unit requests release for internal maintenance.
! 1026: * We just delay a while and try again later. Use exponentially
! 1027: * increasing backoff a la ethernet drivers since we don't really
! 1028: * know how long the maintenance will take. With HDWAITC and
! 1029: * HDRETRY as defined, the range is 1 to 32 seconds.
! 1030: */
! 1031: if (sp->c_fef & FEF_IMR) {
! 1032: int hdtimo = HDWAITC << rs->sc_errcnt;
! 1033: #ifdef DEBUG
! 1034: printf("%s: internal maintenance, %d second timeout\n",
! 1035: rs->sc_dev.dv_xname, hdtimo);
! 1036: rs->sc_stats.hdtimeouts++;
! 1037: #endif
! 1038: hpibfree(rs->sc_dev.dv_parent, &rs->sc_hq);
! 1039: timeout_add(&rs->sc_timeout, hdtimo * hz);
! 1040: return(0);
! 1041: }
! 1042: /*
! 1043: * Only report error if we have reached the error reporting
! 1044: * threshold. By default, this will only report after the
! 1045: * retry limit has been exceeded.
! 1046: */
! 1047: if (rs->sc_errcnt < hderrthresh)
! 1048: return(1);
! 1049:
! 1050: /*
! 1051: * First conjure up the block number at which the error occurred.
! 1052: * Note that not all errors report a block number, in that case
! 1053: * we just use b_blkno.
! 1054: */
! 1055: bp = rs->sc_tab.b_actf;
! 1056: pbn = DL_GETPOFFSET(&rs->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)]);
! 1057: if ((sp->c_fef & FEF_CU) || (sp->c_fef & FEF_DR) ||
! 1058: (sp->c_ief & IEF_RRMASK)) {
! 1059: hwbn = HDBTOS(pbn + bp->b_blkno);
! 1060: pbn = bp->b_blkno;
! 1061: } else {
! 1062: hwbn = sp->c_blk;
! 1063: pbn = HDSTOB(hwbn) - pbn;
! 1064: }
! 1065:
! 1066: diskerr(bp, hd_cd.cd_name, "hard error", LOG_PRINTF,
! 1067: pbn - bp->b_blkno, rs->sc_dkdev.dk_label);
! 1068: printf("\n%s%c: ", rs->sc_dev.dv_xname, 'a' + DISKPART(bp->b_dev));
! 1069:
! 1070: #ifdef DEBUG
! 1071: if (hddebug & HDB_ERROR) {
! 1072: /* status info */
! 1073: printf("volume: %d, unit: %d\n",
! 1074: (sp->c_vu>>4)&0xF, sp->c_vu&0xF);
! 1075: hdprinterr("reject", sp->c_ref, err_reject);
! 1076: hdprinterr("fault", sp->c_fef, err_fault);
! 1077: hdprinterr("access", sp->c_aef, err_access);
! 1078: hdprinterr("info", sp->c_ief, err_info);
! 1079: printf(" block: %d, P1-P10: ", hwbn);
! 1080: printf("0x%04x", *(u_int *)&sp->c_raw[0]);
! 1081: printf("%04x", *(u_int *)&sp->c_raw[4]);
! 1082: printf("%02x\n", *(u_short *)&sp->c_raw[8]);
! 1083: /* command */
! 1084: printf(" ioc: ");
! 1085: printf("0x%x", *(u_int *)&rs->sc_ioc.c_pad);
! 1086: printf("0x%x", *(u_short *)&rs->sc_ioc.c_hiaddr);
! 1087: printf("0x%x", *(u_int *)&rs->sc_ioc.c_addr);
! 1088: printf("0x%x", *(u_short *)&rs->sc_ioc.c_nop2);
! 1089: printf("0x%x", *(u_int *)&rs->sc_ioc.c_len);
! 1090: printf("0x%x\n", *(u_short *)&rs->sc_ioc.c_cmd);
! 1091: } else
! 1092: #endif
! 1093: {
! 1094: printf("v%d u%d, R0x%x F0x%x A0x%x I0x%x",
! 1095: (sp->c_vu>>4)&0xF, sp->c_vu&0xF,
! 1096: sp->c_ref, sp->c_fef, sp->c_aef, sp->c_ief);
! 1097: printf(" P1-P10: 0x%04x%04x%02x\n",
! 1098: *(u_int *)&sp->c_raw[0], *(u_int *)&sp->c_raw[4],
! 1099: *(u_short *)&sp->c_raw[8]);
! 1100: }
! 1101: return (1);
! 1102: }
! 1103:
! 1104: int
! 1105: hdread(dev, uio, flags)
! 1106: dev_t dev;
! 1107: struct uio *uio;
! 1108: int flags;
! 1109: {
! 1110:
! 1111: return (physio(hdstrategy, NULL, dev, B_READ, minphys, uio));
! 1112: }
! 1113:
! 1114: int
! 1115: hdwrite(dev, uio, flags)
! 1116: dev_t dev;
! 1117: struct uio *uio;
! 1118: int flags;
! 1119: {
! 1120:
! 1121: return (physio(hdstrategy, NULL, dev, B_WRITE, minphys, uio));
! 1122: }
! 1123:
! 1124: int
! 1125: hdioctl(dev, cmd, data, flag, p)
! 1126: dev_t dev;
! 1127: u_long cmd;
! 1128: caddr_t data;
! 1129: int flag;
! 1130: struct proc *p;
! 1131: {
! 1132: int unit = DISKUNIT(dev);
! 1133: struct hd_softc *sc;
! 1134: int error = 0;
! 1135:
! 1136: sc = hdlookup(unit);
! 1137: if (sc == NULL)
! 1138: return (ENXIO);
! 1139:
! 1140: switch (cmd) {
! 1141: case DIOCGPDINFO:
! 1142: hdgetdisklabel(dev, sc, (struct disklabel *)data, 1);
! 1143: goto exit;
! 1144:
! 1145: case DIOCGDINFO:
! 1146: *(struct disklabel *)data = *sc->sc_dkdev.dk_label;
! 1147: goto exit;
! 1148:
! 1149: case DIOCGPART:
! 1150: ((struct partinfo *)data)->disklab = sc->sc_dkdev.dk_label;
! 1151: ((struct partinfo *)data)->part =
! 1152: &sc->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
! 1153: goto exit;
! 1154:
! 1155: case DIOCWLABEL:
! 1156: if ((flag & FWRITE) == 0) {
! 1157: error = EBADF;
! 1158: goto exit;
! 1159: }
! 1160: if (*(int *)data)
! 1161: sc->sc_flags |= HDF_WLABEL;
! 1162: else
! 1163: sc->sc_flags &= ~HDF_WLABEL;
! 1164: goto exit;
! 1165:
! 1166: case DIOCWDINFO:
! 1167: case DIOCSDINFO:
! 1168: if ((flag & FWRITE) == 0) {
! 1169: error = EBADF;
! 1170: goto exit;
! 1171: }
! 1172:
! 1173: if ((error = hdlock(sc)) != 0)
! 1174: goto exit;
! 1175: sc->sc_flags |= HDF_WLABEL;
! 1176:
! 1177: error = setdisklabel(sc->sc_dkdev.dk_label,
! 1178: (struct disklabel *)data, /* sc->sc_dkdev.dk_openmask */ 0);
! 1179: if (error == 0) {
! 1180: if (cmd == DIOCWDINFO)
! 1181: error = writedisklabel(DISKLABELDEV(dev),
! 1182: hdstrategy, sc->sc_dkdev.dk_label);
! 1183: }
! 1184:
! 1185: sc->sc_flags &= ~HDF_WLABEL;
! 1186: hdunlock(sc);
! 1187: goto exit;
! 1188:
! 1189: default:
! 1190: error = EINVAL;
! 1191: break;
! 1192: }
! 1193:
! 1194: exit:
! 1195: device_unref(&sc->sc_dev);
! 1196: return (error);
! 1197: }
! 1198:
! 1199: daddr64_t
! 1200: hdsize(dev)
! 1201: dev_t dev;
! 1202: {
! 1203: struct hd_softc *rs;
! 1204: int unit = DISKUNIT(dev);
! 1205: int part, omask;
! 1206: int size;
! 1207:
! 1208: rs = hdlookup(unit);
! 1209: if (rs == NULL)
! 1210: return (-1);
! 1211:
! 1212: part = DISKPART(dev);
! 1213: omask = rs->sc_dkdev.dk_openmask & (1 << part);
! 1214:
! 1215: /*
! 1216: * We get called very early on (via swapconf)
! 1217: * without the device being open so we may need
! 1218: * to handle it here.
! 1219: */
! 1220: if (omask == 0 && hdopen(dev, FREAD | FWRITE, S_IFBLK, NULL) != 0) {
! 1221: size = -1;
! 1222: goto out;
! 1223: }
! 1224:
! 1225: if (rs->sc_dkdev.dk_label->d_partitions[part].p_fstype != FS_SWAP)
! 1226: size = -1;
! 1227: else
! 1228: size = DL_GETPSIZE(&rs->sc_dkdev.dk_label->d_partitions[part]) *
! 1229: (rs->sc_dkdev.dk_label->d_secsize / DEV_BSIZE);
! 1230:
! 1231: if (hdclose(dev, FREAD | FWRITE, S_IFBLK, NULL) != 0)
! 1232: size = -1;
! 1233:
! 1234: out:
! 1235: device_unref(&rs->sc_dev);
! 1236: return (size);
! 1237: }
! 1238:
! 1239: #ifdef DEBUG
! 1240: void
! 1241: hdprinterr(str, err, tab)
! 1242: const char *str;
! 1243: short err;
! 1244: const char **tab;
! 1245: {
! 1246: int i;
! 1247: int printed;
! 1248:
! 1249: if (err == 0)
! 1250: return;
! 1251: printf(" %s error %d field:", str, err);
! 1252: printed = 0;
! 1253: for (i = 0; i < 16; i++)
! 1254: if (err & (0x8000 >> i))
! 1255: printf("%s%s", printed++ ? " + " : " ", tab[i]);
! 1256: printf("\n");
! 1257: }
! 1258: #endif
! 1259:
! 1260: static int hddoingadump; /* simple mutex */
! 1261:
! 1262: /*
! 1263: * Non-interrupt driven, non-dma dump routine.
! 1264: */
! 1265: int
! 1266: hddump(dev, blkno, va, size)
! 1267: dev_t dev;
! 1268: daddr64_t blkno;
! 1269: caddr_t va;
! 1270: size_t size;
! 1271: {
! 1272: int sectorsize; /* size of a disk sector */
! 1273: daddr64_t nsects; /* number of sectors in partition */
! 1274: daddr64_t sectoff; /* sector offset of partition */
! 1275: int totwrt; /* total number of sectors left to write */
! 1276: int nwrt; /* current number of sectors to write */
! 1277: int unit, part;
! 1278: int ctlr, slave;
! 1279: struct hd_softc *rs;
! 1280: struct disklabel *lp;
! 1281: char stat;
! 1282:
! 1283: /* Check for recursive dump; if so, punt. */
! 1284: if (hddoingadump)
! 1285: return (EFAULT);
! 1286: hddoingadump = 1;
! 1287:
! 1288: /* Decompose unit and partition. */
! 1289: unit = DISKUNIT(dev);
! 1290: part = DISKPART(dev);
! 1291:
! 1292: /* Make sure dump device is ok. */
! 1293: rs = hdlookup(unit);
! 1294: if (rs == NULL)
! 1295: return (ENXIO);
! 1296: device_unref(&rs->sc_dev);
! 1297:
! 1298: ctlr = rs->sc_dev.dv_parent->dv_unit;
! 1299: slave = rs->sc_slave;
! 1300:
! 1301: /*
! 1302: * Convert to disk sectors. Request must be a multiple of size.
! 1303: */
! 1304: lp = rs->sc_dkdev.dk_label;
! 1305: sectorsize = lp->d_secsize;
! 1306: if ((size % sectorsize) != 0)
! 1307: return (EFAULT);
! 1308: totwrt = size / sectorsize;
! 1309: blkno = dbtob(blkno) / sectorsize; /* blkno in DEV_BSIZE units */
! 1310:
! 1311: nsects = DL_GETPSIZE(&lp->d_partitions[part]);
! 1312: sectoff = DL_GETPOFFSET(&lp->d_partitions[part]);
! 1313:
! 1314: /* Check transfer bounds against partition size. */
! 1315: if ((blkno < 0) || (blkno + totwrt) > nsects)
! 1316: return (EINVAL);
! 1317:
! 1318: /* Offset block number to start of partition. */
! 1319: blkno += sectoff;
! 1320:
! 1321: while (totwrt > 0) {
! 1322: nwrt = totwrt; /* XXX */
! 1323: #ifndef HD_DUMP_NOT_TRUSTED
! 1324: /*
! 1325: * Fill out and send HPIB command.
! 1326: */
! 1327: rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit);
! 1328: rs->sc_ioc.c_volume = C_SVOL(0);
! 1329: rs->sc_ioc.c_saddr = C_SADDR;
! 1330: rs->sc_ioc.c_hiaddr = 0;
! 1331: rs->sc_ioc.c_addr = HDBTOS(blkno);
! 1332: rs->sc_ioc.c_nop2 = C_NOP;
! 1333: rs->sc_ioc.c_slen = C_SLEN;
! 1334: rs->sc_ioc.c_len = nwrt * sectorsize;
! 1335: rs->sc_ioc.c_cmd = C_WRITE;
! 1336: hpibsend(ctlr, slave, C_CMD, &rs->sc_ioc.c_unit,
! 1337: sizeof(rs->sc_ioc)-2);
! 1338: if (hpibswait(ctlr, slave))
! 1339: return (EIO);
! 1340:
! 1341: /*
! 1342: * Send the data.
! 1343: */
! 1344: hpibsend(ctlr, slave, C_EXEC, va, nwrt * sectorsize);
! 1345: (void) hpibswait(ctlr, slave);
! 1346: hpibrecv(ctlr, slave, C_QSTAT, &stat, 1);
! 1347: if (stat)
! 1348: return (EIO);
! 1349: #else /* HD_DUMP_NOT_TRUSTED */
! 1350: /* Let's just talk about this first... */
! 1351: printf("%s: dump addr %p, blk %d\n", sc->sc_dev.dv_xname,
! 1352: va, blkno);
! 1353: delay(500 * 1000); /* half a second */
! 1354: #endif /* HD_DUMP_NOT_TRUSTED */
! 1355:
! 1356: /* update block count */
! 1357: totwrt -= nwrt;
! 1358: blkno += nwrt;
! 1359: va += sectorsize * nwrt;
! 1360: }
! 1361: hddoingadump = 0;
! 1362: return (0);
! 1363: }
CVSweb