141480Smckusick /* 2*63151Sbostic * Copyright (c) 1990, 1993 3*63151Sbostic * The Regents of the University of California. 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*63151Sbostic * @(#)sd.c 8.1 (Berkeley) 06/10/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; 31458055Shibler lp->d_ncylinders = 1; 31557327Shibler lp->d_secpercyl = 32*20; 31657327Shibler lp->d_npartitions = 3; 31757327Shibler lp->d_partitions[2].p_offset = 0; 31858055Shibler /* XXX we can open a device even without SDF_ALIVE */ 31958055Shibler if (sc->sc_blksize == 0) 32058055Shibler 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 33257327Shibler pi = lp->d_partitions; 33357327Shibler printf("sd%d: WARNING: %s, ", unit, msg); 33457327Shibler #ifdef COMPAT_NOLABEL 33557327Shibler printf("using old default partitioning\n"); 33657327Shibler sdmakedisklabel(unit, lp); 33757327Shibler #else 33857327Shibler printf("defining `c' partition as entire disk\n"); 33957327Shibler pi[2].p_size = sc->sc_blks; 34057327Shibler #endif 34157327Shibler return(0); 34257327Shibler } 34357327Shibler 34457327Shibler int 34549132Skarels sdopen(dev, flags, mode, p) 34641480Smckusick dev_t dev; 34749132Skarels int flags, mode; 34849132Skarels struct proc *p; 34941480Smckusick { 35041480Smckusick register int unit = sdunit(dev); 35141480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 35257327Shibler int mask, error; 35341480Smckusick 35441480Smckusick if (unit >= NSD) 35541480Smckusick return(ENXIO); 35649132Skarels if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag)) 35741480Smckusick return(ENXIO); 35857327Shibler if (sc->sc_flags & SDF_ERROR) 35957327Shibler return(EIO); 36041480Smckusick 36157327Shibler /* 36257327Shibler * Wait for any pending opens/closes to complete 36357327Shibler */ 36457327Shibler while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING)) 36557327Shibler sleep((caddr_t)sc, PRIBIO); 36657327Shibler /* 36757327Shibler * On first open, get label and partition info. 36857327Shibler * We may block reading the label, so be careful 36957327Shibler * to stop any other opens. 37057327Shibler */ 37157327Shibler if (sc->sc_info.si_open == 0) { 37257327Shibler sc->sc_flags |= SDF_OPENING; 37357327Shibler error = sdgetinfo(dev); 37457327Shibler sc->sc_flags &= ~SDF_OPENING; 37557327Shibler wakeup((caddr_t)sc); 37657327Shibler if (error) 37757327Shibler return(error); 37857327Shibler } 37941480Smckusick if (sc->sc_hd->hp_dk >= 0) 38041480Smckusick dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms; 38157327Shibler 38257327Shibler mask = 1 << sdpart(dev); 38357327Shibler if (mode == S_IFCHR) 38457327Shibler sc->sc_info.si_copen |= mask; 38557327Shibler else 38657327Shibler sc->sc_info.si_bopen |= mask; 38757327Shibler sc->sc_info.si_open |= mask; 38841480Smckusick return(0); 38941480Smckusick } 39041480Smckusick 39153929Shibler int 39253929Shibler sdclose(dev, flag, mode, p) 39353929Shibler dev_t dev; 39453929Shibler int flag, mode; 39553929Shibler struct proc *p; 39653929Shibler { 39753929Shibler int unit = sdunit(dev); 39853929Shibler register struct sd_softc *sc = &sd_softc[unit]; 39957327Shibler register struct sdinfo *si = &sc->sc_info; 40057327Shibler int mask, s; 40153929Shibler 40257327Shibler mask = 1 << sdpart(dev); 40357327Shibler if (mode == S_IFCHR) 40457327Shibler si->si_copen &= ~mask; 40557327Shibler else 40657327Shibler si->si_bopen &= ~mask; 40757327Shibler si->si_open = si->si_bopen | si->si_copen; 40853929Shibler /* 40957327Shibler * On last close, we wait for all activity to cease since 41057327Shibler * the label/parition info will become invalid. Since we 41157327Shibler * might sleep, we must block any opens while we are here. 41257327Shibler * Note we don't have to about other closes since we know 41357327Shibler * we are the last one. 41453929Shibler */ 41557327Shibler if (si->si_open == 0) { 41657327Shibler sc->sc_flags |= SDF_CLOSING; 41753929Shibler s = splbio(); 41853929Shibler while (sdtab[unit].b_active) { 41953929Shibler sc->sc_flags |= SDF_WANTED; 42053929Shibler sleep((caddr_t)&sdtab[unit], PRIBIO); 42153929Shibler } 42253929Shibler splx(s); 42357327Shibler sc->sc_flags &= ~(SDF_CLOSING|SDF_WLABEL|SDF_ERROR); 42457327Shibler wakeup((caddr_t)sc); 42553929Shibler } 42653929Shibler sc->sc_format_pid = 0; 42757327Shibler return(0); 42853929Shibler } 42953929Shibler 43041480Smckusick /* 43141480Smckusick * This routine is called for partial block transfers and non-aligned 43241480Smckusick * transfers (the latter only being possible on devices with a block size 43341480Smckusick * larger than DEV_BSIZE). The operation is performed in three steps 43441480Smckusick * using a locally allocated buffer: 43541480Smckusick * 1. transfer any initial partial block 43641480Smckusick * 2. transfer full blocks 43741480Smckusick * 3. transfer any final partial block 43841480Smckusick */ 43941480Smckusick static void 44041480Smckusick sdlblkstrat(bp, bsize) 44141480Smckusick register struct buf *bp; 44241480Smckusick register int bsize; 44341480Smckusick { 44441480Smckusick register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf), 44541480Smckusick M_DEVBUF, M_WAITOK); 44641480Smckusick caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); 44741480Smckusick register int bn, resid; 44841480Smckusick register caddr_t addr; 44941480Smckusick 45041480Smckusick bzero((caddr_t)cbp, sizeof(*cbp)); 45149132Skarels cbp->b_proc = curproc; /* XXX */ 45241480Smckusick cbp->b_dev = bp->b_dev; 45341480Smckusick bn = bp->b_blkno; 45441480Smckusick resid = bp->b_bcount; 45541480Smckusick addr = bp->b_un.b_addr; 45641480Smckusick #ifdef DEBUG 45741480Smckusick if (sddebug & SDB_PARTIAL) 45841480Smckusick printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", 45941480Smckusick bp, bp->b_flags, bn, resid, addr); 46041480Smckusick #endif 46141480Smckusick 46241480Smckusick while (resid > 0) { 46341480Smckusick register int boff = dbtob(bn) & (bsize - 1); 46441480Smckusick register int count; 46541480Smckusick 46641480Smckusick if (boff || resid < bsize) { 46741480Smckusick sdstats[sdunit(bp->b_dev)].sdpartials++; 46855068Spendry count = min(resid, bsize - boff); 46941480Smckusick cbp->b_flags = B_BUSY | B_PHYS | B_READ; 47041480Smckusick cbp->b_blkno = bn - btodb(boff); 47141480Smckusick cbp->b_un.b_addr = cbuf; 47241480Smckusick cbp->b_bcount = bsize; 47341480Smckusick #ifdef DEBUG 47441480Smckusick if (sddebug & SDB_PARTIAL) 47541480Smckusick printf(" readahead: bn %x cnt %x off %x addr %x\n", 47641480Smckusick cbp->b_blkno, count, boff, addr); 47741480Smckusick #endif 47841480Smckusick sdstrategy(cbp); 47941480Smckusick biowait(cbp); 48041480Smckusick if (cbp->b_flags & B_ERROR) { 48141480Smckusick bp->b_flags |= B_ERROR; 48241480Smckusick bp->b_error = cbp->b_error; 48341480Smckusick break; 48441480Smckusick } 48541480Smckusick if (bp->b_flags & B_READ) { 48641480Smckusick bcopy(&cbuf[boff], addr, count); 48741480Smckusick goto done; 48841480Smckusick } 48941480Smckusick bcopy(addr, &cbuf[boff], count); 49041480Smckusick #ifdef DEBUG 49141480Smckusick if (sddebug & SDB_PARTIAL) 49241480Smckusick printf(" writeback: bn %x cnt %x off %x addr %x\n", 49341480Smckusick cbp->b_blkno, count, boff, addr); 49441480Smckusick #endif 49541480Smckusick } else { 49641480Smckusick count = resid & ~(bsize - 1); 49741480Smckusick cbp->b_blkno = bn; 49841480Smckusick cbp->b_un.b_addr = addr; 49941480Smckusick cbp->b_bcount = count; 50041480Smckusick #ifdef DEBUG 50141480Smckusick if (sddebug & SDB_PARTIAL) 50241480Smckusick printf(" fulltrans: bn %x cnt %x addr %x\n", 50341480Smckusick cbp->b_blkno, count, addr); 50441480Smckusick #endif 50541480Smckusick } 50641480Smckusick cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); 50741480Smckusick sdstrategy(cbp); 50841480Smckusick biowait(cbp); 50941480Smckusick if (cbp->b_flags & B_ERROR) { 51041480Smckusick bp->b_flags |= B_ERROR; 51141480Smckusick bp->b_error = cbp->b_error; 51241480Smckusick break; 51341480Smckusick } 51441480Smckusick done: 51541480Smckusick bn += btodb(count); 51641480Smckusick resid -= count; 51741480Smckusick addr += count; 51841480Smckusick #ifdef DEBUG 51941480Smckusick if (sddebug & SDB_PARTIAL) 52041480Smckusick printf(" done: bn %x resid %x addr %x\n", 52141480Smckusick bn, resid, addr); 52241480Smckusick #endif 52341480Smckusick } 52441480Smckusick free(cbuf, M_DEVBUF); 52541480Smckusick free(cbp, M_DEVBUF); 52641480Smckusick } 52741480Smckusick 52841480Smckusick void 52941480Smckusick sdstrategy(bp) 53041480Smckusick register struct buf *bp; 53141480Smckusick { 53257327Shibler int unit = sdunit(bp->b_dev); 53341480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 53441480Smckusick register struct buf *dp = &sdtab[unit]; 53557327Shibler register struct partition *pinfo; 53645750Smckusick register daddr_t bn; 53745750Smckusick register int sz, s; 53841480Smckusick 53957327Shibler if (sc->sc_flags & SDF_ERROR) { 54057327Shibler bp->b_error = EIO; 54157327Shibler goto bad; 54257327Shibler } 54341480Smckusick if (sc->sc_format_pid) { 54449132Skarels if (sc->sc_format_pid != curproc->p_pid) { /* XXX */ 54541480Smckusick bp->b_error = EPERM; 54657327Shibler goto bad; 54741480Smckusick } 54841480Smckusick bp->b_cylin = 0; 54941480Smckusick } else { 55041480Smckusick bn = bp->b_blkno; 55145750Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 55257327Shibler pinfo = &sc->sc_info.si_label.d_partitions[sdpart(bp->b_dev)]; 55357327Shibler if (bn < 0 || bn + sz > pinfo->p_size) { 55457327Shibler sz = pinfo->p_size - bn; 55545750Smckusick if (sz == 0) { 55641480Smckusick bp->b_resid = bp->b_bcount; 55741480Smckusick goto done; 55841480Smckusick } 55945750Smckusick if (sz < 0) { 56045750Smckusick bp->b_error = EINVAL; 56157327Shibler goto bad; 56245750Smckusick } 56345750Smckusick bp->b_bcount = dbtob(sz); 56441480Smckusick } 56541480Smckusick /* 56657327Shibler * Check for write to write protected label 56757327Shibler */ 56857327Shibler if (bn + pinfo->p_offset <= LABELSECTOR && 56957327Shibler #if LABELSECTOR != 0 57057327Shibler bn + pinfo->p_offset + sz > LABELSECTOR && 57157327Shibler #endif 57257327Shibler !(bp->b_flags & B_READ) && !(sc->sc_flags & SDF_WLABEL)) { 57357327Shibler bp->b_error = EROFS; 57457327Shibler goto bad; 57557327Shibler } 57657327Shibler /* 57741480Smckusick * Non-aligned or partial-block transfers handled specially. 57841480Smckusick */ 57941480Smckusick s = sc->sc_blksize - 1; 58041480Smckusick if ((dbtob(bn) & s) || (bp->b_bcount & s)) { 58141480Smckusick sdlblkstrat(bp, sc->sc_blksize); 58241480Smckusick goto done; 58341480Smckusick } 58457327Shibler bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift; 58541480Smckusick } 58641480Smckusick s = splbio(); 58741480Smckusick disksort(dp, bp); 58841480Smckusick if (dp->b_active == 0) { 58941480Smckusick dp->b_active = 1; 59041480Smckusick sdustart(unit); 59141480Smckusick } 59241480Smckusick splx(s); 59341480Smckusick return; 59457327Shibler bad: 59557327Shibler bp->b_flags |= B_ERROR; 59641480Smckusick done: 59745750Smckusick biodone(bp); 59841480Smckusick } 59941480Smckusick 60041480Smckusick void 60141480Smckusick sdustart(unit) 60241480Smckusick register int unit; 60341480Smckusick { 60441480Smckusick if (scsireq(&sd_softc[unit].sc_dq)) 60541480Smckusick sdstart(unit); 60641480Smckusick } 60741480Smckusick 60850039Skarels /* 60950039Skarels * Return: 61050039Skarels * 0 if not really an error 61150039Skarels * <0 if we should do a retry 61250039Skarels * >0 if a fatal error 61350039Skarels */ 61445750Smckusick static int 61541480Smckusick sderror(unit, sc, hp, stat) 61641480Smckusick int unit, stat; 61741480Smckusick register struct sd_softc *sc; 61841480Smckusick register struct hp_device *hp; 61941480Smckusick { 62050039Skarels int cond = 1; 62145750Smckusick 62241480Smckusick sdsense[unit].status = stat; 62341480Smckusick if (stat & STS_CHECKCOND) { 62441480Smckusick struct scsi_xsense *sp; 62541480Smckusick 62641480Smckusick scsi_request_sense(hp->hp_ctlr, hp->hp_slave, 62741480Smckusick sc->sc_punit, sdsense[unit].sense, 62841480Smckusick sizeof(sdsense[unit].sense)); 62941480Smckusick sp = (struct scsi_xsense *)sdsense[unit].sense; 63041480Smckusick printf("sd%d: scsi sense class %d, code %d", unit, 63141480Smckusick sp->class, sp->code); 63241480Smckusick if (sp->class == 7) { 63341480Smckusick printf(", key %d", sp->key); 63441480Smckusick if (sp->valid) 63541480Smckusick printf(", blk %d", *(int *)&sp->info1); 63650039Skarels switch (sp->key) { 63750039Skarels /* no sense, try again */ 63850039Skarels case 0: 63950039Skarels cond = -1; 64050039Skarels break; 64150039Skarels /* recovered error, not a problem */ 64250039Skarels case 1: 64350039Skarels cond = 0; 64450039Skarels break; 64557327Shibler /* possible media change */ 64657327Shibler case 6: 64757327Shibler /* 64857327Shibler * For removable media, if we are doing the 64957327Shibler * first open (i.e. reading the label) go 65057327Shibler * ahead and retry, otherwise someone has 65157327Shibler * changed the media out from under us and 65257327Shibler * we should abort any further operations 65357327Shibler * until a close is done. 65457327Shibler */ 65557327Shibler if (sc->sc_flags & SDF_RMEDIA) { 65657327Shibler if (sc->sc_flags & SDF_OPENING) 65757327Shibler cond = -1; 65857327Shibler else 65957327Shibler sc->sc_flags |= SDF_ERROR; 66057327Shibler } 66157327Shibler break; 66250039Skarels } 66341480Smckusick } 66441480Smckusick printf("\n"); 66541480Smckusick } 66650039Skarels return(cond); 66741480Smckusick } 66841480Smckusick 66941480Smckusick static void 67041480Smckusick sdfinish(unit, sc, bp) 67141480Smckusick int unit; 67241480Smckusick register struct sd_softc *sc; 67341480Smckusick register struct buf *bp; 67441480Smckusick { 67553929Shibler register struct buf *dp = &sdtab[unit]; 67653929Shibler 67753929Shibler dp->b_errcnt = 0; 67853929Shibler dp->b_actf = bp->b_actf; 67941480Smckusick bp->b_resid = 0; 68045750Smckusick biodone(bp); 68141480Smckusick scsifree(&sc->sc_dq); 68253929Shibler if (dp->b_actf) 68341480Smckusick sdustart(unit); 68453929Shibler else { 68553929Shibler dp->b_active = 0; 68653929Shibler if (sc->sc_flags & SDF_WANTED) { 68753929Shibler sc->sc_flags &= ~SDF_WANTED; 68853929Shibler wakeup((caddr_t)dp); 68953929Shibler } 69053929Shibler } 69141480Smckusick } 69241480Smckusick 69341480Smckusick void 69441480Smckusick sdstart(unit) 69541480Smckusick register int unit; 69641480Smckusick { 69741480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 69841480Smckusick register struct hp_device *hp = sc->sc_hd; 69941480Smckusick 70041480Smckusick /* 70141480Smckusick * we have the SCSI bus -- in format mode, we may or may not need dma 70241480Smckusick * so check now. 70341480Smckusick */ 70441480Smckusick if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) { 70541480Smckusick register struct buf *bp = sdtab[unit].b_actf; 70641480Smckusick register int sts; 70741480Smckusick 70841480Smckusick sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave, 70941480Smckusick sc->sc_punit, &sdcmd[unit], 71041480Smckusick bp->b_un.b_addr, bp->b_bcount, 71141480Smckusick bp->b_flags & B_READ); 71241480Smckusick sdsense[unit].status = sts; 71341480Smckusick if (sts & 0xfe) { 71445750Smckusick (void) sderror(unit, sc, hp, sts); 71541480Smckusick bp->b_flags |= B_ERROR; 71641480Smckusick bp->b_error = EIO; 71741480Smckusick } 71841480Smckusick sdfinish(unit, sc, bp); 71941480Smckusick 72041480Smckusick } else if (scsiustart(hp->hp_ctlr)) 72141480Smckusick sdgo(unit); 72241480Smckusick } 72341480Smckusick 72441480Smckusick void 72541480Smckusick sdgo(unit) 72641480Smckusick register int unit; 72741480Smckusick { 72841480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 72941480Smckusick register struct hp_device *hp = sc->sc_hd; 73041480Smckusick register struct buf *bp = sdtab[unit].b_actf; 73141480Smckusick register int pad; 73241480Smckusick register struct scsi_fmt_cdb *cmd; 73341480Smckusick 73457327Shibler /* 73557327Shibler * Drive is in an error state, abort all operations 73657327Shibler */ 73757327Shibler if (sc->sc_flags & SDF_ERROR) { 73857327Shibler bp->b_flags |= B_ERROR; 73957327Shibler bp->b_error = EIO; 74057327Shibler sdfinish(unit, sc, bp); 74157327Shibler return; 74257327Shibler } 74341480Smckusick if (sc->sc_format_pid) { 74441480Smckusick cmd = &sdcmd[unit]; 74541480Smckusick pad = 0; 74641480Smckusick } else { 74741480Smckusick cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd; 74841480Smckusick *(int *)(&cmd->cdb[2]) = bp->b_cylin; 74941480Smckusick pad = howmany(bp->b_bcount, sc->sc_blksize); 75041480Smckusick *(u_short *)(&cmd->cdb[7]) = pad; 75141480Smckusick pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0; 75241480Smckusick #ifdef DEBUG 75341480Smckusick if (pad) 75441480Smckusick printf("sd%d: partial block xfer -- %x bytes\n", 75541480Smckusick unit, bp->b_bcount); 75641480Smckusick #endif 75741480Smckusick sdstats[unit].sdtransfers++; 75841480Smckusick } 75957327Shibler #ifdef USELEDS 76057327Shibler if (inledcontrol == 0) 76157327Shibler ledcontrol(0, 0, LED_DISK); 76257327Shibler #endif 76341480Smckusick if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) { 76441480Smckusick if (hp->hp_dk >= 0) { 76541480Smckusick dk_busy |= 1 << hp->hp_dk; 76641480Smckusick ++dk_seek[hp->hp_dk]; 76741480Smckusick ++dk_xfer[hp->hp_dk]; 76841480Smckusick dk_wds[hp->hp_dk] += bp->b_bcount >> 6; 76941480Smckusick } 77041480Smckusick return; 77141480Smckusick } 77241480Smckusick #ifdef DEBUG 77341480Smckusick if (sddebug & SDB_ERROR) 77441480Smckusick printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n", 77541480Smckusick unit, bp->b_flags & B_READ? "read" : "write", 77641480Smckusick bp->b_un.b_addr, bp->b_cylin, bp->b_bcount, 77741480Smckusick sdtab[unit].b_errcnt); 77841480Smckusick #endif 77941480Smckusick bp->b_flags |= B_ERROR; 78041480Smckusick bp->b_error = EIO; 78141480Smckusick sdfinish(unit, sc, bp); 78241480Smckusick } 78341480Smckusick 78441480Smckusick void 78541480Smckusick sdintr(unit, stat) 78641480Smckusick register int unit; 78741480Smckusick int stat; 78841480Smckusick { 78941480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 79041480Smckusick register struct buf *bp = sdtab[unit].b_actf; 79141480Smckusick register struct hp_device *hp = sc->sc_hd; 79250039Skarels int cond; 79341480Smckusick 79441480Smckusick if (bp == NULL) { 79541480Smckusick printf("sd%d: bp == NULL\n", unit); 79641480Smckusick return; 79741480Smckusick } 79841480Smckusick if (hp->hp_dk >= 0) 79941480Smckusick dk_busy &=~ (1 << hp->hp_dk); 80041480Smckusick if (stat) { 80141480Smckusick #ifdef DEBUG 80241480Smckusick if (sddebug & SDB_ERROR) 80341480Smckusick printf("sd%d: sdintr: bad scsi status 0x%x\n", 80441480Smckusick unit, stat); 80541480Smckusick #endif 80650039Skarels cond = sderror(unit, sc, hp, stat); 80750039Skarels if (cond) { 80850039Skarels if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) { 80950038Skarels #ifdef DEBUG 81050039Skarels if (sddebug & SDB_ERROR) 81150039Skarels printf("sd%d: retry #%d\n", 81250039Skarels unit, sdtab[unit].b_errcnt); 81350038Skarels #endif 81450039Skarels sdstart(unit); 81550039Skarels return; 81650039Skarels } 81750039Skarels bp->b_flags |= B_ERROR; 81850039Skarels bp->b_error = EIO; 81945750Smckusick } 82041480Smckusick } 82141480Smckusick sdfinish(unit, sc, bp); 82241480Smckusick } 82341480Smckusick 82441480Smckusick int 82549132Skarels sdread(dev, uio, flags) 82641480Smckusick dev_t dev; 82741480Smckusick struct uio *uio; 82849132Skarels int flags; 82941480Smckusick { 83041480Smckusick register int unit = sdunit(dev); 83141480Smckusick register int pid; 83241480Smckusick 83349132Skarels if ((pid = sd_softc[unit].sc_format_pid) && 83449132Skarels pid != uio->uio_procp->p_pid) 83541480Smckusick return (EPERM); 83641480Smckusick 83749132Skarels return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio)); 83841480Smckusick } 83941480Smckusick 84041480Smckusick int 84149132Skarels sdwrite(dev, uio, flags) 84241480Smckusick dev_t dev; 84341480Smckusick struct uio *uio; 84449132Skarels int flags; 84541480Smckusick { 84641480Smckusick register int unit = sdunit(dev); 84741480Smckusick register int pid; 84841480Smckusick 84949132Skarels if ((pid = sd_softc[unit].sc_format_pid) && 85049132Skarels pid != uio->uio_procp->p_pid) 85141480Smckusick return (EPERM); 85241480Smckusick 85349132Skarels return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio)); 85441480Smckusick } 85541480Smckusick 85641480Smckusick int 85749132Skarels sdioctl(dev, cmd, data, flag, p) 85841480Smckusick dev_t dev; 85941480Smckusick int cmd; 86041480Smckusick caddr_t data; 86141480Smckusick int flag; 86249132Skarels struct proc *p; 86341480Smckusick { 86457327Shibler int unit = sdunit(dev); 86541480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 86657327Shibler register struct disklabel *lp = &sc->sc_info.si_label; 86757327Shibler int error, flags; 86841480Smckusick 86941480Smckusick switch (cmd) { 87041480Smckusick default: 87141480Smckusick return (EINVAL); 87241480Smckusick 87357327Shibler case DIOCGDINFO: 87457327Shibler *(struct disklabel *)data = *lp; 87557327Shibler return (0); 87657327Shibler 87757327Shibler case DIOCGPART: 87857327Shibler ((struct partinfo *)data)->disklab = lp; 87957327Shibler ((struct partinfo *)data)->part = 88057327Shibler &lp->d_partitions[sdpart(dev)]; 88157327Shibler return (0); 88257327Shibler 88357327Shibler case DIOCWLABEL: 88457327Shibler if ((flag & FWRITE) == 0) 88557327Shibler return (EBADF); 88657327Shibler if (*(int *)data) 88757327Shibler sc->sc_flags |= SDF_WLABEL; 88857327Shibler else 88957327Shibler sc->sc_flags &= ~SDF_WLABEL; 89057327Shibler return (0); 89157327Shibler 89257327Shibler case DIOCSDINFO: 89357327Shibler if ((flag & FWRITE) == 0) 89457327Shibler return (EBADF); 89557327Shibler error = setdisklabel(lp, (struct disklabel *)data, 89657327Shibler (sc->sc_flags & SDF_WLABEL) ? 0 89757327Shibler : sc->sc_info.si_open); 89857327Shibler return (error); 89957327Shibler 90057327Shibler case DIOCWDINFO: 90157327Shibler if ((flag & FWRITE) == 0) 90257327Shibler return (EBADF); 90357327Shibler error = setdisklabel(lp, (struct disklabel *)data, 90457327Shibler (sc->sc_flags & SDF_WLABEL) ? 0 90557327Shibler : sc->sc_info.si_open); 90657327Shibler if (error) 90757327Shibler return (error); 90857327Shibler flags = sc->sc_flags; 90957327Shibler sc->sc_flags = SDF_ALIVE | SDF_WLABEL; 91057327Shibler error = writedisklabel(sdlabdev(dev), sdstrategy, lp); 91157327Shibler sc->sc_flags = flags; 91257327Shibler return (error); 91357327Shibler 91441480Smckusick case SDIOCSFORMAT: 91541480Smckusick /* take this device into or out of "format" mode */ 91649132Skarels if (suser(p->p_ucred, &p->p_acflag)) 91741480Smckusick return(EPERM); 91841480Smckusick 91941480Smckusick if (*(int *)data) { 92041480Smckusick if (sc->sc_format_pid) 92141480Smckusick return (EPERM); 92249132Skarels sc->sc_format_pid = p->p_pid; 92341480Smckusick } else 92441480Smckusick sc->sc_format_pid = 0; 92541480Smckusick return (0); 92641480Smckusick 92741480Smckusick case SDIOCGFORMAT: 92841480Smckusick /* find out who has the device in format mode */ 92941480Smckusick *(int *)data = sc->sc_format_pid; 93041480Smckusick return (0); 93141480Smckusick 93241480Smckusick case SDIOCSCSICOMMAND: 93341480Smckusick /* 93441480Smckusick * Save what user gave us as SCSI cdb to use with next 93541480Smckusick * read or write to the char device. 93641480Smckusick */ 93749132Skarels if (sc->sc_format_pid != p->p_pid) 93841480Smckusick return (EPERM); 93941480Smckusick if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) 94041480Smckusick return (EINVAL); 94141480Smckusick bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0])); 94241480Smckusick return (0); 94341480Smckusick 94441480Smckusick case SDIOCSENSE: 94541480Smckusick /* 94641480Smckusick * return the SCSI sense data saved after the last 94741480Smckusick * operation that completed with "check condition" status. 94841480Smckusick */ 94941480Smckusick bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0])); 95041480Smckusick return (0); 95141480Smckusick 95241480Smckusick } 95341480Smckusick /*NOTREACHED*/ 95441480Smckusick } 95541480Smckusick 95641480Smckusick int 95741480Smckusick sdsize(dev) 95841480Smckusick dev_t dev; 95941480Smckusick { 96041480Smckusick register int unit = sdunit(dev); 96141480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 96257327Shibler int psize, didopen = 0; 96341480Smckusick 96441480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 96541480Smckusick return(-1); 96641480Smckusick 96757327Shibler /* 96857327Shibler * We get called very early on (via swapconf) 96957327Shibler * without the device being open so we may need 97057327Shibler * to handle it here. 97157327Shibler */ 97257327Shibler if (sc->sc_info.si_open == 0) { 97357327Shibler if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) 97457327Shibler return(-1); 97557327Shibler didopen = 1; 97657327Shibler } 97757327Shibler psize = sc->sc_info.si_label.d_partitions[sdpart(dev)].p_size; 97857327Shibler if (didopen) 97957327Shibler (void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); 98057327Shibler return (psize); 98141480Smckusick } 98241480Smckusick 98341480Smckusick /* 98441480Smckusick * Non-interrupt driven, non-dma dump routine. 98541480Smckusick */ 98641480Smckusick int 98741480Smckusick sddump(dev) 98841480Smckusick dev_t dev; 98941480Smckusick { 99041480Smckusick int part = sdpart(dev); 99141480Smckusick int unit = sdunit(dev); 99241480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 99341480Smckusick register struct hp_device *hp = sc->sc_hd; 99457327Shibler register struct partition *pinfo; 99541480Smckusick register daddr_t baddr; 99641480Smckusick register int maddr; 99741480Smckusick register int pages, i; 99841480Smckusick int stat; 99941480Smckusick extern int lowram; 100041480Smckusick 100141480Smckusick /* is drive ok? */ 100241480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 100341480Smckusick return (ENXIO); 100457327Shibler pinfo = &sc->sc_info.si_label.d_partitions[part]; 100541480Smckusick /* dump parameters in range? */ 100657327Shibler if (dumplo < 0 || dumplo >= pinfo->p_size || 100757327Shibler pinfo->p_fstype != FS_SWAP) 100841480Smckusick return (EINVAL); 100957327Shibler pages = physmem; 101057327Shibler if (dumplo + ctod(pages) > pinfo->p_size) 101157327Shibler pages = dtoc(pinfo->p_size - dumplo); 101241480Smckusick maddr = lowram; 101357327Shibler baddr = dumplo + pinfo->p_offset; 101441480Smckusick /* scsi bus idle? */ 101541480Smckusick if (!scsireq(&sc->sc_dq)) { 101641480Smckusick scsireset(hp->hp_ctlr); 101741480Smckusick sdreset(sc, sc->sc_hd); 101841480Smckusick printf("[ drive %d reset ] ", unit); 101941480Smckusick } 102041480Smckusick for (i = 0; i < pages; i++) { 102141480Smckusick #define NPGMB (1024*1024/NBPG) 102241480Smckusick /* print out how many Mbs we have dumped */ 102341480Smckusick if (i && (i % NPGMB) == 0) 102441480Smckusick printf("%d ", i / NPGMB); 102541480Smckusick #undef NPBMG 102652614Smckusick pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr, 102751576Smckusick VM_PROT_READ, TRUE); 102841480Smckusick stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, 102941480Smckusick vmmap, NBPG, baddr, sc->sc_bshift); 103041480Smckusick if (stat) { 103141480Smckusick printf("sddump: scsi write error 0x%x\n", stat); 103241480Smckusick return (EIO); 103341480Smckusick } 103441480Smckusick maddr += NBPG; 103541480Smckusick baddr += ctod(1); 103641480Smckusick } 103741480Smckusick return (0); 103841480Smckusick } 103941480Smckusick #endif 1040