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*57327Shibler * @(#)sd.c 7.17 (Berkeley) 12/27/92 1141480Smckusick */ 1241480Smckusick 1341480Smckusick /* 1441480Smckusick * SCSI CCS (Command Command Set) disk driver. 1541480Smckusick */ 1641480Smckusick #include "sd.h" 1741480Smckusick #if NSD > 0 1841480Smckusick 1941480Smckusick #ifndef lint 20*57327Shibler 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> 26*57327Shibler #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> 32*57327Shibler #include <sys/fcntl.h> 3341480Smckusick 3456507Sbostic #include <hp/dev/device.h> 3556507Sbostic #include <hp300/dev/scsireg.h> 36*57327Shibler #include <hp300/dev/sdvar.h> 37*57327Shibler #ifdef USELEDS 38*57327Shibler #include <hp300/hp300/led.h> 39*57327Shibler #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 76*57327Shibler struct sd_softc sd_softc[NSD]; 77*57327Shibler 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 */ 191*57327Shibler switch (inqbuf.version) { 192*57327Shibler case 1: 193*57327Shibler 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; 207*57327Shibler break; 208*57327Shibler default: 209*57327Shibler bcopy("UNKNOWN", &idstr[0], 8); 210*57327Shibler 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 229*57327Shibler switch (inqbuf.version) { 230*57327Shibler case 1: 231*57327Shibler case 2: 23241480Smckusick printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8], 23341480Smckusick &idstr[24]); 234*57327Shibler if (inqbuf.version == 2) 235*57327Shibler printf(" (SCSI-2)"); 236*57327Shibler break; 237*57327Shibler default: 238*57327Shibler printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit, 239*57327Shibler inqbuf.type, inqbuf.qual, inqbuf.version); 240*57327Shibler break; 241*57327Shibler } 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 292*57327Shibler /* 293*57327Shibler * Read or constuct a disklabel 294*57327Shibler */ 29541480Smckusick int 296*57327Shibler sdgetinfo(dev) 297*57327Shibler dev_t dev; 298*57327Shibler { 299*57327Shibler int unit = sdunit(dev); 300*57327Shibler register struct sd_softc *sc = &sd_softc[unit]; 301*57327Shibler register struct disklabel *lp = &sc->sc_info.si_label; 302*57327Shibler register struct partition *pi; 303*57327Shibler char *msg, *readdisklabel(); 304*57327Shibler 305*57327Shibler /* 306*57327Shibler * Set some default values to use while reading the label 307*57327Shibler * or to use if there isn't a label. 308*57327Shibler */ 309*57327Shibler bzero((caddr_t)lp, sizeof *lp); 310*57327Shibler lp->d_type = DTYPE_SCSI; 311*57327Shibler lp->d_secsize = DEV_BSIZE; 312*57327Shibler lp->d_nsectors = 32; 313*57327Shibler lp->d_ntracks = 20; 314*57327Shibler lp->d_secpercyl = 32*20; 315*57327Shibler lp->d_npartitions = 3; 316*57327Shibler lp->d_partitions[2].p_offset = 0; 317*57327Shibler /* XXX ensure size is at least one device block */ 318*57327Shibler lp->d_partitions[2].p_size = 319*57327Shibler roundup(LABELSECTOR+1, btodb(sc->sc_blksize)); 320*57327Shibler 321*57327Shibler /* 322*57327Shibler * Now try to read the disklabel 323*57327Shibler */ 324*57327Shibler msg = readdisklabel(sdlabdev(dev), sdstrategy, lp); 325*57327Shibler if (msg == NULL) 326*57327Shibler return(0); 327*57327Shibler if (bcmp(msg, "I/O", 3) == 0) /* XXX */ 328*57327Shibler return(EIO); 329*57327Shibler 330*57327Shibler pi = lp->d_partitions; 331*57327Shibler printf("sd%d: WARNING: %s, ", unit, msg); 332*57327Shibler #ifdef COMPAT_NOLABEL 333*57327Shibler printf("using old default partitioning\n"); 334*57327Shibler sdmakedisklabel(unit, lp); 335*57327Shibler #else 336*57327Shibler printf("defining `c' partition as entire disk\n"); 337*57327Shibler pi[2].p_size = sc->sc_blks; 338*57327Shibler #endif 339*57327Shibler return(0); 340*57327Shibler } 341*57327Shibler 342*57327Shibler int 34349132Skarels sdopen(dev, flags, mode, p) 34441480Smckusick dev_t dev; 34549132Skarels int flags, mode; 34649132Skarels struct proc *p; 34741480Smckusick { 34841480Smckusick register int unit = sdunit(dev); 34941480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 350*57327Shibler int mask, error; 35141480Smckusick 35241480Smckusick if (unit >= NSD) 35341480Smckusick return(ENXIO); 35449132Skarels if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag)) 35541480Smckusick return(ENXIO); 356*57327Shibler if (sc->sc_flags & SDF_ERROR) 357*57327Shibler return(EIO); 35841480Smckusick 359*57327Shibler /* 360*57327Shibler * Wait for any pending opens/closes to complete 361*57327Shibler */ 362*57327Shibler while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING)) 363*57327Shibler sleep((caddr_t)sc, PRIBIO); 364*57327Shibler /* 365*57327Shibler * On first open, get label and partition info. 366*57327Shibler * We may block reading the label, so be careful 367*57327Shibler * to stop any other opens. 368*57327Shibler */ 369*57327Shibler if (sc->sc_info.si_open == 0) { 370*57327Shibler sc->sc_flags |= SDF_OPENING; 371*57327Shibler error = sdgetinfo(dev); 372*57327Shibler sc->sc_flags &= ~SDF_OPENING; 373*57327Shibler wakeup((caddr_t)sc); 374*57327Shibler if (error) 375*57327Shibler return(error); 376*57327Shibler } 37741480Smckusick if (sc->sc_hd->hp_dk >= 0) 37841480Smckusick dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms; 379*57327Shibler 380*57327Shibler mask = 1 << sdpart(dev); 381*57327Shibler if (mode == S_IFCHR) 382*57327Shibler sc->sc_info.si_copen |= mask; 383*57327Shibler else 384*57327Shibler sc->sc_info.si_bopen |= mask; 385*57327Shibler sc->sc_info.si_open |= mask; 38641480Smckusick return(0); 38741480Smckusick } 38841480Smckusick 38953929Shibler int 39053929Shibler sdclose(dev, flag, mode, p) 39153929Shibler dev_t dev; 39253929Shibler int flag, mode; 39353929Shibler struct proc *p; 39453929Shibler { 39553929Shibler int unit = sdunit(dev); 39653929Shibler register struct sd_softc *sc = &sd_softc[unit]; 397*57327Shibler register struct sdinfo *si = &sc->sc_info; 398*57327Shibler int mask, s; 39953929Shibler 400*57327Shibler mask = 1 << sdpart(dev); 401*57327Shibler if (mode == S_IFCHR) 402*57327Shibler si->si_copen &= ~mask; 403*57327Shibler else 404*57327Shibler si->si_bopen &= ~mask; 405*57327Shibler si->si_open = si->si_bopen | si->si_copen; 40653929Shibler /* 407*57327Shibler * On last close, we wait for all activity to cease since 408*57327Shibler * the label/parition info will become invalid. Since we 409*57327Shibler * might sleep, we must block any opens while we are here. 410*57327Shibler * Note we don't have to about other closes since we know 411*57327Shibler * we are the last one. 41253929Shibler */ 413*57327Shibler if (si->si_open == 0) { 414*57327Shibler sc->sc_flags |= SDF_CLOSING; 41553929Shibler s = splbio(); 41653929Shibler while (sdtab[unit].b_active) { 41753929Shibler sc->sc_flags |= SDF_WANTED; 41853929Shibler sleep((caddr_t)&sdtab[unit], PRIBIO); 41953929Shibler } 42053929Shibler splx(s); 421*57327Shibler sc->sc_flags &= ~(SDF_CLOSING|SDF_WLABEL|SDF_ERROR); 422*57327Shibler wakeup((caddr_t)sc); 42353929Shibler } 42453929Shibler sc->sc_format_pid = 0; 425*57327Shibler return(0); 42653929Shibler } 42753929Shibler 42841480Smckusick /* 42941480Smckusick * This routine is called for partial block transfers and non-aligned 43041480Smckusick * transfers (the latter only being possible on devices with a block size 43141480Smckusick * larger than DEV_BSIZE). The operation is performed in three steps 43241480Smckusick * using a locally allocated buffer: 43341480Smckusick * 1. transfer any initial partial block 43441480Smckusick * 2. transfer full blocks 43541480Smckusick * 3. transfer any final partial block 43641480Smckusick */ 43741480Smckusick static void 43841480Smckusick sdlblkstrat(bp, bsize) 43941480Smckusick register struct buf *bp; 44041480Smckusick register int bsize; 44141480Smckusick { 44241480Smckusick register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf), 44341480Smckusick M_DEVBUF, M_WAITOK); 44441480Smckusick caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); 44541480Smckusick register int bn, resid; 44641480Smckusick register caddr_t addr; 44741480Smckusick 44841480Smckusick bzero((caddr_t)cbp, sizeof(*cbp)); 44949132Skarels cbp->b_proc = curproc; /* XXX */ 45041480Smckusick cbp->b_dev = bp->b_dev; 45141480Smckusick bn = bp->b_blkno; 45241480Smckusick resid = bp->b_bcount; 45341480Smckusick addr = bp->b_un.b_addr; 45441480Smckusick #ifdef DEBUG 45541480Smckusick if (sddebug & SDB_PARTIAL) 45641480Smckusick printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", 45741480Smckusick bp, bp->b_flags, bn, resid, addr); 45841480Smckusick #endif 45941480Smckusick 46041480Smckusick while (resid > 0) { 46141480Smckusick register int boff = dbtob(bn) & (bsize - 1); 46241480Smckusick register int count; 46341480Smckusick 46441480Smckusick if (boff || resid < bsize) { 46541480Smckusick sdstats[sdunit(bp->b_dev)].sdpartials++; 46655068Spendry count = min(resid, bsize - boff); 46741480Smckusick cbp->b_flags = B_BUSY | B_PHYS | B_READ; 46841480Smckusick cbp->b_blkno = bn - btodb(boff); 46941480Smckusick cbp->b_un.b_addr = cbuf; 47041480Smckusick cbp->b_bcount = bsize; 47141480Smckusick #ifdef DEBUG 47241480Smckusick if (sddebug & SDB_PARTIAL) 47341480Smckusick printf(" readahead: bn %x cnt %x off %x addr %x\n", 47441480Smckusick cbp->b_blkno, count, boff, addr); 47541480Smckusick #endif 47641480Smckusick sdstrategy(cbp); 47741480Smckusick biowait(cbp); 47841480Smckusick if (cbp->b_flags & B_ERROR) { 47941480Smckusick bp->b_flags |= B_ERROR; 48041480Smckusick bp->b_error = cbp->b_error; 48141480Smckusick break; 48241480Smckusick } 48341480Smckusick if (bp->b_flags & B_READ) { 48441480Smckusick bcopy(&cbuf[boff], addr, count); 48541480Smckusick goto done; 48641480Smckusick } 48741480Smckusick bcopy(addr, &cbuf[boff], count); 48841480Smckusick #ifdef DEBUG 48941480Smckusick if (sddebug & SDB_PARTIAL) 49041480Smckusick printf(" writeback: bn %x cnt %x off %x addr %x\n", 49141480Smckusick cbp->b_blkno, count, boff, addr); 49241480Smckusick #endif 49341480Smckusick } else { 49441480Smckusick count = resid & ~(bsize - 1); 49541480Smckusick cbp->b_blkno = bn; 49641480Smckusick cbp->b_un.b_addr = addr; 49741480Smckusick cbp->b_bcount = count; 49841480Smckusick #ifdef DEBUG 49941480Smckusick if (sddebug & SDB_PARTIAL) 50041480Smckusick printf(" fulltrans: bn %x cnt %x addr %x\n", 50141480Smckusick cbp->b_blkno, count, addr); 50241480Smckusick #endif 50341480Smckusick } 50441480Smckusick cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); 50541480Smckusick sdstrategy(cbp); 50641480Smckusick biowait(cbp); 50741480Smckusick if (cbp->b_flags & B_ERROR) { 50841480Smckusick bp->b_flags |= B_ERROR; 50941480Smckusick bp->b_error = cbp->b_error; 51041480Smckusick break; 51141480Smckusick } 51241480Smckusick done: 51341480Smckusick bn += btodb(count); 51441480Smckusick resid -= count; 51541480Smckusick addr += count; 51641480Smckusick #ifdef DEBUG 51741480Smckusick if (sddebug & SDB_PARTIAL) 51841480Smckusick printf(" done: bn %x resid %x addr %x\n", 51941480Smckusick bn, resid, addr); 52041480Smckusick #endif 52141480Smckusick } 52241480Smckusick free(cbuf, M_DEVBUF); 52341480Smckusick free(cbp, M_DEVBUF); 52441480Smckusick } 52541480Smckusick 52641480Smckusick void 52741480Smckusick sdstrategy(bp) 52841480Smckusick register struct buf *bp; 52941480Smckusick { 530*57327Shibler int unit = sdunit(bp->b_dev); 53141480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 53241480Smckusick register struct buf *dp = &sdtab[unit]; 533*57327Shibler register struct partition *pinfo; 53445750Smckusick register daddr_t bn; 53545750Smckusick register int sz, s; 53641480Smckusick 537*57327Shibler if (sc->sc_flags & SDF_ERROR) { 538*57327Shibler bp->b_error = EIO; 539*57327Shibler goto bad; 540*57327Shibler } 54141480Smckusick if (sc->sc_format_pid) { 54249132Skarels if (sc->sc_format_pid != curproc->p_pid) { /* XXX */ 54341480Smckusick bp->b_error = EPERM; 544*57327Shibler goto bad; 54541480Smckusick } 54641480Smckusick bp->b_cylin = 0; 54741480Smckusick } else { 54841480Smckusick bn = bp->b_blkno; 54945750Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 550*57327Shibler pinfo = &sc->sc_info.si_label.d_partitions[sdpart(bp->b_dev)]; 551*57327Shibler if (bn < 0 || bn + sz > pinfo->p_size) { 552*57327Shibler sz = pinfo->p_size - bn; 55345750Smckusick if (sz == 0) { 55441480Smckusick bp->b_resid = bp->b_bcount; 55541480Smckusick goto done; 55641480Smckusick } 55745750Smckusick if (sz < 0) { 55845750Smckusick bp->b_error = EINVAL; 559*57327Shibler goto bad; 56045750Smckusick } 56145750Smckusick bp->b_bcount = dbtob(sz); 56241480Smckusick } 56341480Smckusick /* 564*57327Shibler * Check for write to write protected label 565*57327Shibler */ 566*57327Shibler if (bn + pinfo->p_offset <= LABELSECTOR && 567*57327Shibler #if LABELSECTOR != 0 568*57327Shibler bn + pinfo->p_offset + sz > LABELSECTOR && 569*57327Shibler #endif 570*57327Shibler !(bp->b_flags & B_READ) && !(sc->sc_flags & SDF_WLABEL)) { 571*57327Shibler bp->b_error = EROFS; 572*57327Shibler goto bad; 573*57327Shibler } 574*57327Shibler /* 57541480Smckusick * Non-aligned or partial-block transfers handled specially. 57641480Smckusick */ 57741480Smckusick s = sc->sc_blksize - 1; 57841480Smckusick if ((dbtob(bn) & s) || (bp->b_bcount & s)) { 57941480Smckusick sdlblkstrat(bp, sc->sc_blksize); 58041480Smckusick goto done; 58141480Smckusick } 582*57327Shibler bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift; 58341480Smckusick } 58441480Smckusick s = splbio(); 58541480Smckusick disksort(dp, bp); 58641480Smckusick if (dp->b_active == 0) { 58741480Smckusick dp->b_active = 1; 58841480Smckusick sdustart(unit); 58941480Smckusick } 59041480Smckusick splx(s); 59141480Smckusick return; 592*57327Shibler bad: 593*57327Shibler bp->b_flags |= B_ERROR; 59441480Smckusick done: 59545750Smckusick biodone(bp); 59641480Smckusick } 59741480Smckusick 59841480Smckusick void 59941480Smckusick sdustart(unit) 60041480Smckusick register int unit; 60141480Smckusick { 60241480Smckusick if (scsireq(&sd_softc[unit].sc_dq)) 60341480Smckusick sdstart(unit); 60441480Smckusick } 60541480Smckusick 60650039Skarels /* 60750039Skarels * Return: 60850039Skarels * 0 if not really an error 60950039Skarels * <0 if we should do a retry 61050039Skarels * >0 if a fatal error 61150039Skarels */ 61245750Smckusick static int 61341480Smckusick sderror(unit, sc, hp, stat) 61441480Smckusick int unit, stat; 61541480Smckusick register struct sd_softc *sc; 61641480Smckusick register struct hp_device *hp; 61741480Smckusick { 61850039Skarels int cond = 1; 61945750Smckusick 62041480Smckusick sdsense[unit].status = stat; 62141480Smckusick if (stat & STS_CHECKCOND) { 62241480Smckusick struct scsi_xsense *sp; 62341480Smckusick 62441480Smckusick scsi_request_sense(hp->hp_ctlr, hp->hp_slave, 62541480Smckusick sc->sc_punit, sdsense[unit].sense, 62641480Smckusick sizeof(sdsense[unit].sense)); 62741480Smckusick sp = (struct scsi_xsense *)sdsense[unit].sense; 62841480Smckusick printf("sd%d: scsi sense class %d, code %d", unit, 62941480Smckusick sp->class, sp->code); 63041480Smckusick if (sp->class == 7) { 63141480Smckusick printf(", key %d", sp->key); 63241480Smckusick if (sp->valid) 63341480Smckusick printf(", blk %d", *(int *)&sp->info1); 63450039Skarels switch (sp->key) { 63550039Skarels /* no sense, try again */ 63650039Skarels case 0: 63750039Skarels cond = -1; 63850039Skarels break; 63950039Skarels /* recovered error, not a problem */ 64050039Skarels case 1: 64150039Skarels cond = 0; 64250039Skarels break; 643*57327Shibler /* possible media change */ 644*57327Shibler case 6: 645*57327Shibler /* 646*57327Shibler * For removable media, if we are doing the 647*57327Shibler * first open (i.e. reading the label) go 648*57327Shibler * ahead and retry, otherwise someone has 649*57327Shibler * changed the media out from under us and 650*57327Shibler * we should abort any further operations 651*57327Shibler * until a close is done. 652*57327Shibler */ 653*57327Shibler if (sc->sc_flags & SDF_RMEDIA) { 654*57327Shibler if (sc->sc_flags & SDF_OPENING) 655*57327Shibler cond = -1; 656*57327Shibler else 657*57327Shibler sc->sc_flags |= SDF_ERROR; 658*57327Shibler } 659*57327Shibler break; 66050039Skarels } 66141480Smckusick } 66241480Smckusick printf("\n"); 66341480Smckusick } 66450039Skarels return(cond); 66541480Smckusick } 66641480Smckusick 66741480Smckusick static void 66841480Smckusick sdfinish(unit, sc, bp) 66941480Smckusick int unit; 67041480Smckusick register struct sd_softc *sc; 67141480Smckusick register struct buf *bp; 67241480Smckusick { 67353929Shibler register struct buf *dp = &sdtab[unit]; 67453929Shibler 67553929Shibler dp->b_errcnt = 0; 67653929Shibler dp->b_actf = bp->b_actf; 67741480Smckusick bp->b_resid = 0; 67845750Smckusick biodone(bp); 67941480Smckusick scsifree(&sc->sc_dq); 68053929Shibler if (dp->b_actf) 68141480Smckusick sdustart(unit); 68253929Shibler else { 68353929Shibler dp->b_active = 0; 68453929Shibler if (sc->sc_flags & SDF_WANTED) { 68553929Shibler sc->sc_flags &= ~SDF_WANTED; 68653929Shibler wakeup((caddr_t)dp); 68753929Shibler } 68853929Shibler } 68941480Smckusick } 69041480Smckusick 69141480Smckusick void 69241480Smckusick sdstart(unit) 69341480Smckusick register int unit; 69441480Smckusick { 69541480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 69641480Smckusick register struct hp_device *hp = sc->sc_hd; 69741480Smckusick 69841480Smckusick /* 69941480Smckusick * we have the SCSI bus -- in format mode, we may or may not need dma 70041480Smckusick * so check now. 70141480Smckusick */ 70241480Smckusick if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) { 70341480Smckusick register struct buf *bp = sdtab[unit].b_actf; 70441480Smckusick register int sts; 70541480Smckusick 70641480Smckusick sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave, 70741480Smckusick sc->sc_punit, &sdcmd[unit], 70841480Smckusick bp->b_un.b_addr, bp->b_bcount, 70941480Smckusick bp->b_flags & B_READ); 71041480Smckusick sdsense[unit].status = sts; 71141480Smckusick if (sts & 0xfe) { 71245750Smckusick (void) sderror(unit, sc, hp, sts); 71341480Smckusick bp->b_flags |= B_ERROR; 71441480Smckusick bp->b_error = EIO; 71541480Smckusick } 71641480Smckusick sdfinish(unit, sc, bp); 71741480Smckusick 71841480Smckusick } else if (scsiustart(hp->hp_ctlr)) 71941480Smckusick sdgo(unit); 72041480Smckusick } 72141480Smckusick 72241480Smckusick void 72341480Smckusick sdgo(unit) 72441480Smckusick register int unit; 72541480Smckusick { 72641480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 72741480Smckusick register struct hp_device *hp = sc->sc_hd; 72841480Smckusick register struct buf *bp = sdtab[unit].b_actf; 72941480Smckusick register int pad; 73041480Smckusick register struct scsi_fmt_cdb *cmd; 73141480Smckusick 732*57327Shibler /* 733*57327Shibler * Drive is in an error state, abort all operations 734*57327Shibler */ 735*57327Shibler if (sc->sc_flags & SDF_ERROR) { 736*57327Shibler bp->b_flags |= B_ERROR; 737*57327Shibler bp->b_error = EIO; 738*57327Shibler sdfinish(unit, sc, bp); 739*57327Shibler return; 740*57327Shibler } 74141480Smckusick if (sc->sc_format_pid) { 74241480Smckusick cmd = &sdcmd[unit]; 74341480Smckusick pad = 0; 74441480Smckusick } else { 74541480Smckusick cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd; 74641480Smckusick *(int *)(&cmd->cdb[2]) = bp->b_cylin; 74741480Smckusick pad = howmany(bp->b_bcount, sc->sc_blksize); 74841480Smckusick *(u_short *)(&cmd->cdb[7]) = pad; 74941480Smckusick pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0; 75041480Smckusick #ifdef DEBUG 75141480Smckusick if (pad) 75241480Smckusick printf("sd%d: partial block xfer -- %x bytes\n", 75341480Smckusick unit, bp->b_bcount); 75441480Smckusick #endif 75541480Smckusick sdstats[unit].sdtransfers++; 75641480Smckusick } 757*57327Shibler #ifdef USELEDS 758*57327Shibler if (inledcontrol == 0) 759*57327Shibler ledcontrol(0, 0, LED_DISK); 760*57327Shibler #endif 76141480Smckusick if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) { 76241480Smckusick if (hp->hp_dk >= 0) { 76341480Smckusick dk_busy |= 1 << hp->hp_dk; 76441480Smckusick ++dk_seek[hp->hp_dk]; 76541480Smckusick ++dk_xfer[hp->hp_dk]; 76641480Smckusick dk_wds[hp->hp_dk] += bp->b_bcount >> 6; 76741480Smckusick } 76841480Smckusick return; 76941480Smckusick } 77041480Smckusick #ifdef DEBUG 77141480Smckusick if (sddebug & SDB_ERROR) 77241480Smckusick printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n", 77341480Smckusick unit, bp->b_flags & B_READ? "read" : "write", 77441480Smckusick bp->b_un.b_addr, bp->b_cylin, bp->b_bcount, 77541480Smckusick sdtab[unit].b_errcnt); 77641480Smckusick #endif 77741480Smckusick bp->b_flags |= B_ERROR; 77841480Smckusick bp->b_error = EIO; 77941480Smckusick sdfinish(unit, sc, bp); 78041480Smckusick } 78141480Smckusick 78241480Smckusick void 78341480Smckusick sdintr(unit, stat) 78441480Smckusick register int unit; 78541480Smckusick int stat; 78641480Smckusick { 78741480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 78841480Smckusick register struct buf *bp = sdtab[unit].b_actf; 78941480Smckusick register struct hp_device *hp = sc->sc_hd; 79050039Skarels int cond; 79141480Smckusick 79241480Smckusick if (bp == NULL) { 79341480Smckusick printf("sd%d: bp == NULL\n", unit); 79441480Smckusick return; 79541480Smckusick } 79641480Smckusick if (hp->hp_dk >= 0) 79741480Smckusick dk_busy &=~ (1 << hp->hp_dk); 79841480Smckusick if (stat) { 79941480Smckusick #ifdef DEBUG 80041480Smckusick if (sddebug & SDB_ERROR) 80141480Smckusick printf("sd%d: sdintr: bad scsi status 0x%x\n", 80241480Smckusick unit, stat); 80341480Smckusick #endif 80450039Skarels cond = sderror(unit, sc, hp, stat); 80550039Skarels if (cond) { 80650039Skarels if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) { 80750038Skarels #ifdef DEBUG 80850039Skarels if (sddebug & SDB_ERROR) 80950039Skarels printf("sd%d: retry #%d\n", 81050039Skarels unit, sdtab[unit].b_errcnt); 81150038Skarels #endif 81250039Skarels sdstart(unit); 81350039Skarels return; 81450039Skarels } 81550039Skarels bp->b_flags |= B_ERROR; 81650039Skarels bp->b_error = EIO; 81745750Smckusick } 81841480Smckusick } 81941480Smckusick sdfinish(unit, sc, bp); 82041480Smckusick } 82141480Smckusick 82241480Smckusick int 82349132Skarels sdread(dev, uio, flags) 82441480Smckusick dev_t dev; 82541480Smckusick struct uio *uio; 82649132Skarels int flags; 82741480Smckusick { 82841480Smckusick register int unit = sdunit(dev); 82941480Smckusick register int pid; 83041480Smckusick 83149132Skarels if ((pid = sd_softc[unit].sc_format_pid) && 83249132Skarels pid != uio->uio_procp->p_pid) 83341480Smckusick return (EPERM); 83441480Smckusick 83549132Skarels return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio)); 83641480Smckusick } 83741480Smckusick 83841480Smckusick int 83949132Skarels sdwrite(dev, uio, flags) 84041480Smckusick dev_t dev; 84141480Smckusick struct uio *uio; 84249132Skarels int flags; 84341480Smckusick { 84441480Smckusick register int unit = sdunit(dev); 84541480Smckusick register int pid; 84641480Smckusick 84749132Skarels if ((pid = sd_softc[unit].sc_format_pid) && 84849132Skarels pid != uio->uio_procp->p_pid) 84941480Smckusick return (EPERM); 85041480Smckusick 85149132Skarels return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio)); 85241480Smckusick } 85341480Smckusick 85441480Smckusick int 85549132Skarels sdioctl(dev, cmd, data, flag, p) 85641480Smckusick dev_t dev; 85741480Smckusick int cmd; 85841480Smckusick caddr_t data; 85941480Smckusick int flag; 86049132Skarels struct proc *p; 86141480Smckusick { 862*57327Shibler int unit = sdunit(dev); 86341480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 864*57327Shibler register struct disklabel *lp = &sc->sc_info.si_label; 865*57327Shibler int error, flags; 86641480Smckusick 86741480Smckusick switch (cmd) { 86841480Smckusick default: 86941480Smckusick return (EINVAL); 87041480Smckusick 871*57327Shibler case DIOCGDINFO: 872*57327Shibler *(struct disklabel *)data = *lp; 873*57327Shibler return (0); 874*57327Shibler 875*57327Shibler case DIOCGPART: 876*57327Shibler ((struct partinfo *)data)->disklab = lp; 877*57327Shibler ((struct partinfo *)data)->part = 878*57327Shibler &lp->d_partitions[sdpart(dev)]; 879*57327Shibler return (0); 880*57327Shibler 881*57327Shibler case DIOCWLABEL: 882*57327Shibler if ((flag & FWRITE) == 0) 883*57327Shibler return (EBADF); 884*57327Shibler if (*(int *)data) 885*57327Shibler sc->sc_flags |= SDF_WLABEL; 886*57327Shibler else 887*57327Shibler sc->sc_flags &= ~SDF_WLABEL; 888*57327Shibler return (0); 889*57327Shibler 890*57327Shibler case DIOCSDINFO: 891*57327Shibler if ((flag & FWRITE) == 0) 892*57327Shibler return (EBADF); 893*57327Shibler error = setdisklabel(lp, (struct disklabel *)data, 894*57327Shibler (sc->sc_flags & SDF_WLABEL) ? 0 895*57327Shibler : sc->sc_info.si_open); 896*57327Shibler return (error); 897*57327Shibler 898*57327Shibler case DIOCWDINFO: 899*57327Shibler if ((flag & FWRITE) == 0) 900*57327Shibler return (EBADF); 901*57327Shibler error = setdisklabel(lp, (struct disklabel *)data, 902*57327Shibler (sc->sc_flags & SDF_WLABEL) ? 0 903*57327Shibler : sc->sc_info.si_open); 904*57327Shibler if (error) 905*57327Shibler return (error); 906*57327Shibler flags = sc->sc_flags; 907*57327Shibler sc->sc_flags = SDF_ALIVE | SDF_WLABEL; 908*57327Shibler error = writedisklabel(sdlabdev(dev), sdstrategy, lp); 909*57327Shibler sc->sc_flags = flags; 910*57327Shibler return (error); 911*57327Shibler 91241480Smckusick case SDIOCSFORMAT: 91341480Smckusick /* take this device into or out of "format" mode */ 91449132Skarels if (suser(p->p_ucred, &p->p_acflag)) 91541480Smckusick return(EPERM); 91641480Smckusick 91741480Smckusick if (*(int *)data) { 91841480Smckusick if (sc->sc_format_pid) 91941480Smckusick return (EPERM); 92049132Skarels sc->sc_format_pid = p->p_pid; 92141480Smckusick } else 92241480Smckusick sc->sc_format_pid = 0; 92341480Smckusick return (0); 92441480Smckusick 92541480Smckusick case SDIOCGFORMAT: 92641480Smckusick /* find out who has the device in format mode */ 92741480Smckusick *(int *)data = sc->sc_format_pid; 92841480Smckusick return (0); 92941480Smckusick 93041480Smckusick case SDIOCSCSICOMMAND: 93141480Smckusick /* 93241480Smckusick * Save what user gave us as SCSI cdb to use with next 93341480Smckusick * read or write to the char device. 93441480Smckusick */ 93549132Skarels if (sc->sc_format_pid != p->p_pid) 93641480Smckusick return (EPERM); 93741480Smckusick if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) 93841480Smckusick return (EINVAL); 93941480Smckusick bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0])); 94041480Smckusick return (0); 94141480Smckusick 94241480Smckusick case SDIOCSENSE: 94341480Smckusick /* 94441480Smckusick * return the SCSI sense data saved after the last 94541480Smckusick * operation that completed with "check condition" status. 94641480Smckusick */ 94741480Smckusick bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0])); 94841480Smckusick return (0); 94941480Smckusick 95041480Smckusick } 95141480Smckusick /*NOTREACHED*/ 95241480Smckusick } 95341480Smckusick 95441480Smckusick int 95541480Smckusick sdsize(dev) 95641480Smckusick dev_t dev; 95741480Smckusick { 95841480Smckusick register int unit = sdunit(dev); 95941480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 960*57327Shibler int psize, didopen = 0; 96141480Smckusick 96241480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 96341480Smckusick return(-1); 96441480Smckusick 965*57327Shibler /* 966*57327Shibler * We get called very early on (via swapconf) 967*57327Shibler * without the device being open so we may need 968*57327Shibler * to handle it here. 969*57327Shibler */ 970*57327Shibler if (sc->sc_info.si_open == 0) { 971*57327Shibler if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) 972*57327Shibler return(-1); 973*57327Shibler didopen = 1; 974*57327Shibler } 975*57327Shibler psize = sc->sc_info.si_label.d_partitions[sdpart(dev)].p_size; 976*57327Shibler if (didopen) 977*57327Shibler (void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); 978*57327Shibler return (psize); 97941480Smckusick } 98041480Smckusick 98141480Smckusick /* 98241480Smckusick * Non-interrupt driven, non-dma dump routine. 98341480Smckusick */ 98441480Smckusick int 98541480Smckusick sddump(dev) 98641480Smckusick dev_t dev; 98741480Smckusick { 98841480Smckusick int part = sdpart(dev); 98941480Smckusick int unit = sdunit(dev); 99041480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 99141480Smckusick register struct hp_device *hp = sc->sc_hd; 992*57327Shibler register struct partition *pinfo; 99341480Smckusick register daddr_t baddr; 99441480Smckusick register int maddr; 99541480Smckusick register int pages, i; 99641480Smckusick int stat; 99741480Smckusick extern int lowram; 99841480Smckusick 99941480Smckusick /* is drive ok? */ 100041480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 100141480Smckusick return (ENXIO); 1002*57327Shibler pinfo = &sc->sc_info.si_label.d_partitions[part]; 100341480Smckusick /* dump parameters in range? */ 1004*57327Shibler if (dumplo < 0 || dumplo >= pinfo->p_size || 1005*57327Shibler pinfo->p_fstype != FS_SWAP) 100641480Smckusick return (EINVAL); 1007*57327Shibler pages = physmem; 1008*57327Shibler if (dumplo + ctod(pages) > pinfo->p_size) 1009*57327Shibler pages = dtoc(pinfo->p_size - dumplo); 101041480Smckusick maddr = lowram; 1011*57327Shibler baddr = dumplo + pinfo->p_offset; 101241480Smckusick /* scsi bus idle? */ 101341480Smckusick if (!scsireq(&sc->sc_dq)) { 101441480Smckusick scsireset(hp->hp_ctlr); 101541480Smckusick sdreset(sc, sc->sc_hd); 101641480Smckusick printf("[ drive %d reset ] ", unit); 101741480Smckusick } 101841480Smckusick for (i = 0; i < pages; i++) { 101941480Smckusick #define NPGMB (1024*1024/NBPG) 102041480Smckusick /* print out how many Mbs we have dumped */ 102141480Smckusick if (i && (i % NPGMB) == 0) 102241480Smckusick printf("%d ", i / NPGMB); 102341480Smckusick #undef NPBMG 102452614Smckusick pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr, 102551576Smckusick VM_PROT_READ, TRUE); 102641480Smckusick stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, 102741480Smckusick vmmap, NBPG, baddr, sc->sc_bshift); 102841480Smckusick if (stat) { 102941480Smckusick printf("sddump: scsi write error 0x%x\n", stat); 103041480Smckusick return (EIO); 103141480Smckusick } 103241480Smckusick maddr += NBPG; 103341480Smckusick baddr += ctod(1); 103441480Smckusick } 103541480Smckusick return (0); 103641480Smckusick } 103741480Smckusick #endif 1038