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*45788Sbostic * @(#)sd.c 7.4 (Berkeley) 12/16/90 1141480Smckusick */ 1241480Smckusick 1341480Smckusick /* 1441480Smckusick * SCSI CCS (Command Command Set) disk driver. 1541480Smckusick */ 1641480Smckusick #include "sd.h" 1741480Smckusick #if NSD > 0 1841480Smckusick 1941480Smckusick #ifndef lint 2045750Smckusick static char rcsid[] = "$Header: sd.c,v 1.3 90/10/10 14:55:10 mike Exp $"; 2141480Smckusick #endif 2241480Smckusick 23*45788Sbostic #include "sys/param.h" 24*45788Sbostic #include "sys/systm.h" 25*45788Sbostic #include "sys/buf.h" 26*45788Sbostic #include "sys/errno.h" 27*45788Sbostic #include "sys/dkstat.h" 28*45788Sbostic #include "sys/disklabel.h" 2941480Smckusick #include "device.h" 30*45788Sbostic #include "sys/malloc.h" 3141480Smckusick #include "scsireg.h" 3241480Smckusick 33*45788Sbostic #include "sys/user.h" 34*45788Sbostic #include "sys/proc.h" 35*45788Sbostic #include "sys/uio.h" 3641480Smckusick 37*45788Sbostic #include "vm/vm_param.h" 38*45788Sbostic #include "vm/pmap.h" 39*45788Sbostic #include "vm/vm_prot.h" 4045750Smckusick 4141480Smckusick extern int scsi_test_unit_rdy(); 4241480Smckusick extern int scsi_request_sense(); 4341480Smckusick extern int scsi_inquiry(); 4441480Smckusick extern int scsi_read_capacity(); 4541480Smckusick extern int scsi_tt_write(); 4641480Smckusick extern int scsireq(); 4741480Smckusick extern int scsiustart(); 4841480Smckusick extern int scsigo(); 4941480Smckusick extern void scsifree(); 5041480Smckusick extern void scsireset(); 5141480Smckusick 5241480Smckusick extern void printf(); 5341480Smckusick extern void bcopy(); 5441480Smckusick extern void disksort(); 5541480Smckusick extern int splbio(); 5641480Smckusick extern void splx(); 5741480Smckusick extern void biodone(); 5841480Smckusick extern int physio(); 5941480Smckusick extern void TBIS(); 6041480Smckusick 6141480Smckusick int sdinit(); 6241480Smckusick void sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr(); 6341480Smckusick 6441480Smckusick struct driver sddriver = { 6541480Smckusick sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr, 6641480Smckusick }; 6741480Smckusick 6841480Smckusick struct size { 6941480Smckusick u_long strtblk; 7041480Smckusick u_long endblk; 7141480Smckusick int nblocks; 7241480Smckusick }; 7341480Smckusick 7441480Smckusick struct sdinfo { 7541480Smckusick struct size part[8]; 7641480Smckusick }; 7741480Smckusick 7841480Smckusick /* 7941480Smckusick * since the SCSI standard tends to hide the disk structure, we define 8041480Smckusick * partitions in terms of DEV_BSIZE blocks. The default partition table 8141480Smckusick * (for an unlabeled disk) reserves 512K for a boot area, has an 8 meg 8241480Smckusick * root and 32 meg of swap. The rest of the space on the drive goes in 8341480Smckusick * the G partition. As usual, the C partition covers the entire disk 8441480Smckusick * (including the boot area). 8541480Smckusick */ 8641480Smckusick struct sdinfo sddefaultpart = { 8741480Smckusick 1024, 17408, 16384 , /* A */ 8841480Smckusick 17408, 82944, 65536 , /* B */ 8941480Smckusick 0, 0, 0 , /* C */ 9041480Smckusick 17408, 115712, 98304 , /* D */ 9141480Smckusick 115712, 218112, 102400 , /* E */ 9241480Smckusick 218112, 0, 0 , /* F */ 9341480Smckusick 82944, 0, 0 , /* G */ 9441480Smckusick 115712, 0, 0 , /* H */ 9541480Smckusick }; 9641480Smckusick 9741480Smckusick struct sd_softc { 9841480Smckusick struct hp_device *sc_hd; 9941480Smckusick struct devqueue sc_dq; 10041480Smckusick int sc_format_pid; /* process using "format" mode */ 10141480Smckusick short sc_flags; 10241480Smckusick short sc_type; /* drive type */ 10341480Smckusick short sc_punit; /* physical unit (scsi lun) */ 10441480Smckusick u_short sc_bshift; /* convert device blocks to DEV_BSIZE blks */ 10541480Smckusick u_int sc_blks; /* number of blocks on device */ 10641480Smckusick int sc_blksize; /* device block size in bytes */ 10741480Smckusick u_int sc_wpms; /* average xfer rate in 16 bit wds/sec. */ 10841480Smckusick struct sdinfo sc_info; /* drive partition table & label info */ 10941480Smckusick } sd_softc[NSD]; 11041480Smckusick 11141480Smckusick /* sc_flags values */ 11241480Smckusick #define SDF_ALIVE 0x1 11341480Smckusick 11441480Smckusick #ifdef DEBUG 11541480Smckusick int sddebug = 1; 11641480Smckusick #define SDB_ERROR 0x01 11741480Smckusick #define SDB_PARTIAL 0x02 11841480Smckusick #endif 11941480Smckusick 12041480Smckusick struct sdstats { 12141480Smckusick long sdresets; 12241480Smckusick long sdtransfers; 12341480Smckusick long sdpartials; 12441480Smckusick } sdstats[NSD]; 12541480Smckusick 12641480Smckusick struct buf sdtab[NSD]; 12741480Smckusick struct buf sdbuf[NSD]; 12841480Smckusick struct scsi_fmt_cdb sdcmd[NSD]; 12941480Smckusick struct scsi_fmt_sense sdsense[NSD]; 13041480Smckusick 13141480Smckusick static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT }; 13241480Smckusick static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT }; 13341480Smckusick 13441480Smckusick #define sdunit(x) ((minor(x) >> 3) & 0x7) 13541480Smckusick #define sdpart(x) (minor(x) & 0x7) 13641480Smckusick #define sdpunit(x) ((x) & 7) 13741480Smckusick #define b_cylin b_resid 13845750Smckusick 13941480Smckusick #define SDRETRY 2 14041480Smckusick 14141480Smckusick /* 14241480Smckusick * Table of scsi commands users are allowed to access via "format" 14341480Smckusick * mode. 0 means not legal. 1 means "immediate" (doesn't need dma). 14441480Smckusick * -1 means needs dma and/or wait for intr. 14541480Smckusick */ 14641480Smckusick static char legal_cmds[256] = { 14741480Smckusick /***** 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 14841480Smckusick /*00*/ 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14941480Smckusick /*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 15041480Smckusick /*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15141480Smckusick /*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15241480Smckusick /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15341480Smckusick /*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15441480Smckusick /*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15541480Smckusick /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15641480Smckusick /*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15741480Smckusick /*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15841480Smckusick /*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15941480Smckusick /*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16041480Smckusick /*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16141480Smckusick /*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16241480Smckusick /*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16341480Smckusick /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16441480Smckusick }; 16541480Smckusick 16641480Smckusick static struct scsi_inquiry inqbuf; 16741480Smckusick static struct scsi_fmt_cdb inq = { 16841480Smckusick 6, 16941480Smckusick CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 17041480Smckusick }; 17141480Smckusick 17241480Smckusick static u_char capbuf[8]; 17341480Smckusick struct scsi_fmt_cdb cap = { 17441480Smckusick 10, 17541480Smckusick CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 17641480Smckusick }; 17741480Smckusick 17841480Smckusick static int 17941480Smckusick sdident(sc, hd) 18041480Smckusick struct sd_softc *sc; 18141480Smckusick struct hp_device *hd; 18241480Smckusick { 18341480Smckusick int unit; 18441480Smckusick register int ctlr, slave; 18541480Smckusick register int i; 18641480Smckusick register int tries = 10; 18745750Smckusick int ismo = 0; 18841480Smckusick 18941480Smckusick ctlr = hd->hp_ctlr; 19041480Smckusick slave = hd->hp_slave; 19141480Smckusick unit = sc->sc_punit; 19241480Smckusick 19341480Smckusick /* 19441480Smckusick * See if unit exists and is a disk then read block size & nblocks. 19541480Smckusick */ 19641480Smckusick while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) { 19745750Smckusick if (i == -1 || --tries < 0) { 19845750Smckusick if (ismo) 19945750Smckusick break; 20041480Smckusick /* doesn't exist or not a CCS device */ 20141480Smckusick return (-1); 20245750Smckusick } 20341480Smckusick if (i == STS_CHECKCOND) { 20441480Smckusick u_char sensebuf[128]; 20541480Smckusick struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf; 20641480Smckusick 20741480Smckusick scsi_request_sense(ctlr, slave, unit, sensebuf, 20841480Smckusick sizeof(sensebuf)); 20945750Smckusick if (sp->class == 7) 21045750Smckusick switch (sp->key) { 21145750Smckusick /* not ready -- might be MO with no media */ 21245750Smckusick case 2: 21345750Smckusick if (sp->len == 12 && 21445750Smckusick sensebuf[12] == 10) /* XXX */ 21545750Smckusick ismo = 1; 21645750Smckusick break; 21741480Smckusick /* drive doing an RTZ -- give it a while */ 21845750Smckusick case 6: 21945750Smckusick DELAY(1000000); 22045750Smckusick break; 22145750Smckusick default: 22245750Smckusick break; 22345750Smckusick } 22441480Smckusick } 22541480Smckusick DELAY(1000); 22641480Smckusick } 22745750Smckusick /* 22845750Smckusick * Find out about device 22945750Smckusick */ 23045750Smckusick if (scsi_immed_command(ctlr, slave, unit, &inq, 23145750Smckusick (u_char *)&inqbuf, sizeof(inqbuf), B_READ)) 23245750Smckusick return(-1); 23341480Smckusick switch (inqbuf.type) { 23441480Smckusick case 0: /* disk */ 23541480Smckusick case 4: /* WORM */ 23641480Smckusick case 5: /* CD-ROM */ 23741480Smckusick case 7: /* Magneto-optical */ 23841480Smckusick break; 23941480Smckusick default: /* not a disk */ 24041480Smckusick return (-1); 24141480Smckusick } 24245750Smckusick /* 24345750Smckusick * XXX determine if this is an HP MO drive. 24445750Smckusick */ 24545750Smckusick { 24645750Smckusick u_long *id = (u_long *)&inqbuf; 24741480Smckusick 24845750Smckusick ismo = (id[2] == 0x48502020 && /* "HP " */ 24945750Smckusick id[3] == 0x20202020 && /* " " */ 25045750Smckusick id[4] == 0x53363330 && /* "S630" */ 25145750Smckusick id[5] == 0x302e3635 && /* "0.65" */ 25245750Smckusick id[6] == 0x30412020); /* "0A " */ 25345750Smckusick } 25445750Smckusick i = scsi_immed_command(ctlr, slave, unit, &cap, 25545750Smckusick (u_char *)&capbuf, sizeof(capbuf), B_READ); 25645750Smckusick if (i) { 25745750Smckusick /* XXX unformatted or non-existant MO media; fake it */ 25845750Smckusick if (i == STS_CHECKCOND && ismo) { 25945750Smckusick sc->sc_blks = 318664; 26045750Smckusick sc->sc_blksize = 1024; 26145750Smckusick } else 26245750Smckusick return(-1); 26345750Smckusick } else { 26445750Smckusick sc->sc_blks = *(u_int *)&capbuf[0]; 26545750Smckusick sc->sc_blksize = *(int *)&capbuf[4]; 26645750Smckusick } 26745750Smckusick /* return value of read capacity is last valid block number */ 26845750Smckusick sc->sc_blks++; 26945750Smckusick 27041480Smckusick if (inqbuf.version != 1) 27141480Smckusick printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit, 27241480Smckusick inqbuf.type, inqbuf.qual, inqbuf.version); 27341480Smckusick else { 27441480Smckusick char idstr[32]; 27541480Smckusick 27641480Smckusick bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28); 27741480Smckusick for (i = 27; i > 23; --i) 27841480Smckusick if (idstr[i] != ' ') 27941480Smckusick break; 28041480Smckusick idstr[i+1] = 0; 28141480Smckusick for (i = 23; i > 7; --i) 28241480Smckusick if (idstr[i] != ' ') 28341480Smckusick break; 28441480Smckusick idstr[i+1] = 0; 28541480Smckusick for (i = 7; i >= 0; --i) 28641480Smckusick if (idstr[i] != ' ') 28741480Smckusick break; 28841480Smckusick idstr[i+1] = 0; 28941480Smckusick printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8], 29041480Smckusick &idstr[24]); 29141480Smckusick } 29241480Smckusick printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize); 29341480Smckusick if (sc->sc_blksize != DEV_BSIZE) { 29441480Smckusick if (sc->sc_blksize < DEV_BSIZE) { 29541480Smckusick printf("sd%d: need %d byte blocks - drive ignored\n", 29641480Smckusick unit, DEV_BSIZE); 29741480Smckusick return (-1); 29841480Smckusick } 29941480Smckusick for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) 30041480Smckusick ++sc->sc_bshift; 30141480Smckusick sc->sc_blks <<= sc->sc_bshift; 30241480Smckusick } 30341480Smckusick sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */ 30441480Smckusick return(inqbuf.type); 30541480Smckusick } 30641480Smckusick 30741480Smckusick int 30841480Smckusick sdinit(hd) 30941480Smckusick register struct hp_device *hd; 31041480Smckusick { 31141480Smckusick register struct sd_softc *sc = &sd_softc[hd->hp_unit]; 31241480Smckusick 31341480Smckusick sc->sc_hd = hd; 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 36141480Smckusick 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 37441480Smckusick sdopen(dev, flags) 37541480Smckusick dev_t dev; 37641480Smckusick int flags; 37741480Smckusick { 37841480Smckusick register int unit = sdunit(dev); 37941480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 38041480Smckusick 38141480Smckusick if (unit >= NSD) 38241480Smckusick return(ENXIO); 38341480Smckusick if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(u.u_cred, &u.u_acflag)) 38441480Smckusick return(ENXIO); 38541480Smckusick 38641480Smckusick if (sc->sc_hd->hp_dk >= 0) 38741480Smckusick dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms; 38841480Smckusick return(0); 38941480Smckusick } 39041480Smckusick 39141480Smckusick /* 39241480Smckusick * This routine is called for partial block transfers and non-aligned 39341480Smckusick * transfers (the latter only being possible on devices with a block size 39441480Smckusick * larger than DEV_BSIZE). The operation is performed in three steps 39541480Smckusick * using a locally allocated buffer: 39641480Smckusick * 1. transfer any initial partial block 39741480Smckusick * 2. transfer full blocks 39841480Smckusick * 3. transfer any final partial block 39941480Smckusick */ 40041480Smckusick static void 40141480Smckusick sdlblkstrat(bp, bsize) 40241480Smckusick register struct buf *bp; 40341480Smckusick register int bsize; 40441480Smckusick { 40541480Smckusick register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf), 40641480Smckusick M_DEVBUF, M_WAITOK); 40741480Smckusick caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); 40841480Smckusick register int bn, resid; 40941480Smckusick register caddr_t addr; 41041480Smckusick 41141480Smckusick bzero((caddr_t)cbp, sizeof(*cbp)); 41241480Smckusick cbp->b_proc = u.u_procp; 41341480Smckusick cbp->b_dev = bp->b_dev; 41441480Smckusick bn = bp->b_blkno; 41541480Smckusick resid = bp->b_bcount; 41641480Smckusick addr = bp->b_un.b_addr; 41741480Smckusick #ifdef DEBUG 41841480Smckusick if (sddebug & SDB_PARTIAL) 41941480Smckusick printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", 42041480Smckusick bp, bp->b_flags, bn, resid, addr); 42141480Smckusick #endif 42241480Smckusick 42341480Smckusick while (resid > 0) { 42441480Smckusick register int boff = dbtob(bn) & (bsize - 1); 42541480Smckusick register int count; 42641480Smckusick 42741480Smckusick if (boff || resid < bsize) { 42841480Smckusick sdstats[sdunit(bp->b_dev)].sdpartials++; 42941480Smckusick count = MIN(resid, bsize - boff); 43041480Smckusick cbp->b_flags = B_BUSY | B_PHYS | B_READ; 43141480Smckusick cbp->b_blkno = bn - btodb(boff); 43241480Smckusick cbp->b_un.b_addr = cbuf; 43341480Smckusick cbp->b_bcount = bsize; 43441480Smckusick #ifdef DEBUG 43541480Smckusick if (sddebug & SDB_PARTIAL) 43641480Smckusick printf(" readahead: bn %x cnt %x off %x addr %x\n", 43741480Smckusick cbp->b_blkno, count, boff, addr); 43841480Smckusick #endif 43941480Smckusick sdstrategy(cbp); 44041480Smckusick biowait(cbp); 44141480Smckusick if (cbp->b_flags & B_ERROR) { 44241480Smckusick bp->b_flags |= B_ERROR; 44341480Smckusick bp->b_error = cbp->b_error; 44441480Smckusick break; 44541480Smckusick } 44641480Smckusick if (bp->b_flags & B_READ) { 44741480Smckusick bcopy(&cbuf[boff], addr, count); 44841480Smckusick goto done; 44941480Smckusick } 45041480Smckusick bcopy(addr, &cbuf[boff], count); 45141480Smckusick #ifdef DEBUG 45241480Smckusick if (sddebug & SDB_PARTIAL) 45341480Smckusick printf(" writeback: bn %x cnt %x off %x addr %x\n", 45441480Smckusick cbp->b_blkno, count, boff, addr); 45541480Smckusick #endif 45641480Smckusick } else { 45741480Smckusick count = resid & ~(bsize - 1); 45841480Smckusick cbp->b_blkno = bn; 45941480Smckusick cbp->b_un.b_addr = addr; 46041480Smckusick cbp->b_bcount = count; 46141480Smckusick #ifdef DEBUG 46241480Smckusick if (sddebug & SDB_PARTIAL) 46341480Smckusick printf(" fulltrans: bn %x cnt %x addr %x\n", 46441480Smckusick cbp->b_blkno, count, addr); 46541480Smckusick #endif 46641480Smckusick } 46741480Smckusick cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); 46841480Smckusick sdstrategy(cbp); 46941480Smckusick biowait(cbp); 47041480Smckusick if (cbp->b_flags & B_ERROR) { 47141480Smckusick bp->b_flags |= B_ERROR; 47241480Smckusick bp->b_error = cbp->b_error; 47341480Smckusick break; 47441480Smckusick } 47541480Smckusick done: 47641480Smckusick bn += btodb(count); 47741480Smckusick resid -= count; 47841480Smckusick addr += count; 47941480Smckusick #ifdef DEBUG 48041480Smckusick if (sddebug & SDB_PARTIAL) 48141480Smckusick printf(" done: bn %x resid %x addr %x\n", 48241480Smckusick bn, resid, addr); 48341480Smckusick #endif 48441480Smckusick } 48541480Smckusick free(cbuf, M_DEVBUF); 48641480Smckusick free(cbp, M_DEVBUF); 48741480Smckusick } 48841480Smckusick 48941480Smckusick void 49041480Smckusick sdstrategy(bp) 49141480Smckusick register struct buf *bp; 49241480Smckusick { 49341480Smckusick register int unit = sdunit(bp->b_dev); 49441480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 49545750Smckusick register struct size *pinfo = &sc->sc_info.part[sdpart(bp->b_dev)]; 49641480Smckusick register struct buf *dp = &sdtab[unit]; 49745750Smckusick register daddr_t bn; 49845750Smckusick register int sz, s; 49941480Smckusick 50041480Smckusick if (sc->sc_format_pid) { 50141480Smckusick if (sc->sc_format_pid != u.u_procp->p_pid) { 50241480Smckusick bp->b_error = EPERM; 50345750Smckusick bp->b_flags |= B_ERROR; 50445750Smckusick goto done; 50541480Smckusick } 50641480Smckusick bp->b_cylin = 0; 50741480Smckusick } else { 50841480Smckusick bn = bp->b_blkno; 50945750Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 51045750Smckusick if (bn < 0 || bn + sz > pinfo->nblocks) { 51145750Smckusick sz = pinfo->nblocks - bn; 51245750Smckusick if (sz == 0) { 51341480Smckusick bp->b_resid = bp->b_bcount; 51441480Smckusick goto done; 51541480Smckusick } 51645750Smckusick if (sz < 0) { 51745750Smckusick bp->b_error = EINVAL; 51845750Smckusick bp->b_flags |= B_ERROR; 51945750Smckusick goto done; 52045750Smckusick } 52145750Smckusick bp->b_bcount = dbtob(sz); 52241480Smckusick } 52341480Smckusick /* 52441480Smckusick * Non-aligned or partial-block transfers handled specially. 52541480Smckusick */ 52641480Smckusick s = sc->sc_blksize - 1; 52741480Smckusick if ((dbtob(bn) & s) || (bp->b_bcount & s)) { 52841480Smckusick sdlblkstrat(bp, sc->sc_blksize); 52941480Smckusick goto done; 53041480Smckusick } 53145750Smckusick bp->b_cylin = (bn + pinfo->strtblk) >> sc->sc_bshift; 53241480Smckusick } 53341480Smckusick s = splbio(); 53441480Smckusick disksort(dp, bp); 53541480Smckusick if (dp->b_active == 0) { 53641480Smckusick dp->b_active = 1; 53741480Smckusick sdustart(unit); 53841480Smckusick } 53941480Smckusick splx(s); 54041480Smckusick return; 54141480Smckusick done: 54245750Smckusick biodone(bp); 54341480Smckusick } 54441480Smckusick 54541480Smckusick void 54641480Smckusick sdustart(unit) 54741480Smckusick register int unit; 54841480Smckusick { 54941480Smckusick if (scsireq(&sd_softc[unit].sc_dq)) 55041480Smckusick sdstart(unit); 55141480Smckusick } 55241480Smckusick 55345750Smckusick static int 55441480Smckusick sderror(unit, sc, hp, stat) 55541480Smckusick int unit, stat; 55641480Smckusick register struct sd_softc *sc; 55741480Smckusick register struct hp_device *hp; 55841480Smckusick { 55945750Smckusick int retry = 0; 56045750Smckusick 56141480Smckusick sdsense[unit].status = stat; 56241480Smckusick if (stat & STS_CHECKCOND) { 56341480Smckusick struct scsi_xsense *sp; 56441480Smckusick 56541480Smckusick scsi_request_sense(hp->hp_ctlr, hp->hp_slave, 56641480Smckusick sc->sc_punit, sdsense[unit].sense, 56741480Smckusick sizeof(sdsense[unit].sense)); 56841480Smckusick sp = (struct scsi_xsense *)sdsense[unit].sense; 56941480Smckusick printf("sd%d: scsi sense class %d, code %d", unit, 57041480Smckusick sp->class, sp->code); 57141480Smckusick if (sp->class == 7) { 57241480Smckusick printf(", key %d", sp->key); 57341480Smckusick if (sp->valid) 57441480Smckusick printf(", blk %d", *(int *)&sp->info1); 57545750Smckusick /* no sense or recovered error, try again */ 57645750Smckusick if (sp->key == 0 || sp->key == 1) 57745750Smckusick retry = 1; 57841480Smckusick } 57941480Smckusick printf("\n"); 58041480Smckusick } 58145750Smckusick return(retry); 58241480Smckusick } 58341480Smckusick 58441480Smckusick static void 58541480Smckusick sdfinish(unit, sc, bp) 58641480Smckusick int unit; 58741480Smckusick register struct sd_softc *sc; 58841480Smckusick register struct buf *bp; 58941480Smckusick { 59041480Smckusick sdtab[unit].b_errcnt = 0; 59141480Smckusick sdtab[unit].b_actf = bp->b_actf; 59241480Smckusick bp->b_resid = 0; 59345750Smckusick biodone(bp); 59441480Smckusick scsifree(&sc->sc_dq); 59541480Smckusick if (sdtab[unit].b_actf) 59641480Smckusick sdustart(unit); 59741480Smckusick else 59841480Smckusick sdtab[unit].b_active = 0; 59941480Smckusick } 60041480Smckusick 60141480Smckusick void 60241480Smckusick sdstart(unit) 60341480Smckusick register int unit; 60441480Smckusick { 60541480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 60641480Smckusick register struct hp_device *hp = sc->sc_hd; 60741480Smckusick 60841480Smckusick /* 60941480Smckusick * we have the SCSI bus -- in format mode, we may or may not need dma 61041480Smckusick * so check now. 61141480Smckusick */ 61241480Smckusick if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) { 61341480Smckusick register struct buf *bp = sdtab[unit].b_actf; 61441480Smckusick register int sts; 61541480Smckusick 61641480Smckusick sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave, 61741480Smckusick sc->sc_punit, &sdcmd[unit], 61841480Smckusick bp->b_un.b_addr, bp->b_bcount, 61941480Smckusick bp->b_flags & B_READ); 62041480Smckusick sdsense[unit].status = sts; 62141480Smckusick if (sts & 0xfe) { 62245750Smckusick (void) sderror(unit, sc, hp, sts); 62341480Smckusick bp->b_flags |= B_ERROR; 62441480Smckusick bp->b_error = EIO; 62541480Smckusick } 62641480Smckusick sdfinish(unit, sc, bp); 62741480Smckusick 62841480Smckusick } else if (scsiustart(hp->hp_ctlr)) 62941480Smckusick sdgo(unit); 63041480Smckusick } 63141480Smckusick 63241480Smckusick void 63341480Smckusick sdgo(unit) 63441480Smckusick register int unit; 63541480Smckusick { 63641480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 63741480Smckusick register struct hp_device *hp = sc->sc_hd; 63841480Smckusick register struct buf *bp = sdtab[unit].b_actf; 63941480Smckusick register int pad; 64041480Smckusick register struct scsi_fmt_cdb *cmd; 64141480Smckusick 64241480Smckusick if (sc->sc_format_pid) { 64341480Smckusick cmd = &sdcmd[unit]; 64441480Smckusick pad = 0; 64541480Smckusick } else { 64641480Smckusick cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd; 64741480Smckusick *(int *)(&cmd->cdb[2]) = bp->b_cylin; 64841480Smckusick pad = howmany(bp->b_bcount, sc->sc_blksize); 64941480Smckusick *(u_short *)(&cmd->cdb[7]) = pad; 65041480Smckusick pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0; 65141480Smckusick #ifdef DEBUG 65241480Smckusick if (pad) 65341480Smckusick printf("sd%d: partial block xfer -- %x bytes\n", 65441480Smckusick unit, bp->b_bcount); 65541480Smckusick #endif 65641480Smckusick sdstats[unit].sdtransfers++; 65741480Smckusick } 65841480Smckusick if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) { 65941480Smckusick if (hp->hp_dk >= 0) { 66041480Smckusick dk_busy |= 1 << hp->hp_dk; 66141480Smckusick ++dk_seek[hp->hp_dk]; 66241480Smckusick ++dk_xfer[hp->hp_dk]; 66341480Smckusick dk_wds[hp->hp_dk] += bp->b_bcount >> 6; 66441480Smckusick } 66541480Smckusick return; 66641480Smckusick } 66741480Smckusick #ifdef DEBUG 66841480Smckusick if (sddebug & SDB_ERROR) 66941480Smckusick printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n", 67041480Smckusick unit, bp->b_flags & B_READ? "read" : "write", 67141480Smckusick bp->b_un.b_addr, bp->b_cylin, bp->b_bcount, 67241480Smckusick sdtab[unit].b_errcnt); 67341480Smckusick #endif 67441480Smckusick bp->b_flags |= B_ERROR; 67541480Smckusick bp->b_error = EIO; 67641480Smckusick sdfinish(unit, sc, bp); 67741480Smckusick } 67841480Smckusick 67941480Smckusick void 68041480Smckusick sdintr(unit, stat) 68141480Smckusick register int unit; 68241480Smckusick int stat; 68341480Smckusick { 68441480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 68541480Smckusick register struct buf *bp = sdtab[unit].b_actf; 68641480Smckusick register struct hp_device *hp = sc->sc_hd; 68745750Smckusick int retry; 68841480Smckusick 68941480Smckusick if (bp == NULL) { 69041480Smckusick printf("sd%d: bp == NULL\n", unit); 69141480Smckusick return; 69241480Smckusick } 69341480Smckusick if (hp->hp_dk >= 0) 69441480Smckusick dk_busy &=~ (1 << hp->hp_dk); 69541480Smckusick if (stat) { 69641480Smckusick #ifdef DEBUG 69741480Smckusick if (sddebug & SDB_ERROR) 69841480Smckusick printf("sd%d: sdintr: bad scsi status 0x%x\n", 69941480Smckusick unit, stat); 70041480Smckusick #endif 70145750Smckusick retry = sderror(unit, sc, hp, stat); 70245750Smckusick if (retry && sdtab[unit].b_errcnt++ < SDRETRY) { 70345750Smckusick printf("sd%d: retry #%d\n", 70445750Smckusick unit, sdtab[unit].b_errcnt); 70545750Smckusick sdstart(unit); 70645750Smckusick return; 70745750Smckusick } 70841480Smckusick bp->b_flags |= B_ERROR; 70941480Smckusick bp->b_error = EIO; 71041480Smckusick } 71141480Smckusick sdfinish(unit, sc, bp); 71241480Smckusick } 71341480Smckusick 71441480Smckusick int 71541480Smckusick sdread(dev, uio) 71641480Smckusick dev_t dev; 71741480Smckusick struct uio *uio; 71841480Smckusick { 71941480Smckusick register int unit = sdunit(dev); 72041480Smckusick register int pid; 72141480Smckusick 72241480Smckusick if ((pid = sd_softc[unit].sc_format_pid) && pid != u.u_procp->p_pid) 72341480Smckusick return (EPERM); 72441480Smckusick 72541480Smckusick return(physio(sdstrategy, &sdbuf[unit], dev, B_READ, minphys, uio)); 72641480Smckusick } 72741480Smckusick 72841480Smckusick int 72941480Smckusick sdwrite(dev, uio) 73041480Smckusick dev_t dev; 73141480Smckusick struct uio *uio; 73241480Smckusick { 73341480Smckusick register int unit = sdunit(dev); 73441480Smckusick register int pid; 73541480Smckusick 73641480Smckusick if ((pid = sd_softc[unit].sc_format_pid) && pid != u.u_procp->p_pid) 73741480Smckusick return (EPERM); 73841480Smckusick 73941480Smckusick return(physio(sdstrategy, &sdbuf[unit], dev, B_WRITE, minphys, uio)); 74041480Smckusick } 74141480Smckusick 74241480Smckusick int 74341480Smckusick sdioctl(dev, cmd, data, flag) 74441480Smckusick dev_t dev; 74541480Smckusick int cmd; 74641480Smckusick caddr_t data; 74741480Smckusick int flag; 74841480Smckusick { 74941480Smckusick register int unit = sdunit(dev); 75041480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 75141480Smckusick 75241480Smckusick switch (cmd) { 75341480Smckusick default: 75441480Smckusick return (EINVAL); 75541480Smckusick 75641480Smckusick case SDIOCSFORMAT: 75741480Smckusick /* take this device into or out of "format" mode */ 75841480Smckusick if (suser(u.u_cred, &u.u_acflag)) 75941480Smckusick return(EPERM); 76041480Smckusick 76141480Smckusick if (*(int *)data) { 76241480Smckusick if (sc->sc_format_pid) 76341480Smckusick return (EPERM); 76441480Smckusick sc->sc_format_pid = u.u_procp->p_pid; 76541480Smckusick } else 76641480Smckusick sc->sc_format_pid = 0; 76741480Smckusick return (0); 76841480Smckusick 76941480Smckusick case SDIOCGFORMAT: 77041480Smckusick /* find out who has the device in format mode */ 77141480Smckusick *(int *)data = sc->sc_format_pid; 77241480Smckusick return (0); 77341480Smckusick 77441480Smckusick case SDIOCSCSICOMMAND: 77541480Smckusick /* 77641480Smckusick * Save what user gave us as SCSI cdb to use with next 77741480Smckusick * read or write to the char device. 77841480Smckusick */ 77941480Smckusick if (sc->sc_format_pid != u.u_procp->p_pid) 78041480Smckusick return (EPERM); 78141480Smckusick if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) 78241480Smckusick return (EINVAL); 78341480Smckusick bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0])); 78441480Smckusick return (0); 78541480Smckusick 78641480Smckusick case SDIOCSENSE: 78741480Smckusick /* 78841480Smckusick * return the SCSI sense data saved after the last 78941480Smckusick * operation that completed with "check condition" status. 79041480Smckusick */ 79141480Smckusick bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0])); 79241480Smckusick return (0); 79341480Smckusick 79441480Smckusick } 79541480Smckusick /*NOTREACHED*/ 79641480Smckusick } 79741480Smckusick 79841480Smckusick int 79941480Smckusick sdsize(dev) 80041480Smckusick dev_t dev; 80141480Smckusick { 80241480Smckusick register int unit = sdunit(dev); 80341480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 80441480Smckusick 80541480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 80641480Smckusick return(-1); 80741480Smckusick 80841480Smckusick return(sc->sc_info.part[sdpart(dev)].nblocks); 80941480Smckusick } 81041480Smckusick 81141480Smckusick /* 81241480Smckusick * Non-interrupt driven, non-dma dump routine. 81341480Smckusick */ 81441480Smckusick int 81541480Smckusick sddump(dev) 81641480Smckusick dev_t dev; 81741480Smckusick { 81841480Smckusick int part = sdpart(dev); 81941480Smckusick int unit = sdunit(dev); 82041480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 82141480Smckusick register struct hp_device *hp = sc->sc_hd; 82241480Smckusick register daddr_t baddr; 82341480Smckusick register int maddr; 82441480Smckusick register int pages, i; 82541480Smckusick int stat; 82641480Smckusick extern int lowram; 82741480Smckusick 82841480Smckusick /* 82941480Smckusick * Hmm... all vax drivers dump maxfree pages which is physmem minus 83041480Smckusick * the message buffer. Is there a reason for not dumping the 83141480Smckusick * message buffer? Savecore expects to read 'dumpsize' pages of 83241480Smckusick * dump, where dumpsys() sets dumpsize to physmem! 83341480Smckusick */ 83441480Smckusick pages = physmem; 83541480Smckusick 83641480Smckusick /* is drive ok? */ 83741480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 83841480Smckusick return (ENXIO); 83941480Smckusick /* dump parameters in range? */ 84041480Smckusick if (dumplo < 0 || dumplo >= sc->sc_info.part[part].nblocks) 84141480Smckusick return (EINVAL); 84241480Smckusick if (dumplo + ctod(pages) > sc->sc_info.part[part].nblocks) 84341480Smckusick pages = dtoc(sc->sc_info.part[part].nblocks - dumplo); 84441480Smckusick maddr = lowram; 84541480Smckusick baddr = dumplo + sc->sc_info.part[part].strtblk; 84641480Smckusick /* scsi bus idle? */ 84741480Smckusick if (!scsireq(&sc->sc_dq)) { 84841480Smckusick scsireset(hp->hp_ctlr); 84941480Smckusick sdreset(sc, sc->sc_hd); 85041480Smckusick printf("[ drive %d reset ] ", unit); 85141480Smckusick } 85241480Smckusick for (i = 0; i < pages; i++) { 85341480Smckusick #define NPGMB (1024*1024/NBPG) 85441480Smckusick /* print out how many Mbs we have dumped */ 85541480Smckusick if (i && (i % NPGMB) == 0) 85641480Smckusick printf("%d ", i / NPGMB); 85741480Smckusick #undef NPBMG 85845750Smckusick pmap_enter(pmap_kernel(), vmmap, maddr, VM_PROT_READ, TRUE); 85941480Smckusick stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, 86041480Smckusick vmmap, NBPG, baddr, sc->sc_bshift); 86141480Smckusick if (stat) { 86241480Smckusick printf("sddump: scsi write error 0x%x\n", stat); 86341480Smckusick return (EIO); 86441480Smckusick } 86541480Smckusick maddr += NBPG; 86641480Smckusick baddr += ctod(1); 86741480Smckusick } 86841480Smckusick return (0); 86941480Smckusick } 87041480Smckusick #endif 871