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*56507Sbostic * @(#)sd.c 7.16 (Berkeley) 10/11/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 2053929Shibler static char rcsid[] = "$Header: /usr/src/sys/hp300/dev/RCS/sd.c,v 1.2 92/04/10 20:48:35 mike Exp $"; 2141480Smckusick #endif 2241480Smckusick 23*56507Sbostic #include <sys/param.h> 24*56507Sbostic #include <sys/systm.h> 25*56507Sbostic #include <sys/buf.h> 26*56507Sbostic #include <sys/dkstat.h> 27*56507Sbostic #include <sys/disklabel.h> 28*56507Sbostic #include <sys/malloc.h> 29*56507Sbostic #include <sys/proc.h> 30*56507Sbostic #include <sys/ioctl.h> 3141480Smckusick 32*56507Sbostic #include <hp/dev/device.h> 33*56507Sbostic #include <hp300/dev/scsireg.h> 3445750Smckusick 35*56507Sbostic #include <vm/vm_param.h> 36*56507Sbostic #include <vm/lock.h> 37*56507Sbostic #include <vm/vm_prot.h> 38*56507Sbostic #include <vm/pmap.h> 39*56507Sbostic 4041480Smckusick extern int scsi_test_unit_rdy(); 4141480Smckusick extern int scsi_request_sense(); 4241480Smckusick extern int scsi_inquiry(); 4341480Smckusick extern int scsi_read_capacity(); 4441480Smckusick extern int scsi_tt_write(); 4541480Smckusick extern int scsireq(); 4641480Smckusick extern int scsiustart(); 4741480Smckusick extern int scsigo(); 4841480Smckusick extern void scsifree(); 4941480Smckusick extern void scsireset(); 5049304Shibler extern void scsi_delay(); 5141480Smckusick 5241480Smckusick extern void disksort(); 5341480Smckusick extern void biodone(); 5441480Smckusick extern int physio(); 5541480Smckusick extern void TBIS(); 5641480Smckusick 5741480Smckusick int sdinit(); 5841480Smckusick void sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr(); 5941480Smckusick 6041480Smckusick struct driver sddriver = { 6141480Smckusick sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr, 6241480Smckusick }; 6341480Smckusick 6441480Smckusick struct size { 6541480Smckusick u_long strtblk; 6641480Smckusick u_long endblk; 6741480Smckusick int nblocks; 6841480Smckusick }; 6941480Smckusick 7041480Smckusick struct sdinfo { 7141480Smckusick struct size part[8]; 7241480Smckusick }; 7341480Smckusick 7441480Smckusick /* 7541480Smckusick * since the SCSI standard tends to hide the disk structure, we define 7641480Smckusick * partitions in terms of DEV_BSIZE blocks. The default partition table 7741480Smckusick * (for an unlabeled disk) reserves 512K for a boot area, has an 8 meg 7841480Smckusick * root and 32 meg of swap. The rest of the space on the drive goes in 7941480Smckusick * the G partition. As usual, the C partition covers the entire disk 8041480Smckusick * (including the boot area). 8141480Smckusick */ 8241480Smckusick struct sdinfo sddefaultpart = { 8341480Smckusick 1024, 17408, 16384 , /* A */ 8441480Smckusick 17408, 82944, 65536 , /* B */ 8541480Smckusick 0, 0, 0 , /* C */ 8641480Smckusick 17408, 115712, 98304 , /* D */ 8741480Smckusick 115712, 218112, 102400 , /* E */ 8841480Smckusick 218112, 0, 0 , /* F */ 8941480Smckusick 82944, 0, 0 , /* G */ 9041480Smckusick 115712, 0, 0 , /* H */ 9141480Smckusick }; 9241480Smckusick 9341480Smckusick struct sd_softc { 9441480Smckusick struct hp_device *sc_hd; 9541480Smckusick struct devqueue sc_dq; 9641480Smckusick int sc_format_pid; /* process using "format" mode */ 9741480Smckusick short sc_flags; 9841480Smckusick short sc_type; /* drive type */ 9941480Smckusick short sc_punit; /* physical unit (scsi lun) */ 10041480Smckusick u_short sc_bshift; /* convert device blocks to DEV_BSIZE blks */ 10141480Smckusick u_int sc_blks; /* number of blocks on device */ 10241480Smckusick int sc_blksize; /* device block size in bytes */ 10341480Smckusick u_int sc_wpms; /* average xfer rate in 16 bit wds/sec. */ 10441480Smckusick struct sdinfo sc_info; /* drive partition table & label info */ 10541480Smckusick } sd_softc[NSD]; 10641480Smckusick 10741480Smckusick /* sc_flags values */ 10841480Smckusick #define SDF_ALIVE 0x1 10953929Shibler #define SDF_WANTED 0x2 11053929Shibler #define SDF_RMEDIA 0x4 11141480Smckusick 11241480Smckusick #ifdef DEBUG 11341480Smckusick int sddebug = 1; 11441480Smckusick #define SDB_ERROR 0x01 11541480Smckusick #define SDB_PARTIAL 0x02 11641480Smckusick #endif 11741480Smckusick 11841480Smckusick struct sdstats { 11941480Smckusick long sdresets; 12041480Smckusick long sdtransfers; 12141480Smckusick long sdpartials; 12241480Smckusick } sdstats[NSD]; 12341480Smckusick 12441480Smckusick struct buf sdtab[NSD]; 12541480Smckusick struct scsi_fmt_cdb sdcmd[NSD]; 12641480Smckusick struct scsi_fmt_sense sdsense[NSD]; 12741480Smckusick 12841480Smckusick static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT }; 12941480Smckusick static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT }; 13041480Smckusick 13149132Skarels #define sdunit(x) (minor(x) >> 3) 13241480Smckusick #define sdpart(x) (minor(x) & 0x7) 13341480Smckusick #define sdpunit(x) ((x) & 7) 13441480Smckusick #define b_cylin b_resid 13545750Smckusick 13641480Smckusick #define SDRETRY 2 13741480Smckusick 13841480Smckusick /* 13941480Smckusick * Table of scsi commands users are allowed to access via "format" 14041480Smckusick * mode. 0 means not legal. 1 means "immediate" (doesn't need dma). 14141480Smckusick * -1 means needs dma and/or wait for intr. 14241480Smckusick */ 14341480Smckusick static char legal_cmds[256] = { 14441480Smckusick /***** 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 14541480Smckusick /*00*/ 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14641480Smckusick /*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 14741480Smckusick /*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14841480Smckusick /*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14941480Smckusick /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15041480Smckusick /*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15141480Smckusick /*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15241480Smckusick /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15341480Smckusick /*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15441480Smckusick /*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15541480Smckusick /*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15641480Smckusick /*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15741480Smckusick /*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15841480Smckusick /*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15941480Smckusick /*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16041480Smckusick /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16141480Smckusick }; 16241480Smckusick 16341480Smckusick static struct scsi_inquiry inqbuf; 16441480Smckusick static struct scsi_fmt_cdb inq = { 16541480Smckusick 6, 16641480Smckusick CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 16741480Smckusick }; 16841480Smckusick 16941480Smckusick static u_char capbuf[8]; 17041480Smckusick struct scsi_fmt_cdb cap = { 17141480Smckusick 10, 17241480Smckusick CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 17341480Smckusick }; 17441480Smckusick 17541480Smckusick static int 17641480Smckusick sdident(sc, hd) 17741480Smckusick struct sd_softc *sc; 17841480Smckusick struct hp_device *hd; 17941480Smckusick { 18041480Smckusick int unit; 18141480Smckusick register int ctlr, slave; 18241480Smckusick register int i; 18341480Smckusick register int tries = 10; 18449304Shibler char idstr[32]; 18545750Smckusick int ismo = 0; 18641480Smckusick 18741480Smckusick ctlr = hd->hp_ctlr; 18841480Smckusick slave = hd->hp_slave; 18941480Smckusick unit = sc->sc_punit; 19049304Shibler scsi_delay(-1); 19141480Smckusick 19241480Smckusick /* 19341480Smckusick * See if unit exists and is a disk then read block size & nblocks. 19441480Smckusick */ 19541480Smckusick while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) { 19645750Smckusick if (i == -1 || --tries < 0) { 19745750Smckusick if (ismo) 19845750Smckusick break; 19941480Smckusick /* doesn't exist or not a CCS device */ 20049304Shibler goto failed; 20145750Smckusick } 20241480Smckusick if (i == STS_CHECKCOND) { 20341480Smckusick u_char sensebuf[128]; 20441480Smckusick struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf; 20541480Smckusick 20641480Smckusick scsi_request_sense(ctlr, slave, unit, sensebuf, 20741480Smckusick sizeof(sensebuf)); 20845750Smckusick if (sp->class == 7) 20945750Smckusick switch (sp->key) { 21045750Smckusick /* not ready -- might be MO with no media */ 21145750Smckusick case 2: 21245750Smckusick if (sp->len == 12 && 21345750Smckusick sensebuf[12] == 10) /* XXX */ 21445750Smckusick ismo = 1; 21545750Smckusick break; 21641480Smckusick /* drive doing an RTZ -- give it a while */ 21745750Smckusick case 6: 21845750Smckusick DELAY(1000000); 21945750Smckusick break; 22045750Smckusick default: 22145750Smckusick break; 22245750Smckusick } 22341480Smckusick } 22441480Smckusick DELAY(1000); 22541480Smckusick } 22645750Smckusick /* 22745750Smckusick * Find out about device 22845750Smckusick */ 22945750Smckusick if (scsi_immed_command(ctlr, slave, unit, &inq, 23045750Smckusick (u_char *)&inqbuf, sizeof(inqbuf), B_READ)) 23149304Shibler goto failed; 23241480Smckusick switch (inqbuf.type) { 23341480Smckusick case 0: /* disk */ 23441480Smckusick case 4: /* WORM */ 23541480Smckusick case 5: /* CD-ROM */ 23641480Smckusick case 7: /* Magneto-optical */ 23741480Smckusick break; 23841480Smckusick default: /* not a disk */ 23949304Shibler goto failed; 24041480Smckusick } 24145750Smckusick /* 24249304Shibler * Get a usable id string 24345750Smckusick */ 24449304Shibler if (inqbuf.version != 1) { 24549304Shibler bcopy("UNKNOWN", &idstr[0], 8); 24649304Shibler bcopy("DRIVE TYPE", &idstr[8], 11); 24749304Shibler } else { 24849304Shibler bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28); 24949304Shibler for (i = 27; i > 23; --i) 25049304Shibler if (idstr[i] != ' ') 25149304Shibler break; 25249304Shibler idstr[i+1] = 0; 25349304Shibler for (i = 23; i > 7; --i) 25449304Shibler if (idstr[i] != ' ') 25549304Shibler break; 25649304Shibler idstr[i+1] = 0; 25749304Shibler for (i = 7; i >= 0; --i) 25849304Shibler if (idstr[i] != ' ') 25949304Shibler break; 26049304Shibler idstr[i+1] = 0; 26145750Smckusick } 26245750Smckusick i = scsi_immed_command(ctlr, slave, unit, &cap, 26345750Smckusick (u_char *)&capbuf, sizeof(capbuf), B_READ); 26445750Smckusick if (i) { 26549304Shibler if (i != STS_CHECKCOND || 26649304Shibler bcmp(&idstr[0], "HP", 3) || 26749304Shibler bcmp(&idstr[8], "S6300.650A", 11)) 26849304Shibler goto failed; 26945750Smckusick /* XXX unformatted or non-existant MO media; fake it */ 27049304Shibler sc->sc_blks = 318664; 27149304Shibler sc->sc_blksize = 1024; 27245750Smckusick } else { 27345750Smckusick sc->sc_blks = *(u_int *)&capbuf[0]; 27445750Smckusick sc->sc_blksize = *(int *)&capbuf[4]; 27545750Smckusick } 27645750Smckusick /* return value of read capacity is last valid block number */ 27745750Smckusick sc->sc_blks++; 27845750Smckusick 27941480Smckusick if (inqbuf.version != 1) 28041480Smckusick printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit, 28141480Smckusick inqbuf.type, inqbuf.qual, inqbuf.version); 28249304Shibler else 28341480Smckusick printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8], 28441480Smckusick &idstr[24]); 28541480Smckusick printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize); 28653929Shibler if (inqbuf.qual & 0x80) 28753929Shibler sc->sc_flags |= SDF_RMEDIA; 28841480Smckusick if (sc->sc_blksize != DEV_BSIZE) { 28941480Smckusick if (sc->sc_blksize < DEV_BSIZE) { 29041480Smckusick printf("sd%d: need %d byte blocks - drive ignored\n", 29141480Smckusick unit, DEV_BSIZE); 29249304Shibler goto failed; 29341480Smckusick } 29441480Smckusick for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) 29541480Smckusick ++sc->sc_bshift; 29641480Smckusick sc->sc_blks <<= sc->sc_bshift; 29741480Smckusick } 29841480Smckusick sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */ 29949304Shibler scsi_delay(0); 30041480Smckusick return(inqbuf.type); 30149304Shibler failed: 30249304Shibler scsi_delay(0); 30349304Shibler return(-1); 30441480Smckusick } 30541480Smckusick 30641480Smckusick int 30741480Smckusick sdinit(hd) 30841480Smckusick register struct hp_device *hd; 30941480Smckusick { 31041480Smckusick register struct sd_softc *sc = &sd_softc[hd->hp_unit]; 31141480Smckusick 31241480Smckusick sc->sc_hd = hd; 31353929Shibler sc->sc_flags = 0; 31441480Smckusick sc->sc_punit = sdpunit(hd->hp_flags); 31541480Smckusick sc->sc_type = sdident(sc, hd); 31641480Smckusick if (sc->sc_type < 0) 31741480Smckusick return(0); 31841480Smckusick sc->sc_dq.dq_ctlr = hd->hp_ctlr; 31941480Smckusick sc->sc_dq.dq_unit = hd->hp_unit; 32041480Smckusick sc->sc_dq.dq_slave = hd->hp_slave; 32141480Smckusick sc->sc_dq.dq_driver = &sddriver; 32241480Smckusick 32341480Smckusick /* 32441480Smckusick * If we don't have a disk label, build a default partition 32541480Smckusick * table with 'standard' size root & swap and everything else 32641480Smckusick * in the G partition. 32741480Smckusick */ 32841480Smckusick sc->sc_info = sddefaultpart; 32941480Smckusick /* C gets everything */ 33041480Smckusick sc->sc_info.part[2].nblocks = sc->sc_blks; 33141480Smckusick sc->sc_info.part[2].endblk = sc->sc_blks; 33241480Smckusick /* G gets from end of B to end of disk */ 33341480Smckusick sc->sc_info.part[6].nblocks = sc->sc_blks - sc->sc_info.part[1].endblk; 33441480Smckusick sc->sc_info.part[6].endblk = sc->sc_blks; 33541480Smckusick /* 33641480Smckusick * We also define the D, E and F paritions as an alternative to 33741480Smckusick * B and G. D is 48Mb, starts after A and is intended for swapping. 33841480Smckusick * E is 50Mb, starts after D and is intended for /usr. F starts 33941480Smckusick * after E and is what ever is left. 34041480Smckusick */ 34141480Smckusick if (sc->sc_blks >= sc->sc_info.part[4].endblk) { 34241480Smckusick sc->sc_info.part[5].nblocks = 34341480Smckusick sc->sc_blks - sc->sc_info.part[4].endblk; 34441480Smckusick sc->sc_info.part[5].endblk = sc->sc_blks; 34541480Smckusick } else { 34641480Smckusick sc->sc_info.part[5].strtblk = 0; 34741480Smckusick sc->sc_info.part[3] = sc->sc_info.part[5]; 34841480Smckusick sc->sc_info.part[4] = sc->sc_info.part[5]; 34941480Smckusick } 35041480Smckusick /* 35141480Smckusick * H is a single partition alternative to E and F. 35241480Smckusick */ 35341480Smckusick if (sc->sc_blks >= sc->sc_info.part[3].endblk) { 35441480Smckusick sc->sc_info.part[7].nblocks = 35541480Smckusick sc->sc_blks - sc->sc_info.part[3].endblk; 35641480Smckusick sc->sc_info.part[7].endblk = sc->sc_blks; 35741480Smckusick } else { 35841480Smckusick sc->sc_info.part[7].strtblk = 0; 35941480Smckusick } 36041480Smckusick 36153929Shibler sc->sc_flags |= SDF_ALIVE; 36241480Smckusick return(1); 36341480Smckusick } 36441480Smckusick 36541480Smckusick void 36641480Smckusick sdreset(sc, hd) 36741480Smckusick register struct sd_softc *sc; 36841480Smckusick register struct hp_device *hd; 36941480Smckusick { 37041480Smckusick sdstats[hd->hp_unit].sdresets++; 37141480Smckusick } 37241480Smckusick 37341480Smckusick int 37449132Skarels sdopen(dev, flags, mode, p) 37541480Smckusick dev_t dev; 37649132Skarels int flags, mode; 37749132Skarels struct proc *p; 37841480Smckusick { 37941480Smckusick register int unit = sdunit(dev); 38041480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 38141480Smckusick 38241480Smckusick if (unit >= NSD) 38341480Smckusick return(ENXIO); 38449132Skarels if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag)) 38541480Smckusick return(ENXIO); 38641480Smckusick 38741480Smckusick if (sc->sc_hd->hp_dk >= 0) 38841480Smckusick dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms; 38941480Smckusick return(0); 39041480Smckusick } 39141480Smckusick 39253929Shibler int 39353929Shibler sdclose(dev, flag, mode, p) 39453929Shibler dev_t dev; 39553929Shibler int flag, mode; 39653929Shibler struct proc *p; 39753929Shibler { 39853929Shibler int unit = sdunit(dev); 39953929Shibler register struct sd_softc *sc = &sd_softc[unit]; 40053929Shibler int s; 40153929Shibler 40253929Shibler /* 40353929Shibler * XXX we should really do this for all drives. 40453929Shibler */ 40553929Shibler if (sc->sc_flags & SDF_RMEDIA) { 40653929Shibler s = splbio(); 40753929Shibler while (sdtab[unit].b_active) { 40853929Shibler sc->sc_flags |= SDF_WANTED; 40953929Shibler sleep((caddr_t)&sdtab[unit], PRIBIO); 41053929Shibler } 41153929Shibler splx(s); 41253929Shibler } 41353929Shibler sc->sc_format_pid = 0; 41453929Shibler } 41553929Shibler 41641480Smckusick /* 41741480Smckusick * This routine is called for partial block transfers and non-aligned 41841480Smckusick * transfers (the latter only being possible on devices with a block size 41941480Smckusick * larger than DEV_BSIZE). The operation is performed in three steps 42041480Smckusick * using a locally allocated buffer: 42141480Smckusick * 1. transfer any initial partial block 42241480Smckusick * 2. transfer full blocks 42341480Smckusick * 3. transfer any final partial block 42441480Smckusick */ 42541480Smckusick static void 42641480Smckusick sdlblkstrat(bp, bsize) 42741480Smckusick register struct buf *bp; 42841480Smckusick register int bsize; 42941480Smckusick { 43041480Smckusick register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf), 43141480Smckusick M_DEVBUF, M_WAITOK); 43241480Smckusick caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); 43341480Smckusick register int bn, resid; 43441480Smckusick register caddr_t addr; 43541480Smckusick 43641480Smckusick bzero((caddr_t)cbp, sizeof(*cbp)); 43749132Skarels cbp->b_proc = curproc; /* XXX */ 43841480Smckusick cbp->b_dev = bp->b_dev; 43941480Smckusick bn = bp->b_blkno; 44041480Smckusick resid = bp->b_bcount; 44141480Smckusick addr = bp->b_un.b_addr; 44241480Smckusick #ifdef DEBUG 44341480Smckusick if (sddebug & SDB_PARTIAL) 44441480Smckusick printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", 44541480Smckusick bp, bp->b_flags, bn, resid, addr); 44641480Smckusick #endif 44741480Smckusick 44841480Smckusick while (resid > 0) { 44941480Smckusick register int boff = dbtob(bn) & (bsize - 1); 45041480Smckusick register int count; 45141480Smckusick 45241480Smckusick if (boff || resid < bsize) { 45341480Smckusick sdstats[sdunit(bp->b_dev)].sdpartials++; 45455068Spendry count = min(resid, bsize - boff); 45541480Smckusick cbp->b_flags = B_BUSY | B_PHYS | B_READ; 45641480Smckusick cbp->b_blkno = bn - btodb(boff); 45741480Smckusick cbp->b_un.b_addr = cbuf; 45841480Smckusick cbp->b_bcount = bsize; 45941480Smckusick #ifdef DEBUG 46041480Smckusick if (sddebug & SDB_PARTIAL) 46141480Smckusick printf(" readahead: bn %x cnt %x off %x addr %x\n", 46241480Smckusick cbp->b_blkno, count, boff, addr); 46341480Smckusick #endif 46441480Smckusick sdstrategy(cbp); 46541480Smckusick biowait(cbp); 46641480Smckusick if (cbp->b_flags & B_ERROR) { 46741480Smckusick bp->b_flags |= B_ERROR; 46841480Smckusick bp->b_error = cbp->b_error; 46941480Smckusick break; 47041480Smckusick } 47141480Smckusick if (bp->b_flags & B_READ) { 47241480Smckusick bcopy(&cbuf[boff], addr, count); 47341480Smckusick goto done; 47441480Smckusick } 47541480Smckusick bcopy(addr, &cbuf[boff], count); 47641480Smckusick #ifdef DEBUG 47741480Smckusick if (sddebug & SDB_PARTIAL) 47841480Smckusick printf(" writeback: bn %x cnt %x off %x addr %x\n", 47941480Smckusick cbp->b_blkno, count, boff, addr); 48041480Smckusick #endif 48141480Smckusick } else { 48241480Smckusick count = resid & ~(bsize - 1); 48341480Smckusick cbp->b_blkno = bn; 48441480Smckusick cbp->b_un.b_addr = addr; 48541480Smckusick cbp->b_bcount = count; 48641480Smckusick #ifdef DEBUG 48741480Smckusick if (sddebug & SDB_PARTIAL) 48841480Smckusick printf(" fulltrans: bn %x cnt %x addr %x\n", 48941480Smckusick cbp->b_blkno, count, addr); 49041480Smckusick #endif 49141480Smckusick } 49241480Smckusick cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); 49341480Smckusick sdstrategy(cbp); 49441480Smckusick biowait(cbp); 49541480Smckusick if (cbp->b_flags & B_ERROR) { 49641480Smckusick bp->b_flags |= B_ERROR; 49741480Smckusick bp->b_error = cbp->b_error; 49841480Smckusick break; 49941480Smckusick } 50041480Smckusick done: 50141480Smckusick bn += btodb(count); 50241480Smckusick resid -= count; 50341480Smckusick addr += count; 50441480Smckusick #ifdef DEBUG 50541480Smckusick if (sddebug & SDB_PARTIAL) 50641480Smckusick printf(" done: bn %x resid %x addr %x\n", 50741480Smckusick bn, resid, addr); 50841480Smckusick #endif 50941480Smckusick } 51041480Smckusick free(cbuf, M_DEVBUF); 51141480Smckusick free(cbp, M_DEVBUF); 51241480Smckusick } 51341480Smckusick 51441480Smckusick void 51541480Smckusick sdstrategy(bp) 51641480Smckusick register struct buf *bp; 51741480Smckusick { 51841480Smckusick register int unit = sdunit(bp->b_dev); 51941480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 52045750Smckusick register struct size *pinfo = &sc->sc_info.part[sdpart(bp->b_dev)]; 52141480Smckusick register struct buf *dp = &sdtab[unit]; 52245750Smckusick register daddr_t bn; 52345750Smckusick register int sz, s; 52441480Smckusick 52541480Smckusick if (sc->sc_format_pid) { 52649132Skarels if (sc->sc_format_pid != curproc->p_pid) { /* XXX */ 52741480Smckusick bp->b_error = EPERM; 52845750Smckusick bp->b_flags |= B_ERROR; 52945750Smckusick goto done; 53041480Smckusick } 53141480Smckusick bp->b_cylin = 0; 53241480Smckusick } else { 53341480Smckusick bn = bp->b_blkno; 53445750Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 53545750Smckusick if (bn < 0 || bn + sz > pinfo->nblocks) { 53645750Smckusick sz = pinfo->nblocks - bn; 53745750Smckusick if (sz == 0) { 53841480Smckusick bp->b_resid = bp->b_bcount; 53941480Smckusick goto done; 54041480Smckusick } 54145750Smckusick if (sz < 0) { 54245750Smckusick bp->b_error = EINVAL; 54345750Smckusick bp->b_flags |= B_ERROR; 54445750Smckusick goto done; 54545750Smckusick } 54645750Smckusick bp->b_bcount = dbtob(sz); 54741480Smckusick } 54841480Smckusick /* 54941480Smckusick * Non-aligned or partial-block transfers handled specially. 55041480Smckusick */ 55141480Smckusick s = sc->sc_blksize - 1; 55241480Smckusick if ((dbtob(bn) & s) || (bp->b_bcount & s)) { 55341480Smckusick sdlblkstrat(bp, sc->sc_blksize); 55441480Smckusick goto done; 55541480Smckusick } 55645750Smckusick bp->b_cylin = (bn + pinfo->strtblk) >> sc->sc_bshift; 55741480Smckusick } 55841480Smckusick s = splbio(); 55941480Smckusick disksort(dp, bp); 56041480Smckusick if (dp->b_active == 0) { 56141480Smckusick dp->b_active = 1; 56241480Smckusick sdustart(unit); 56341480Smckusick } 56441480Smckusick splx(s); 56541480Smckusick return; 56641480Smckusick done: 56745750Smckusick biodone(bp); 56841480Smckusick } 56941480Smckusick 57041480Smckusick void 57141480Smckusick sdustart(unit) 57241480Smckusick register int unit; 57341480Smckusick { 57441480Smckusick if (scsireq(&sd_softc[unit].sc_dq)) 57541480Smckusick sdstart(unit); 57641480Smckusick } 57741480Smckusick 57850039Skarels /* 57950039Skarels * Return: 58050039Skarels * 0 if not really an error 58150039Skarels * <0 if we should do a retry 58250039Skarels * >0 if a fatal error 58350039Skarels */ 58445750Smckusick static int 58541480Smckusick sderror(unit, sc, hp, stat) 58641480Smckusick int unit, stat; 58741480Smckusick register struct sd_softc *sc; 58841480Smckusick register struct hp_device *hp; 58941480Smckusick { 59050039Skarels int cond = 1; 59145750Smckusick 59241480Smckusick sdsense[unit].status = stat; 59341480Smckusick if (stat & STS_CHECKCOND) { 59441480Smckusick struct scsi_xsense *sp; 59541480Smckusick 59641480Smckusick scsi_request_sense(hp->hp_ctlr, hp->hp_slave, 59741480Smckusick sc->sc_punit, sdsense[unit].sense, 59841480Smckusick sizeof(sdsense[unit].sense)); 59941480Smckusick sp = (struct scsi_xsense *)sdsense[unit].sense; 60041480Smckusick printf("sd%d: scsi sense class %d, code %d", unit, 60141480Smckusick sp->class, sp->code); 60241480Smckusick if (sp->class == 7) { 60341480Smckusick printf(", key %d", sp->key); 60441480Smckusick if (sp->valid) 60541480Smckusick printf(", blk %d", *(int *)&sp->info1); 60650039Skarels switch (sp->key) { 60750039Skarels /* no sense, try again */ 60850039Skarels case 0: 60950039Skarels cond = -1; 61050039Skarels break; 61150039Skarels /* recovered error, not a problem */ 61250039Skarels case 1: 61350039Skarels cond = 0; 61450039Skarels break; 61550039Skarels } 61641480Smckusick } 61741480Smckusick printf("\n"); 61841480Smckusick } 61950039Skarels return(cond); 62041480Smckusick } 62141480Smckusick 62241480Smckusick static void 62341480Smckusick sdfinish(unit, sc, bp) 62441480Smckusick int unit; 62541480Smckusick register struct sd_softc *sc; 62641480Smckusick register struct buf *bp; 62741480Smckusick { 62853929Shibler register struct buf *dp = &sdtab[unit]; 62953929Shibler 63053929Shibler dp->b_errcnt = 0; 63153929Shibler dp->b_actf = bp->b_actf; 63241480Smckusick bp->b_resid = 0; 63345750Smckusick biodone(bp); 63441480Smckusick scsifree(&sc->sc_dq); 63553929Shibler if (dp->b_actf) 63641480Smckusick sdustart(unit); 63753929Shibler else { 63853929Shibler dp->b_active = 0; 63953929Shibler if (sc->sc_flags & SDF_WANTED) { 64053929Shibler sc->sc_flags &= ~SDF_WANTED; 64153929Shibler wakeup((caddr_t)dp); 64253929Shibler } 64353929Shibler } 64441480Smckusick } 64541480Smckusick 64641480Smckusick void 64741480Smckusick sdstart(unit) 64841480Smckusick register int unit; 64941480Smckusick { 65041480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 65141480Smckusick register struct hp_device *hp = sc->sc_hd; 65241480Smckusick 65341480Smckusick /* 65441480Smckusick * we have the SCSI bus -- in format mode, we may or may not need dma 65541480Smckusick * so check now. 65641480Smckusick */ 65741480Smckusick if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) { 65841480Smckusick register struct buf *bp = sdtab[unit].b_actf; 65941480Smckusick register int sts; 66041480Smckusick 66141480Smckusick sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave, 66241480Smckusick sc->sc_punit, &sdcmd[unit], 66341480Smckusick bp->b_un.b_addr, bp->b_bcount, 66441480Smckusick bp->b_flags & B_READ); 66541480Smckusick sdsense[unit].status = sts; 66641480Smckusick if (sts & 0xfe) { 66745750Smckusick (void) sderror(unit, sc, hp, sts); 66841480Smckusick bp->b_flags |= B_ERROR; 66941480Smckusick bp->b_error = EIO; 67041480Smckusick } 67141480Smckusick sdfinish(unit, sc, bp); 67241480Smckusick 67341480Smckusick } else if (scsiustart(hp->hp_ctlr)) 67441480Smckusick sdgo(unit); 67541480Smckusick } 67641480Smckusick 67741480Smckusick void 67841480Smckusick sdgo(unit) 67941480Smckusick register int unit; 68041480Smckusick { 68141480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 68241480Smckusick register struct hp_device *hp = sc->sc_hd; 68341480Smckusick register struct buf *bp = sdtab[unit].b_actf; 68441480Smckusick register int pad; 68541480Smckusick register struct scsi_fmt_cdb *cmd; 68641480Smckusick 68741480Smckusick if (sc->sc_format_pid) { 68841480Smckusick cmd = &sdcmd[unit]; 68941480Smckusick pad = 0; 69041480Smckusick } else { 69141480Smckusick cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd; 69241480Smckusick *(int *)(&cmd->cdb[2]) = bp->b_cylin; 69341480Smckusick pad = howmany(bp->b_bcount, sc->sc_blksize); 69441480Smckusick *(u_short *)(&cmd->cdb[7]) = pad; 69541480Smckusick pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0; 69641480Smckusick #ifdef DEBUG 69741480Smckusick if (pad) 69841480Smckusick printf("sd%d: partial block xfer -- %x bytes\n", 69941480Smckusick unit, bp->b_bcount); 70041480Smckusick #endif 70141480Smckusick sdstats[unit].sdtransfers++; 70241480Smckusick } 70341480Smckusick if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) { 70441480Smckusick if (hp->hp_dk >= 0) { 70541480Smckusick dk_busy |= 1 << hp->hp_dk; 70641480Smckusick ++dk_seek[hp->hp_dk]; 70741480Smckusick ++dk_xfer[hp->hp_dk]; 70841480Smckusick dk_wds[hp->hp_dk] += bp->b_bcount >> 6; 70941480Smckusick } 71041480Smckusick return; 71141480Smckusick } 71241480Smckusick #ifdef DEBUG 71341480Smckusick if (sddebug & SDB_ERROR) 71441480Smckusick printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n", 71541480Smckusick unit, bp->b_flags & B_READ? "read" : "write", 71641480Smckusick bp->b_un.b_addr, bp->b_cylin, bp->b_bcount, 71741480Smckusick sdtab[unit].b_errcnt); 71841480Smckusick #endif 71941480Smckusick bp->b_flags |= B_ERROR; 72041480Smckusick bp->b_error = EIO; 72141480Smckusick sdfinish(unit, sc, bp); 72241480Smckusick } 72341480Smckusick 72441480Smckusick void 72541480Smckusick sdintr(unit, stat) 72641480Smckusick register int unit; 72741480Smckusick int stat; 72841480Smckusick { 72941480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 73041480Smckusick register struct buf *bp = sdtab[unit].b_actf; 73141480Smckusick register struct hp_device *hp = sc->sc_hd; 73250039Skarels int cond; 73341480Smckusick 73441480Smckusick if (bp == NULL) { 73541480Smckusick printf("sd%d: bp == NULL\n", unit); 73641480Smckusick return; 73741480Smckusick } 73841480Smckusick if (hp->hp_dk >= 0) 73941480Smckusick dk_busy &=~ (1 << hp->hp_dk); 74041480Smckusick if (stat) { 74141480Smckusick #ifdef DEBUG 74241480Smckusick if (sddebug & SDB_ERROR) 74341480Smckusick printf("sd%d: sdintr: bad scsi status 0x%x\n", 74441480Smckusick unit, stat); 74541480Smckusick #endif 74650039Skarels cond = sderror(unit, sc, hp, stat); 74750039Skarels if (cond) { 74850039Skarels if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) { 74950038Skarels #ifdef DEBUG 75050039Skarels if (sddebug & SDB_ERROR) 75150039Skarels printf("sd%d: retry #%d\n", 75250039Skarels unit, sdtab[unit].b_errcnt); 75350038Skarels #endif 75450039Skarels sdstart(unit); 75550039Skarels return; 75650039Skarels } 75750039Skarels bp->b_flags |= B_ERROR; 75850039Skarels bp->b_error = EIO; 75945750Smckusick } 76041480Smckusick } 76141480Smckusick sdfinish(unit, sc, bp); 76241480Smckusick } 76341480Smckusick 76441480Smckusick int 76549132Skarels sdread(dev, uio, flags) 76641480Smckusick dev_t dev; 76741480Smckusick struct uio *uio; 76849132Skarels int flags; 76941480Smckusick { 77041480Smckusick register int unit = sdunit(dev); 77141480Smckusick register int pid; 77241480Smckusick 77349132Skarels if ((pid = sd_softc[unit].sc_format_pid) && 77449132Skarels pid != uio->uio_procp->p_pid) 77541480Smckusick return (EPERM); 77641480Smckusick 77749132Skarels return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio)); 77841480Smckusick } 77941480Smckusick 78041480Smckusick int 78149132Skarels sdwrite(dev, uio, flags) 78241480Smckusick dev_t dev; 78341480Smckusick struct uio *uio; 78449132Skarels int flags; 78541480Smckusick { 78641480Smckusick register int unit = sdunit(dev); 78741480Smckusick register int pid; 78841480Smckusick 78949132Skarels if ((pid = sd_softc[unit].sc_format_pid) && 79049132Skarels pid != uio->uio_procp->p_pid) 79141480Smckusick return (EPERM); 79241480Smckusick 79349132Skarels return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio)); 79441480Smckusick } 79541480Smckusick 79641480Smckusick int 79749132Skarels sdioctl(dev, cmd, data, flag, p) 79841480Smckusick dev_t dev; 79941480Smckusick int cmd; 80041480Smckusick caddr_t data; 80141480Smckusick int flag; 80249132Skarels struct proc *p; 80341480Smckusick { 80441480Smckusick register int unit = sdunit(dev); 80541480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 80641480Smckusick 80741480Smckusick switch (cmd) { 80841480Smckusick default: 80941480Smckusick return (EINVAL); 81041480Smckusick 81141480Smckusick case SDIOCSFORMAT: 81241480Smckusick /* take this device into or out of "format" mode */ 81349132Skarels if (suser(p->p_ucred, &p->p_acflag)) 81441480Smckusick return(EPERM); 81541480Smckusick 81641480Smckusick if (*(int *)data) { 81741480Smckusick if (sc->sc_format_pid) 81841480Smckusick return (EPERM); 81949132Skarels sc->sc_format_pid = p->p_pid; 82041480Smckusick } else 82141480Smckusick sc->sc_format_pid = 0; 82241480Smckusick return (0); 82341480Smckusick 82441480Smckusick case SDIOCGFORMAT: 82541480Smckusick /* find out who has the device in format mode */ 82641480Smckusick *(int *)data = sc->sc_format_pid; 82741480Smckusick return (0); 82841480Smckusick 82941480Smckusick case SDIOCSCSICOMMAND: 83041480Smckusick /* 83141480Smckusick * Save what user gave us as SCSI cdb to use with next 83241480Smckusick * read or write to the char device. 83341480Smckusick */ 83449132Skarels if (sc->sc_format_pid != p->p_pid) 83541480Smckusick return (EPERM); 83641480Smckusick if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) 83741480Smckusick return (EINVAL); 83841480Smckusick bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0])); 83941480Smckusick return (0); 84041480Smckusick 84141480Smckusick case SDIOCSENSE: 84241480Smckusick /* 84341480Smckusick * return the SCSI sense data saved after the last 84441480Smckusick * operation that completed with "check condition" status. 84541480Smckusick */ 84641480Smckusick bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0])); 84741480Smckusick return (0); 84841480Smckusick 84941480Smckusick } 85041480Smckusick /*NOTREACHED*/ 85141480Smckusick } 85241480Smckusick 85341480Smckusick int 85441480Smckusick sdsize(dev) 85541480Smckusick dev_t dev; 85641480Smckusick { 85741480Smckusick register int unit = sdunit(dev); 85841480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 85941480Smckusick 86041480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 86141480Smckusick return(-1); 86241480Smckusick 86341480Smckusick return(sc->sc_info.part[sdpart(dev)].nblocks); 86441480Smckusick } 86541480Smckusick 86641480Smckusick /* 86741480Smckusick * Non-interrupt driven, non-dma dump routine. 86841480Smckusick */ 86941480Smckusick int 87041480Smckusick sddump(dev) 87141480Smckusick dev_t dev; 87241480Smckusick { 87341480Smckusick int part = sdpart(dev); 87441480Smckusick int unit = sdunit(dev); 87541480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 87641480Smckusick register struct hp_device *hp = sc->sc_hd; 87741480Smckusick register daddr_t baddr; 87841480Smckusick register int maddr; 87941480Smckusick register int pages, i; 88041480Smckusick int stat; 88141480Smckusick extern int lowram; 88241480Smckusick 88341480Smckusick /* 88441480Smckusick * Hmm... all vax drivers dump maxfree pages which is physmem minus 88541480Smckusick * the message buffer. Is there a reason for not dumping the 88641480Smckusick * message buffer? Savecore expects to read 'dumpsize' pages of 88741480Smckusick * dump, where dumpsys() sets dumpsize to physmem! 88841480Smckusick */ 88941480Smckusick pages = physmem; 89041480Smckusick 89141480Smckusick /* is drive ok? */ 89241480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 89341480Smckusick return (ENXIO); 89441480Smckusick /* dump parameters in range? */ 89541480Smckusick if (dumplo < 0 || dumplo >= sc->sc_info.part[part].nblocks) 89641480Smckusick return (EINVAL); 89741480Smckusick if (dumplo + ctod(pages) > sc->sc_info.part[part].nblocks) 89841480Smckusick pages = dtoc(sc->sc_info.part[part].nblocks - dumplo); 89941480Smckusick maddr = lowram; 90041480Smckusick baddr = dumplo + sc->sc_info.part[part].strtblk; 90141480Smckusick /* scsi bus idle? */ 90241480Smckusick if (!scsireq(&sc->sc_dq)) { 90341480Smckusick scsireset(hp->hp_ctlr); 90441480Smckusick sdreset(sc, sc->sc_hd); 90541480Smckusick printf("[ drive %d reset ] ", unit); 90641480Smckusick } 90741480Smckusick for (i = 0; i < pages; i++) { 90841480Smckusick #define NPGMB (1024*1024/NBPG) 90941480Smckusick /* print out how many Mbs we have dumped */ 91041480Smckusick if (i && (i % NPGMB) == 0) 91141480Smckusick printf("%d ", i / NPGMB); 91241480Smckusick #undef NPBMG 91352614Smckusick pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr, 91451576Smckusick VM_PROT_READ, TRUE); 91541480Smckusick stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, 91641480Smckusick vmmap, NBPG, baddr, sc->sc_bshift); 91741480Smckusick if (stat) { 91841480Smckusick printf("sddump: scsi write error 0x%x\n", stat); 91941480Smckusick return (EIO); 92041480Smckusick } 92141480Smckusick maddr += NBPG; 92241480Smckusick baddr += ctod(1); 92341480Smckusick } 92441480Smckusick return (0); 92541480Smckusick } 92641480Smckusick #endif 927