141480Smckusick /* 241480Smckusick * Copyright (c) 1990 The Regents of the University of California. 341480Smckusick * All rights reserved. 441480Smckusick * 541480Smckusick * This code is derived from software contributed to Berkeley by 641480Smckusick * Van Jacobson of Lawrence Berkeley Laboratory. 741480Smckusick * 841480Smckusick * %sccs.include.redist.c% 941480Smckusick * 10*58055Shibler * @(#)sd.c 7.18 (Berkeley) 02/18/93 1141480Smckusick */ 1241480Smckusick 1341480Smckusick /* 1441480Smckusick * SCSI CCS (Command Command Set) disk driver. 1541480Smckusick */ 1641480Smckusick #include "sd.h" 1741480Smckusick #if NSD > 0 1841480Smckusick 1941480Smckusick #ifndef lint 2057327Shibler static char rcsid[] = "$Header: /usr/src/sys/hp300/dev/RCS/sd.c,v 1.4 92/12/26 13:26:40 mike Exp $"; 2141480Smckusick #endif 2241480Smckusick 2356507Sbostic #include <sys/param.h> 2456507Sbostic #include <sys/systm.h> 2556507Sbostic #include <sys/buf.h> 2657327Shibler #include <sys/stat.h> 2756507Sbostic #include <sys/dkstat.h> 2856507Sbostic #include <sys/disklabel.h> 2956507Sbostic #include <sys/malloc.h> 3056507Sbostic #include <sys/proc.h> 3156507Sbostic #include <sys/ioctl.h> 3257327Shibler #include <sys/fcntl.h> 3341480Smckusick 3456507Sbostic #include <hp/dev/device.h> 3556507Sbostic #include <hp300/dev/scsireg.h> 3657327Shibler #include <hp300/dev/sdvar.h> 3757327Shibler #ifdef USELEDS 3857327Shibler #include <hp300/hp300/led.h> 3957327Shibler #endif 4045750Smckusick 4156507Sbostic #include <vm/vm_param.h> 4256507Sbostic #include <vm/lock.h> 4356507Sbostic #include <vm/vm_prot.h> 4456507Sbostic #include <vm/pmap.h> 4556507Sbostic 4641480Smckusick extern int scsi_test_unit_rdy(); 4741480Smckusick extern int scsi_request_sense(); 4841480Smckusick extern int scsi_inquiry(); 4941480Smckusick extern int scsi_read_capacity(); 5041480Smckusick extern int scsi_tt_write(); 5141480Smckusick extern int scsireq(); 5241480Smckusick extern int scsiustart(); 5341480Smckusick extern int scsigo(); 5441480Smckusick extern void scsifree(); 5541480Smckusick extern void scsireset(); 5649304Shibler extern void scsi_delay(); 5741480Smckusick 5841480Smckusick extern void disksort(); 5941480Smckusick extern void biodone(); 6041480Smckusick extern int physio(); 6141480Smckusick extern void TBIS(); 6241480Smckusick 6341480Smckusick int sdinit(); 6441480Smckusick void sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr(); 6541480Smckusick 6641480Smckusick struct driver sddriver = { 6741480Smckusick sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr, 6841480Smckusick }; 6941480Smckusick 7041480Smckusick #ifdef DEBUG 7141480Smckusick int sddebug = 1; 7241480Smckusick #define SDB_ERROR 0x01 7341480Smckusick #define SDB_PARTIAL 0x02 7441480Smckusick #endif 7541480Smckusick 7657327Shibler struct sd_softc sd_softc[NSD]; 7757327Shibler struct sdstats sdstats[NSD]; 7841480Smckusick struct buf sdtab[NSD]; 7941480Smckusick struct scsi_fmt_cdb sdcmd[NSD]; 8041480Smckusick struct scsi_fmt_sense sdsense[NSD]; 8141480Smckusick 8241480Smckusick static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT }; 8341480Smckusick static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT }; 8441480Smckusick 8541480Smckusick /* 8641480Smckusick * Table of scsi commands users are allowed to access via "format" 8741480Smckusick * mode. 0 means not legal. 1 means "immediate" (doesn't need dma). 8841480Smckusick * -1 means needs dma and/or wait for intr. 8941480Smckusick */ 9041480Smckusick static char legal_cmds[256] = { 9141480Smckusick /***** 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 9241480Smckusick /*00*/ 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9341480Smckusick /*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 9441480Smckusick /*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9541480Smckusick /*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9641480Smckusick /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9741480Smckusick /*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9841480Smckusick /*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9941480Smckusick /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10041480Smckusick /*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10141480Smckusick /*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10241480Smckusick /*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10341480Smckusick /*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10441480Smckusick /*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10541480Smckusick /*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10641480Smckusick /*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10741480Smckusick /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10841480Smckusick }; 10941480Smckusick 11041480Smckusick static struct scsi_inquiry inqbuf; 11141480Smckusick static struct scsi_fmt_cdb inq = { 11241480Smckusick 6, 11341480Smckusick CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 11441480Smckusick }; 11541480Smckusick 11641480Smckusick static u_char capbuf[8]; 11741480Smckusick struct scsi_fmt_cdb cap = { 11841480Smckusick 10, 11941480Smckusick CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 12041480Smckusick }; 12141480Smckusick 12241480Smckusick static int 12341480Smckusick sdident(sc, hd) 12441480Smckusick struct sd_softc *sc; 12541480Smckusick struct hp_device *hd; 12641480Smckusick { 12741480Smckusick int unit; 12841480Smckusick register int ctlr, slave; 12941480Smckusick register int i; 13041480Smckusick register int tries = 10; 13149304Shibler char idstr[32]; 13245750Smckusick int ismo = 0; 13341480Smckusick 13441480Smckusick ctlr = hd->hp_ctlr; 13541480Smckusick slave = hd->hp_slave; 13641480Smckusick unit = sc->sc_punit; 13749304Shibler scsi_delay(-1); 13841480Smckusick 13941480Smckusick /* 14041480Smckusick * See if unit exists and is a disk then read block size & nblocks. 14141480Smckusick */ 14241480Smckusick while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) { 14345750Smckusick if (i == -1 || --tries < 0) { 14445750Smckusick if (ismo) 14545750Smckusick break; 14641480Smckusick /* doesn't exist or not a CCS device */ 14749304Shibler goto failed; 14845750Smckusick } 14941480Smckusick if (i == STS_CHECKCOND) { 15041480Smckusick u_char sensebuf[128]; 15141480Smckusick struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf; 15241480Smckusick 15341480Smckusick scsi_request_sense(ctlr, slave, unit, sensebuf, 15441480Smckusick sizeof(sensebuf)); 15545750Smckusick if (sp->class == 7) 15645750Smckusick switch (sp->key) { 15745750Smckusick /* not ready -- might be MO with no media */ 15845750Smckusick case 2: 15945750Smckusick if (sp->len == 12 && 16045750Smckusick sensebuf[12] == 10) /* XXX */ 16145750Smckusick ismo = 1; 16245750Smckusick break; 16341480Smckusick /* drive doing an RTZ -- give it a while */ 16445750Smckusick case 6: 16545750Smckusick DELAY(1000000); 16645750Smckusick break; 16745750Smckusick default: 16845750Smckusick break; 16945750Smckusick } 17041480Smckusick } 17141480Smckusick DELAY(1000); 17241480Smckusick } 17345750Smckusick /* 17445750Smckusick * Find out about device 17545750Smckusick */ 17645750Smckusick if (scsi_immed_command(ctlr, slave, unit, &inq, 17745750Smckusick (u_char *)&inqbuf, sizeof(inqbuf), B_READ)) 17849304Shibler goto failed; 17941480Smckusick switch (inqbuf.type) { 18041480Smckusick case 0: /* disk */ 18141480Smckusick case 4: /* WORM */ 18241480Smckusick case 5: /* CD-ROM */ 18341480Smckusick case 7: /* Magneto-optical */ 18441480Smckusick break; 18541480Smckusick default: /* not a disk */ 18649304Shibler goto failed; 18741480Smckusick } 18845750Smckusick /* 18949304Shibler * Get a usable id string 19045750Smckusick */ 19157327Shibler switch (inqbuf.version) { 19257327Shibler case 1: 19357327Shibler case 2: 19449304Shibler bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28); 19549304Shibler for (i = 27; i > 23; --i) 19649304Shibler if (idstr[i] != ' ') 19749304Shibler break; 19849304Shibler idstr[i+1] = 0; 19949304Shibler for (i = 23; i > 7; --i) 20049304Shibler if (idstr[i] != ' ') 20149304Shibler break; 20249304Shibler idstr[i+1] = 0; 20349304Shibler for (i = 7; i >= 0; --i) 20449304Shibler if (idstr[i] != ' ') 20549304Shibler break; 20649304Shibler idstr[i+1] = 0; 20757327Shibler break; 20857327Shibler default: 20957327Shibler bcopy("UNKNOWN", &idstr[0], 8); 21057327Shibler bcopy("DRIVE TYPE", &idstr[8], 11); 21145750Smckusick } 21245750Smckusick i = scsi_immed_command(ctlr, slave, unit, &cap, 21345750Smckusick (u_char *)&capbuf, sizeof(capbuf), B_READ); 21445750Smckusick if (i) { 21549304Shibler if (i != STS_CHECKCOND || 21649304Shibler bcmp(&idstr[0], "HP", 3) || 21749304Shibler bcmp(&idstr[8], "S6300.650A", 11)) 21849304Shibler goto failed; 21945750Smckusick /* XXX unformatted or non-existant MO media; fake it */ 22049304Shibler sc->sc_blks = 318664; 22149304Shibler sc->sc_blksize = 1024; 22245750Smckusick } else { 22345750Smckusick sc->sc_blks = *(u_int *)&capbuf[0]; 22445750Smckusick sc->sc_blksize = *(int *)&capbuf[4]; 22545750Smckusick } 22645750Smckusick /* return value of read capacity is last valid block number */ 22745750Smckusick sc->sc_blks++; 22845750Smckusick 22957327Shibler switch (inqbuf.version) { 23057327Shibler case 1: 23157327Shibler case 2: 23241480Smckusick printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8], 23341480Smckusick &idstr[24]); 23457327Shibler if (inqbuf.version == 2) 23557327Shibler printf(" (SCSI-2)"); 23657327Shibler break; 23757327Shibler default: 23857327Shibler printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit, 23957327Shibler inqbuf.type, inqbuf.qual, inqbuf.version); 24057327Shibler break; 24157327Shibler } 24241480Smckusick printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize); 24353929Shibler if (inqbuf.qual & 0x80) 24453929Shibler sc->sc_flags |= SDF_RMEDIA; 24541480Smckusick if (sc->sc_blksize != DEV_BSIZE) { 24641480Smckusick if (sc->sc_blksize < DEV_BSIZE) { 24741480Smckusick printf("sd%d: need %d byte blocks - drive ignored\n", 24841480Smckusick unit, DEV_BSIZE); 24949304Shibler goto failed; 25041480Smckusick } 25141480Smckusick for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) 25241480Smckusick ++sc->sc_bshift; 25341480Smckusick sc->sc_blks <<= sc->sc_bshift; 25441480Smckusick } 25541480Smckusick sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */ 25649304Shibler scsi_delay(0); 25741480Smckusick return(inqbuf.type); 25849304Shibler failed: 25949304Shibler scsi_delay(0); 26049304Shibler return(-1); 26141480Smckusick } 26241480Smckusick 26341480Smckusick int 26441480Smckusick sdinit(hd) 26541480Smckusick register struct hp_device *hd; 26641480Smckusick { 26741480Smckusick register struct sd_softc *sc = &sd_softc[hd->hp_unit]; 26841480Smckusick 26941480Smckusick sc->sc_hd = hd; 27053929Shibler sc->sc_flags = 0; 27141480Smckusick sc->sc_punit = sdpunit(hd->hp_flags); 27241480Smckusick sc->sc_type = sdident(sc, hd); 27341480Smckusick if (sc->sc_type < 0) 27441480Smckusick return(0); 27541480Smckusick sc->sc_dq.dq_ctlr = hd->hp_ctlr; 27641480Smckusick sc->sc_dq.dq_unit = hd->hp_unit; 27741480Smckusick sc->sc_dq.dq_slave = hd->hp_slave; 27841480Smckusick sc->sc_dq.dq_driver = &sddriver; 27941480Smckusick 28053929Shibler sc->sc_flags |= SDF_ALIVE; 28141480Smckusick return(1); 28241480Smckusick } 28341480Smckusick 28441480Smckusick void 28541480Smckusick sdreset(sc, hd) 28641480Smckusick register struct sd_softc *sc; 28741480Smckusick register struct hp_device *hd; 28841480Smckusick { 28941480Smckusick sdstats[hd->hp_unit].sdresets++; 29041480Smckusick } 29141480Smckusick 29257327Shibler /* 29357327Shibler * Read or constuct a disklabel 29457327Shibler */ 29541480Smckusick int 29657327Shibler sdgetinfo(dev) 29757327Shibler dev_t dev; 29857327Shibler { 29957327Shibler int unit = sdunit(dev); 30057327Shibler register struct sd_softc *sc = &sd_softc[unit]; 30157327Shibler register struct disklabel *lp = &sc->sc_info.si_label; 30257327Shibler register struct partition *pi; 30357327Shibler char *msg, *readdisklabel(); 30457327Shibler 30557327Shibler /* 30657327Shibler * Set some default values to use while reading the label 30757327Shibler * or to use if there isn't a label. 30857327Shibler */ 30957327Shibler bzero((caddr_t)lp, sizeof *lp); 31057327Shibler lp->d_type = DTYPE_SCSI; 31157327Shibler lp->d_secsize = DEV_BSIZE; 31257327Shibler lp->d_nsectors = 32; 31357327Shibler lp->d_ntracks = 20; 314*58055Shibler lp->d_ncylinders = 1; 31557327Shibler lp->d_secpercyl = 32*20; 31657327Shibler lp->d_npartitions = 3; 31757327Shibler lp->d_partitions[2].p_offset = 0; 318*58055Shibler /* XXX we can open a device even without SDF_ALIVE */ 319*58055Shibler if (sc->sc_blksize == 0) 320*58055Shibler sc->sc_blksize = DEV_BSIZE; 32157327Shibler /* XXX ensure size is at least one device block */ 32257327Shibler lp->d_partitions[2].p_size = 32357327Shibler roundup(LABELSECTOR+1, btodb(sc->sc_blksize)); 32457327Shibler 32557327Shibler /* 32657327Shibler * Now try to read the disklabel 32757327Shibler */ 32857327Shibler msg = readdisklabel(sdlabdev(dev), sdstrategy, lp); 32957327Shibler if (msg == NULL) 33057327Shibler return(0); 33157327Shibler if (bcmp(msg, "I/O", 3) == 0) /* XXX */ 33257327Shibler return(EIO); 33357327Shibler 33457327Shibler pi = lp->d_partitions; 33557327Shibler printf("sd%d: WARNING: %s, ", unit, msg); 33657327Shibler #ifdef COMPAT_NOLABEL 33757327Shibler printf("using old default partitioning\n"); 33857327Shibler sdmakedisklabel(unit, lp); 33957327Shibler #else 34057327Shibler printf("defining `c' partition as entire disk\n"); 34157327Shibler pi[2].p_size = sc->sc_blks; 34257327Shibler #endif 34357327Shibler return(0); 34457327Shibler } 34557327Shibler 34657327Shibler int 34749132Skarels sdopen(dev, flags, mode, p) 34841480Smckusick dev_t dev; 34949132Skarels int flags, mode; 35049132Skarels struct proc *p; 35141480Smckusick { 35241480Smckusick register int unit = sdunit(dev); 35341480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 35457327Shibler int mask, error; 35541480Smckusick 35641480Smckusick if (unit >= NSD) 35741480Smckusick return(ENXIO); 35849132Skarels if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag)) 35941480Smckusick return(ENXIO); 36057327Shibler if (sc->sc_flags & SDF_ERROR) 36157327Shibler return(EIO); 36241480Smckusick 36357327Shibler /* 36457327Shibler * Wait for any pending opens/closes to complete 36557327Shibler */ 36657327Shibler while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING)) 36757327Shibler sleep((caddr_t)sc, PRIBIO); 36857327Shibler /* 36957327Shibler * On first open, get label and partition info. 37057327Shibler * We may block reading the label, so be careful 37157327Shibler * to stop any other opens. 37257327Shibler */ 37357327Shibler if (sc->sc_info.si_open == 0) { 37457327Shibler sc->sc_flags |= SDF_OPENING; 37557327Shibler error = sdgetinfo(dev); 37657327Shibler sc->sc_flags &= ~SDF_OPENING; 37757327Shibler wakeup((caddr_t)sc); 37857327Shibler if (error) 37957327Shibler return(error); 38057327Shibler } 38141480Smckusick if (sc->sc_hd->hp_dk >= 0) 38241480Smckusick dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms; 38357327Shibler 38457327Shibler mask = 1 << sdpart(dev); 38557327Shibler if (mode == S_IFCHR) 38657327Shibler sc->sc_info.si_copen |= mask; 38757327Shibler else 38857327Shibler sc->sc_info.si_bopen |= mask; 38957327Shibler sc->sc_info.si_open |= mask; 39041480Smckusick return(0); 39141480Smckusick } 39241480Smckusick 39353929Shibler int 39453929Shibler sdclose(dev, flag, mode, p) 39553929Shibler dev_t dev; 39653929Shibler int flag, mode; 39753929Shibler struct proc *p; 39853929Shibler { 39953929Shibler int unit = sdunit(dev); 40053929Shibler register struct sd_softc *sc = &sd_softc[unit]; 40157327Shibler register struct sdinfo *si = &sc->sc_info; 40257327Shibler int mask, s; 40353929Shibler 40457327Shibler mask = 1 << sdpart(dev); 40557327Shibler if (mode == S_IFCHR) 40657327Shibler si->si_copen &= ~mask; 40757327Shibler else 40857327Shibler si->si_bopen &= ~mask; 40957327Shibler si->si_open = si->si_bopen | si->si_copen; 41053929Shibler /* 41157327Shibler * On last close, we wait for all activity to cease since 41257327Shibler * the label/parition info will become invalid. Since we 41357327Shibler * might sleep, we must block any opens while we are here. 41457327Shibler * Note we don't have to about other closes since we know 41557327Shibler * we are the last one. 41653929Shibler */ 41757327Shibler if (si->si_open == 0) { 41857327Shibler sc->sc_flags |= SDF_CLOSING; 41953929Shibler s = splbio(); 42053929Shibler while (sdtab[unit].b_active) { 42153929Shibler sc->sc_flags |= SDF_WANTED; 42253929Shibler sleep((caddr_t)&sdtab[unit], PRIBIO); 42353929Shibler } 42453929Shibler splx(s); 42557327Shibler sc->sc_flags &= ~(SDF_CLOSING|SDF_WLABEL|SDF_ERROR); 42657327Shibler wakeup((caddr_t)sc); 42753929Shibler } 42853929Shibler sc->sc_format_pid = 0; 42957327Shibler return(0); 43053929Shibler } 43153929Shibler 43241480Smckusick /* 43341480Smckusick * This routine is called for partial block transfers and non-aligned 43441480Smckusick * transfers (the latter only being possible on devices with a block size 43541480Smckusick * larger than DEV_BSIZE). The operation is performed in three steps 43641480Smckusick * using a locally allocated buffer: 43741480Smckusick * 1. transfer any initial partial block 43841480Smckusick * 2. transfer full blocks 43941480Smckusick * 3. transfer any final partial block 44041480Smckusick */ 44141480Smckusick static void 44241480Smckusick sdlblkstrat(bp, bsize) 44341480Smckusick register struct buf *bp; 44441480Smckusick register int bsize; 44541480Smckusick { 44641480Smckusick register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf), 44741480Smckusick M_DEVBUF, M_WAITOK); 44841480Smckusick caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); 44941480Smckusick register int bn, resid; 45041480Smckusick register caddr_t addr; 45141480Smckusick 45241480Smckusick bzero((caddr_t)cbp, sizeof(*cbp)); 45349132Skarels cbp->b_proc = curproc; /* XXX */ 45441480Smckusick cbp->b_dev = bp->b_dev; 45541480Smckusick bn = bp->b_blkno; 45641480Smckusick resid = bp->b_bcount; 45741480Smckusick addr = bp->b_un.b_addr; 45841480Smckusick #ifdef DEBUG 45941480Smckusick if (sddebug & SDB_PARTIAL) 46041480Smckusick printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", 46141480Smckusick bp, bp->b_flags, bn, resid, addr); 46241480Smckusick #endif 46341480Smckusick 46441480Smckusick while (resid > 0) { 46541480Smckusick register int boff = dbtob(bn) & (bsize - 1); 46641480Smckusick register int count; 46741480Smckusick 46841480Smckusick if (boff || resid < bsize) { 46941480Smckusick sdstats[sdunit(bp->b_dev)].sdpartials++; 47055068Spendry count = min(resid, bsize - boff); 47141480Smckusick cbp->b_flags = B_BUSY | B_PHYS | B_READ; 47241480Smckusick cbp->b_blkno = bn - btodb(boff); 47341480Smckusick cbp->b_un.b_addr = cbuf; 47441480Smckusick cbp->b_bcount = bsize; 47541480Smckusick #ifdef DEBUG 47641480Smckusick if (sddebug & SDB_PARTIAL) 47741480Smckusick printf(" readahead: bn %x cnt %x off %x addr %x\n", 47841480Smckusick cbp->b_blkno, count, boff, addr); 47941480Smckusick #endif 48041480Smckusick sdstrategy(cbp); 48141480Smckusick biowait(cbp); 48241480Smckusick if (cbp->b_flags & B_ERROR) { 48341480Smckusick bp->b_flags |= B_ERROR; 48441480Smckusick bp->b_error = cbp->b_error; 48541480Smckusick break; 48641480Smckusick } 48741480Smckusick if (bp->b_flags & B_READ) { 48841480Smckusick bcopy(&cbuf[boff], addr, count); 48941480Smckusick goto done; 49041480Smckusick } 49141480Smckusick bcopy(addr, &cbuf[boff], count); 49241480Smckusick #ifdef DEBUG 49341480Smckusick if (sddebug & SDB_PARTIAL) 49441480Smckusick printf(" writeback: bn %x cnt %x off %x addr %x\n", 49541480Smckusick cbp->b_blkno, count, boff, addr); 49641480Smckusick #endif 49741480Smckusick } else { 49841480Smckusick count = resid & ~(bsize - 1); 49941480Smckusick cbp->b_blkno = bn; 50041480Smckusick cbp->b_un.b_addr = addr; 50141480Smckusick cbp->b_bcount = count; 50241480Smckusick #ifdef DEBUG 50341480Smckusick if (sddebug & SDB_PARTIAL) 50441480Smckusick printf(" fulltrans: bn %x cnt %x addr %x\n", 50541480Smckusick cbp->b_blkno, count, addr); 50641480Smckusick #endif 50741480Smckusick } 50841480Smckusick cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); 50941480Smckusick sdstrategy(cbp); 51041480Smckusick biowait(cbp); 51141480Smckusick if (cbp->b_flags & B_ERROR) { 51241480Smckusick bp->b_flags |= B_ERROR; 51341480Smckusick bp->b_error = cbp->b_error; 51441480Smckusick break; 51541480Smckusick } 51641480Smckusick done: 51741480Smckusick bn += btodb(count); 51841480Smckusick resid -= count; 51941480Smckusick addr += count; 52041480Smckusick #ifdef DEBUG 52141480Smckusick if (sddebug & SDB_PARTIAL) 52241480Smckusick printf(" done: bn %x resid %x addr %x\n", 52341480Smckusick bn, resid, addr); 52441480Smckusick #endif 52541480Smckusick } 52641480Smckusick free(cbuf, M_DEVBUF); 52741480Smckusick free(cbp, M_DEVBUF); 52841480Smckusick } 52941480Smckusick 53041480Smckusick void 53141480Smckusick sdstrategy(bp) 53241480Smckusick register struct buf *bp; 53341480Smckusick { 53457327Shibler int unit = sdunit(bp->b_dev); 53541480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 53641480Smckusick register struct buf *dp = &sdtab[unit]; 53757327Shibler register struct partition *pinfo; 53845750Smckusick register daddr_t bn; 53945750Smckusick register int sz, s; 54041480Smckusick 54157327Shibler if (sc->sc_flags & SDF_ERROR) { 54257327Shibler bp->b_error = EIO; 54357327Shibler goto bad; 54457327Shibler } 54541480Smckusick if (sc->sc_format_pid) { 54649132Skarels if (sc->sc_format_pid != curproc->p_pid) { /* XXX */ 54741480Smckusick bp->b_error = EPERM; 54857327Shibler goto bad; 54941480Smckusick } 55041480Smckusick bp->b_cylin = 0; 55141480Smckusick } else { 55241480Smckusick bn = bp->b_blkno; 55345750Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 55457327Shibler pinfo = &sc->sc_info.si_label.d_partitions[sdpart(bp->b_dev)]; 55557327Shibler if (bn < 0 || bn + sz > pinfo->p_size) { 55657327Shibler sz = pinfo->p_size - bn; 55745750Smckusick if (sz == 0) { 55841480Smckusick bp->b_resid = bp->b_bcount; 55941480Smckusick goto done; 56041480Smckusick } 56145750Smckusick if (sz < 0) { 56245750Smckusick bp->b_error = EINVAL; 56357327Shibler goto bad; 56445750Smckusick } 56545750Smckusick bp->b_bcount = dbtob(sz); 56641480Smckusick } 56741480Smckusick /* 56857327Shibler * Check for write to write protected label 56957327Shibler */ 57057327Shibler if (bn + pinfo->p_offset <= LABELSECTOR && 57157327Shibler #if LABELSECTOR != 0 57257327Shibler bn + pinfo->p_offset + sz > LABELSECTOR && 57357327Shibler #endif 57457327Shibler !(bp->b_flags & B_READ) && !(sc->sc_flags & SDF_WLABEL)) { 57557327Shibler bp->b_error = EROFS; 57657327Shibler goto bad; 57757327Shibler } 57857327Shibler /* 57941480Smckusick * Non-aligned or partial-block transfers handled specially. 58041480Smckusick */ 58141480Smckusick s = sc->sc_blksize - 1; 58241480Smckusick if ((dbtob(bn) & s) || (bp->b_bcount & s)) { 58341480Smckusick sdlblkstrat(bp, sc->sc_blksize); 58441480Smckusick goto done; 58541480Smckusick } 58657327Shibler bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift; 58741480Smckusick } 58841480Smckusick s = splbio(); 58941480Smckusick disksort(dp, bp); 59041480Smckusick if (dp->b_active == 0) { 59141480Smckusick dp->b_active = 1; 59241480Smckusick sdustart(unit); 59341480Smckusick } 59441480Smckusick splx(s); 59541480Smckusick return; 59657327Shibler bad: 59757327Shibler bp->b_flags |= B_ERROR; 59841480Smckusick done: 59945750Smckusick biodone(bp); 60041480Smckusick } 60141480Smckusick 60241480Smckusick void 60341480Smckusick sdustart(unit) 60441480Smckusick register int unit; 60541480Smckusick { 60641480Smckusick if (scsireq(&sd_softc[unit].sc_dq)) 60741480Smckusick sdstart(unit); 60841480Smckusick } 60941480Smckusick 61050039Skarels /* 61150039Skarels * Return: 61250039Skarels * 0 if not really an error 61350039Skarels * <0 if we should do a retry 61450039Skarels * >0 if a fatal error 61550039Skarels */ 61645750Smckusick static int 61741480Smckusick sderror(unit, sc, hp, stat) 61841480Smckusick int unit, stat; 61941480Smckusick register struct sd_softc *sc; 62041480Smckusick register struct hp_device *hp; 62141480Smckusick { 62250039Skarels int cond = 1; 62345750Smckusick 62441480Smckusick sdsense[unit].status = stat; 62541480Smckusick if (stat & STS_CHECKCOND) { 62641480Smckusick struct scsi_xsense *sp; 62741480Smckusick 62841480Smckusick scsi_request_sense(hp->hp_ctlr, hp->hp_slave, 62941480Smckusick sc->sc_punit, sdsense[unit].sense, 63041480Smckusick sizeof(sdsense[unit].sense)); 63141480Smckusick sp = (struct scsi_xsense *)sdsense[unit].sense; 63241480Smckusick printf("sd%d: scsi sense class %d, code %d", unit, 63341480Smckusick sp->class, sp->code); 63441480Smckusick if (sp->class == 7) { 63541480Smckusick printf(", key %d", sp->key); 63641480Smckusick if (sp->valid) 63741480Smckusick printf(", blk %d", *(int *)&sp->info1); 63850039Skarels switch (sp->key) { 63950039Skarels /* no sense, try again */ 64050039Skarels case 0: 64150039Skarels cond = -1; 64250039Skarels break; 64350039Skarels /* recovered error, not a problem */ 64450039Skarels case 1: 64550039Skarels cond = 0; 64650039Skarels break; 64757327Shibler /* possible media change */ 64857327Shibler case 6: 64957327Shibler /* 65057327Shibler * For removable media, if we are doing the 65157327Shibler * first open (i.e. reading the label) go 65257327Shibler * ahead and retry, otherwise someone has 65357327Shibler * changed the media out from under us and 65457327Shibler * we should abort any further operations 65557327Shibler * until a close is done. 65657327Shibler */ 65757327Shibler if (sc->sc_flags & SDF_RMEDIA) { 65857327Shibler if (sc->sc_flags & SDF_OPENING) 65957327Shibler cond = -1; 66057327Shibler else 66157327Shibler sc->sc_flags |= SDF_ERROR; 66257327Shibler } 66357327Shibler break; 66450039Skarels } 66541480Smckusick } 66641480Smckusick printf("\n"); 66741480Smckusick } 66850039Skarels return(cond); 66941480Smckusick } 67041480Smckusick 67141480Smckusick static void 67241480Smckusick sdfinish(unit, sc, bp) 67341480Smckusick int unit; 67441480Smckusick register struct sd_softc *sc; 67541480Smckusick register struct buf *bp; 67641480Smckusick { 67753929Shibler register struct buf *dp = &sdtab[unit]; 67853929Shibler 67953929Shibler dp->b_errcnt = 0; 68053929Shibler dp->b_actf = bp->b_actf; 68141480Smckusick bp->b_resid = 0; 68245750Smckusick biodone(bp); 68341480Smckusick scsifree(&sc->sc_dq); 68453929Shibler if (dp->b_actf) 68541480Smckusick sdustart(unit); 68653929Shibler else { 68753929Shibler dp->b_active = 0; 68853929Shibler if (sc->sc_flags & SDF_WANTED) { 68953929Shibler sc->sc_flags &= ~SDF_WANTED; 69053929Shibler wakeup((caddr_t)dp); 69153929Shibler } 69253929Shibler } 69341480Smckusick } 69441480Smckusick 69541480Smckusick void 69641480Smckusick sdstart(unit) 69741480Smckusick register int unit; 69841480Smckusick { 69941480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 70041480Smckusick register struct hp_device *hp = sc->sc_hd; 70141480Smckusick 70241480Smckusick /* 70341480Smckusick * we have the SCSI bus -- in format mode, we may or may not need dma 70441480Smckusick * so check now. 70541480Smckusick */ 70641480Smckusick if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) { 70741480Smckusick register struct buf *bp = sdtab[unit].b_actf; 70841480Smckusick register int sts; 70941480Smckusick 71041480Smckusick sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave, 71141480Smckusick sc->sc_punit, &sdcmd[unit], 71241480Smckusick bp->b_un.b_addr, bp->b_bcount, 71341480Smckusick bp->b_flags & B_READ); 71441480Smckusick sdsense[unit].status = sts; 71541480Smckusick if (sts & 0xfe) { 71645750Smckusick (void) sderror(unit, sc, hp, sts); 71741480Smckusick bp->b_flags |= B_ERROR; 71841480Smckusick bp->b_error = EIO; 71941480Smckusick } 72041480Smckusick sdfinish(unit, sc, bp); 72141480Smckusick 72241480Smckusick } else if (scsiustart(hp->hp_ctlr)) 72341480Smckusick sdgo(unit); 72441480Smckusick } 72541480Smckusick 72641480Smckusick void 72741480Smckusick sdgo(unit) 72841480Smckusick register int unit; 72941480Smckusick { 73041480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 73141480Smckusick register struct hp_device *hp = sc->sc_hd; 73241480Smckusick register struct buf *bp = sdtab[unit].b_actf; 73341480Smckusick register int pad; 73441480Smckusick register struct scsi_fmt_cdb *cmd; 73541480Smckusick 73657327Shibler /* 73757327Shibler * Drive is in an error state, abort all operations 73857327Shibler */ 73957327Shibler if (sc->sc_flags & SDF_ERROR) { 74057327Shibler bp->b_flags |= B_ERROR; 74157327Shibler bp->b_error = EIO; 74257327Shibler sdfinish(unit, sc, bp); 74357327Shibler return; 74457327Shibler } 74541480Smckusick if (sc->sc_format_pid) { 74641480Smckusick cmd = &sdcmd[unit]; 74741480Smckusick pad = 0; 74841480Smckusick } else { 74941480Smckusick cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd; 75041480Smckusick *(int *)(&cmd->cdb[2]) = bp->b_cylin; 75141480Smckusick pad = howmany(bp->b_bcount, sc->sc_blksize); 75241480Smckusick *(u_short *)(&cmd->cdb[7]) = pad; 75341480Smckusick pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0; 75441480Smckusick #ifdef DEBUG 75541480Smckusick if (pad) 75641480Smckusick printf("sd%d: partial block xfer -- %x bytes\n", 75741480Smckusick unit, bp->b_bcount); 75841480Smckusick #endif 75941480Smckusick sdstats[unit].sdtransfers++; 76041480Smckusick } 76157327Shibler #ifdef USELEDS 76257327Shibler if (inledcontrol == 0) 76357327Shibler ledcontrol(0, 0, LED_DISK); 76457327Shibler #endif 76541480Smckusick if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) { 76641480Smckusick if (hp->hp_dk >= 0) { 76741480Smckusick dk_busy |= 1 << hp->hp_dk; 76841480Smckusick ++dk_seek[hp->hp_dk]; 76941480Smckusick ++dk_xfer[hp->hp_dk]; 77041480Smckusick dk_wds[hp->hp_dk] += bp->b_bcount >> 6; 77141480Smckusick } 77241480Smckusick return; 77341480Smckusick } 77441480Smckusick #ifdef DEBUG 77541480Smckusick if (sddebug & SDB_ERROR) 77641480Smckusick printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n", 77741480Smckusick unit, bp->b_flags & B_READ? "read" : "write", 77841480Smckusick bp->b_un.b_addr, bp->b_cylin, bp->b_bcount, 77941480Smckusick sdtab[unit].b_errcnt); 78041480Smckusick #endif 78141480Smckusick bp->b_flags |= B_ERROR; 78241480Smckusick bp->b_error = EIO; 78341480Smckusick sdfinish(unit, sc, bp); 78441480Smckusick } 78541480Smckusick 78641480Smckusick void 78741480Smckusick sdintr(unit, stat) 78841480Smckusick register int unit; 78941480Smckusick int stat; 79041480Smckusick { 79141480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 79241480Smckusick register struct buf *bp = sdtab[unit].b_actf; 79341480Smckusick register struct hp_device *hp = sc->sc_hd; 79450039Skarels int cond; 79541480Smckusick 79641480Smckusick if (bp == NULL) { 79741480Smckusick printf("sd%d: bp == NULL\n", unit); 79841480Smckusick return; 79941480Smckusick } 80041480Smckusick if (hp->hp_dk >= 0) 80141480Smckusick dk_busy &=~ (1 << hp->hp_dk); 80241480Smckusick if (stat) { 80341480Smckusick #ifdef DEBUG 80441480Smckusick if (sddebug & SDB_ERROR) 80541480Smckusick printf("sd%d: sdintr: bad scsi status 0x%x\n", 80641480Smckusick unit, stat); 80741480Smckusick #endif 80850039Skarels cond = sderror(unit, sc, hp, stat); 80950039Skarels if (cond) { 81050039Skarels if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) { 81150038Skarels #ifdef DEBUG 81250039Skarels if (sddebug & SDB_ERROR) 81350039Skarels printf("sd%d: retry #%d\n", 81450039Skarels unit, sdtab[unit].b_errcnt); 81550038Skarels #endif 81650039Skarels sdstart(unit); 81750039Skarels return; 81850039Skarels } 81950039Skarels bp->b_flags |= B_ERROR; 82050039Skarels bp->b_error = EIO; 82145750Smckusick } 82241480Smckusick } 82341480Smckusick sdfinish(unit, sc, bp); 82441480Smckusick } 82541480Smckusick 82641480Smckusick int 82749132Skarels sdread(dev, uio, flags) 82841480Smckusick dev_t dev; 82941480Smckusick struct uio *uio; 83049132Skarels int flags; 83141480Smckusick { 83241480Smckusick register int unit = sdunit(dev); 83341480Smckusick register int pid; 83441480Smckusick 83549132Skarels if ((pid = sd_softc[unit].sc_format_pid) && 83649132Skarels pid != uio->uio_procp->p_pid) 83741480Smckusick return (EPERM); 83841480Smckusick 83949132Skarels return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio)); 84041480Smckusick } 84141480Smckusick 84241480Smckusick int 84349132Skarels sdwrite(dev, uio, flags) 84441480Smckusick dev_t dev; 84541480Smckusick struct uio *uio; 84649132Skarels int flags; 84741480Smckusick { 84841480Smckusick register int unit = sdunit(dev); 84941480Smckusick register int pid; 85041480Smckusick 85149132Skarels if ((pid = sd_softc[unit].sc_format_pid) && 85249132Skarels pid != uio->uio_procp->p_pid) 85341480Smckusick return (EPERM); 85441480Smckusick 85549132Skarels return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio)); 85641480Smckusick } 85741480Smckusick 85841480Smckusick int 85949132Skarels sdioctl(dev, cmd, data, flag, p) 86041480Smckusick dev_t dev; 86141480Smckusick int cmd; 86241480Smckusick caddr_t data; 86341480Smckusick int flag; 86449132Skarels struct proc *p; 86541480Smckusick { 86657327Shibler int unit = sdunit(dev); 86741480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 86857327Shibler register struct disklabel *lp = &sc->sc_info.si_label; 86957327Shibler int error, flags; 87041480Smckusick 87141480Smckusick switch (cmd) { 87241480Smckusick default: 87341480Smckusick return (EINVAL); 87441480Smckusick 87557327Shibler case DIOCGDINFO: 87657327Shibler *(struct disklabel *)data = *lp; 87757327Shibler return (0); 87857327Shibler 87957327Shibler case DIOCGPART: 88057327Shibler ((struct partinfo *)data)->disklab = lp; 88157327Shibler ((struct partinfo *)data)->part = 88257327Shibler &lp->d_partitions[sdpart(dev)]; 88357327Shibler return (0); 88457327Shibler 88557327Shibler case DIOCWLABEL: 88657327Shibler if ((flag & FWRITE) == 0) 88757327Shibler return (EBADF); 88857327Shibler if (*(int *)data) 88957327Shibler sc->sc_flags |= SDF_WLABEL; 89057327Shibler else 89157327Shibler sc->sc_flags &= ~SDF_WLABEL; 89257327Shibler return (0); 89357327Shibler 89457327Shibler case DIOCSDINFO: 89557327Shibler if ((flag & FWRITE) == 0) 89657327Shibler return (EBADF); 89757327Shibler error = setdisklabel(lp, (struct disklabel *)data, 89857327Shibler (sc->sc_flags & SDF_WLABEL) ? 0 89957327Shibler : sc->sc_info.si_open); 90057327Shibler return (error); 90157327Shibler 90257327Shibler case DIOCWDINFO: 90357327Shibler if ((flag & FWRITE) == 0) 90457327Shibler return (EBADF); 90557327Shibler error = setdisklabel(lp, (struct disklabel *)data, 90657327Shibler (sc->sc_flags & SDF_WLABEL) ? 0 90757327Shibler : sc->sc_info.si_open); 90857327Shibler if (error) 90957327Shibler return (error); 91057327Shibler flags = sc->sc_flags; 91157327Shibler sc->sc_flags = SDF_ALIVE | SDF_WLABEL; 91257327Shibler error = writedisklabel(sdlabdev(dev), sdstrategy, lp); 91357327Shibler sc->sc_flags = flags; 91457327Shibler return (error); 91557327Shibler 91641480Smckusick case SDIOCSFORMAT: 91741480Smckusick /* take this device into or out of "format" mode */ 91849132Skarels if (suser(p->p_ucred, &p->p_acflag)) 91941480Smckusick return(EPERM); 92041480Smckusick 92141480Smckusick if (*(int *)data) { 92241480Smckusick if (sc->sc_format_pid) 92341480Smckusick return (EPERM); 92449132Skarels sc->sc_format_pid = p->p_pid; 92541480Smckusick } else 92641480Smckusick sc->sc_format_pid = 0; 92741480Smckusick return (0); 92841480Smckusick 92941480Smckusick case SDIOCGFORMAT: 93041480Smckusick /* find out who has the device in format mode */ 93141480Smckusick *(int *)data = sc->sc_format_pid; 93241480Smckusick return (0); 93341480Smckusick 93441480Smckusick case SDIOCSCSICOMMAND: 93541480Smckusick /* 93641480Smckusick * Save what user gave us as SCSI cdb to use with next 93741480Smckusick * read or write to the char device. 93841480Smckusick */ 93949132Skarels if (sc->sc_format_pid != p->p_pid) 94041480Smckusick return (EPERM); 94141480Smckusick if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) 94241480Smckusick return (EINVAL); 94341480Smckusick bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0])); 94441480Smckusick return (0); 94541480Smckusick 94641480Smckusick case SDIOCSENSE: 94741480Smckusick /* 94841480Smckusick * return the SCSI sense data saved after the last 94941480Smckusick * operation that completed with "check condition" status. 95041480Smckusick */ 95141480Smckusick bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0])); 95241480Smckusick return (0); 95341480Smckusick 95441480Smckusick } 95541480Smckusick /*NOTREACHED*/ 95641480Smckusick } 95741480Smckusick 95841480Smckusick int 95941480Smckusick sdsize(dev) 96041480Smckusick dev_t dev; 96141480Smckusick { 96241480Smckusick register int unit = sdunit(dev); 96341480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 96457327Shibler int psize, didopen = 0; 96541480Smckusick 96641480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 96741480Smckusick return(-1); 96841480Smckusick 96957327Shibler /* 97057327Shibler * We get called very early on (via swapconf) 97157327Shibler * without the device being open so we may need 97257327Shibler * to handle it here. 97357327Shibler */ 97457327Shibler if (sc->sc_info.si_open == 0) { 97557327Shibler if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) 97657327Shibler return(-1); 97757327Shibler didopen = 1; 97857327Shibler } 97957327Shibler psize = sc->sc_info.si_label.d_partitions[sdpart(dev)].p_size; 98057327Shibler if (didopen) 98157327Shibler (void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); 98257327Shibler return (psize); 98341480Smckusick } 98441480Smckusick 98541480Smckusick /* 98641480Smckusick * Non-interrupt driven, non-dma dump routine. 98741480Smckusick */ 98841480Smckusick int 98941480Smckusick sddump(dev) 99041480Smckusick dev_t dev; 99141480Smckusick { 99241480Smckusick int part = sdpart(dev); 99341480Smckusick int unit = sdunit(dev); 99441480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 99541480Smckusick register struct hp_device *hp = sc->sc_hd; 99657327Shibler register struct partition *pinfo; 99741480Smckusick register daddr_t baddr; 99841480Smckusick register int maddr; 99941480Smckusick register int pages, i; 100041480Smckusick int stat; 100141480Smckusick extern int lowram; 100241480Smckusick 100341480Smckusick /* is drive ok? */ 100441480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 100541480Smckusick return (ENXIO); 100657327Shibler pinfo = &sc->sc_info.si_label.d_partitions[part]; 100741480Smckusick /* dump parameters in range? */ 100857327Shibler if (dumplo < 0 || dumplo >= pinfo->p_size || 100957327Shibler pinfo->p_fstype != FS_SWAP) 101041480Smckusick return (EINVAL); 101157327Shibler pages = physmem; 101257327Shibler if (dumplo + ctod(pages) > pinfo->p_size) 101357327Shibler pages = dtoc(pinfo->p_size - dumplo); 101441480Smckusick maddr = lowram; 101557327Shibler baddr = dumplo + pinfo->p_offset; 101641480Smckusick /* scsi bus idle? */ 101741480Smckusick if (!scsireq(&sc->sc_dq)) { 101841480Smckusick scsireset(hp->hp_ctlr); 101941480Smckusick sdreset(sc, sc->sc_hd); 102041480Smckusick printf("[ drive %d reset ] ", unit); 102141480Smckusick } 102241480Smckusick for (i = 0; i < pages; i++) { 102341480Smckusick #define NPGMB (1024*1024/NBPG) 102441480Smckusick /* print out how many Mbs we have dumped */ 102541480Smckusick if (i && (i % NPGMB) == 0) 102641480Smckusick printf("%d ", i / NPGMB); 102741480Smckusick #undef NPBMG 102852614Smckusick pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr, 102951576Smckusick VM_PROT_READ, TRUE); 103041480Smckusick stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, 103141480Smckusick vmmap, NBPG, baddr, sc->sc_bshift); 103241480Smckusick if (stat) { 103341480Smckusick printf("sddump: scsi write error 0x%x\n", stat); 103441480Smckusick return (EIO); 103541480Smckusick } 103641480Smckusick maddr += NBPG; 103741480Smckusick baddr += ctod(1); 103841480Smckusick } 103941480Smckusick return (0); 104041480Smckusick } 104141480Smckusick #endif 1042