141480Smckusick /* 263151Sbostic * Copyright (c) 1990, 1993 363151Sbostic * The Regents of the University of California. All rights reserved. 441480Smckusick * 541480Smckusick * This code is derived from software contributed to Berkeley by 641480Smckusick * Van Jacobson of Lawrence Berkeley Laboratory. 741480Smckusick * 841480Smckusick * %sccs.include.redist.c% 941480Smckusick * 10*67184Shibler * @(#)sd.c 8.5 (Berkeley) 05/19/94 1141480Smckusick */ 1241480Smckusick 1341480Smckusick /* 1441480Smckusick * SCSI CCS (Command Command Set) disk driver. 1541480Smckusick */ 1641480Smckusick #include "sd.h" 1741480Smckusick #if NSD > 0 1841480Smckusick 1941480Smckusick #ifndef lint 2065662Shibler static char rcsid[] = "$Header: /sys.lite/hp300/dev/RCS/sd.c,v 1.2 1994/01/10 18:29:19 mike Exp mike $"; 2141480Smckusick #endif 2241480Smckusick 2356507Sbostic #include <sys/param.h> 2456507Sbostic #include <sys/systm.h> 2556507Sbostic #include <sys/buf.h> 2657327Shibler #include <sys/stat.h> 2756507Sbostic #include <sys/dkstat.h> 2856507Sbostic #include <sys/disklabel.h> 2956507Sbostic #include <sys/malloc.h> 3056507Sbostic #include <sys/proc.h> 3156507Sbostic #include <sys/ioctl.h> 3257327Shibler #include <sys/fcntl.h> 3341480Smckusick 3456507Sbostic #include <hp/dev/device.h> 3556507Sbostic #include <hp300/dev/scsireg.h> 3657327Shibler #include <hp300/dev/sdvar.h> 3757327Shibler #ifdef USELEDS 3857327Shibler #include <hp300/hp300/led.h> 3957327Shibler #endif 4045750Smckusick 4156507Sbostic #include <vm/vm_param.h> 4256507Sbostic #include <vm/lock.h> 4356507Sbostic #include <vm/vm_prot.h> 4456507Sbostic #include <vm/pmap.h> 4556507Sbostic 4641480Smckusick extern int scsi_test_unit_rdy(); 4741480Smckusick extern int scsi_request_sense(); 4841480Smckusick extern int scsi_inquiry(); 4941480Smckusick extern int scsi_read_capacity(); 5041480Smckusick extern int scsi_tt_write(); 5141480Smckusick extern int scsireq(); 5241480Smckusick extern int scsiustart(); 5341480Smckusick extern int scsigo(); 5441480Smckusick extern void scsifree(); 5541480Smckusick extern void scsireset(); 5649304Shibler extern void scsi_delay(); 5741480Smckusick 5841480Smckusick extern void disksort(); 5941480Smckusick extern void biodone(); 6041480Smckusick extern int physio(); 6141480Smckusick extern void TBIS(); 6241480Smckusick 6341480Smckusick int sdinit(); 6441480Smckusick void sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr(); 6541480Smckusick 6641480Smckusick struct driver sddriver = { 6741480Smckusick sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr, 6841480Smckusick }; 6941480Smckusick 7041480Smckusick #ifdef DEBUG 7141480Smckusick int sddebug = 1; 7241480Smckusick #define SDB_ERROR 0x01 7341480Smckusick #define SDB_PARTIAL 0x02 7465662Shibler #define SDB_CAPACITY 0x04 7541480Smckusick #endif 7641480Smckusick 7757327Shibler struct sd_softc sd_softc[NSD]; 7857327Shibler struct sdstats sdstats[NSD]; 7941480Smckusick struct buf sdtab[NSD]; 8041480Smckusick struct scsi_fmt_cdb sdcmd[NSD]; 8141480Smckusick struct scsi_fmt_sense sdsense[NSD]; 8241480Smckusick 8341480Smckusick static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT }; 8441480Smckusick static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT }; 8541480Smckusick 8641480Smckusick /* 8741480Smckusick * Table of scsi commands users are allowed to access via "format" 8841480Smckusick * mode. 0 means not legal. 1 means "immediate" (doesn't need dma). 8941480Smckusick * -1 means needs dma and/or wait for intr. 9041480Smckusick */ 9141480Smckusick static char legal_cmds[256] = { 9241480Smckusick /***** 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 9341480Smckusick /*00*/ 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9441480Smckusick /*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 9541480Smckusick /*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9641480Smckusick /*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9741480Smckusick /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9841480Smckusick /*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9941480Smckusick /*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10041480Smckusick /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10141480Smckusick /*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10241480Smckusick /*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10341480Smckusick /*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10441480Smckusick /*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10541480Smckusick /*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10641480Smckusick /*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10741480Smckusick /*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10841480Smckusick /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10941480Smckusick }; 11041480Smckusick 11141480Smckusick static struct scsi_inquiry inqbuf; 11241480Smckusick static struct scsi_fmt_cdb inq = { 11341480Smckusick 6, 11441480Smckusick CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 11541480Smckusick }; 11641480Smckusick 11741480Smckusick static int 11841480Smckusick sdident(sc, hd) 11941480Smckusick struct sd_softc *sc; 12041480Smckusick struct hp_device *hd; 12141480Smckusick { 12241480Smckusick int unit; 12341480Smckusick register int ctlr, slave; 12441480Smckusick register int i; 12541480Smckusick register int tries = 10; 12649304Shibler char idstr[32]; 12765662Shibler int isrm = 0; 12841480Smckusick 12941480Smckusick ctlr = hd->hp_ctlr; 13041480Smckusick slave = hd->hp_slave; 13141480Smckusick unit = sc->sc_punit; 13249304Shibler scsi_delay(-1); 13341480Smckusick 13441480Smckusick /* 13541480Smckusick * See if unit exists and is a disk then read block size & nblocks. 13641480Smckusick */ 13741480Smckusick while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) { 13845750Smckusick if (i == -1 || --tries < 0) { 13965662Shibler if (isrm) 14045750Smckusick break; 14141480Smckusick /* doesn't exist or not a CCS device */ 14249304Shibler goto failed; 14345750Smckusick } 14441480Smckusick if (i == STS_CHECKCOND) { 14541480Smckusick u_char sensebuf[128]; 14641480Smckusick struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf; 14741480Smckusick 14841480Smckusick scsi_request_sense(ctlr, slave, unit, sensebuf, 14941480Smckusick sizeof(sensebuf)); 15045750Smckusick if (sp->class == 7) 15145750Smckusick switch (sp->key) { 15265662Shibler /* 15365662Shibler * Not ready -- might be removable media 15465662Shibler * device with no media. Assume as much, 15565662Shibler * if it really isn't, the inquiry commmand 15665662Shibler * below will fail. 15765662Shibler */ 15845750Smckusick case 2: 15965662Shibler isrm = 1; 16045750Smckusick break; 16141480Smckusick /* drive doing an RTZ -- give it a while */ 16245750Smckusick case 6: 16345750Smckusick DELAY(1000000); 16445750Smckusick break; 16545750Smckusick default: 16645750Smckusick break; 16745750Smckusick } 16841480Smckusick } 16941480Smckusick DELAY(1000); 17041480Smckusick } 17145750Smckusick /* 17245750Smckusick * Find out about device 17345750Smckusick */ 17445750Smckusick if (scsi_immed_command(ctlr, slave, unit, &inq, 17545750Smckusick (u_char *)&inqbuf, sizeof(inqbuf), B_READ)) 17649304Shibler goto failed; 17741480Smckusick switch (inqbuf.type) { 17841480Smckusick case 0: /* disk */ 17941480Smckusick case 4: /* WORM */ 18041480Smckusick case 5: /* CD-ROM */ 18141480Smckusick case 7: /* Magneto-optical */ 18241480Smckusick break; 18341480Smckusick default: /* not a disk */ 18449304Shibler goto failed; 18541480Smckusick } 18645750Smckusick /* 18749304Shibler * Get a usable id string 18845750Smckusick */ 18957327Shibler switch (inqbuf.version) { 19057327Shibler case 1: 19157327Shibler case 2: 19249304Shibler bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28); 19349304Shibler for (i = 27; i > 23; --i) 19449304Shibler if (idstr[i] != ' ') 19549304Shibler break; 19649304Shibler idstr[i+1] = 0; 19749304Shibler for (i = 23; i > 7; --i) 19849304Shibler if (idstr[i] != ' ') 19949304Shibler break; 20049304Shibler idstr[i+1] = 0; 20149304Shibler for (i = 7; i >= 0; --i) 20249304Shibler if (idstr[i] != ' ') 20349304Shibler break; 20449304Shibler idstr[i+1] = 0; 20557327Shibler break; 20657327Shibler default: 20757327Shibler bcopy("UNKNOWN", &idstr[0], 8); 20857327Shibler bcopy("DRIVE TYPE", &idstr[8], 11); 20945750Smckusick } 21065662Shibler if (inqbuf.qual & 0x80) 21165662Shibler sc->sc_flags |= SDF_RMEDIA; 21245750Smckusick 21365662Shibler if (sdgetcapacity(sc, hd, NODEV) < 0) 21465662Shibler goto failed; 21565662Shibler 21657327Shibler switch (inqbuf.version) { 21757327Shibler case 1: 21857327Shibler case 2: 21941480Smckusick printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8], 22041480Smckusick &idstr[24]); 22157327Shibler if (inqbuf.version == 2) 22257327Shibler printf(" (SCSI-2)"); 22357327Shibler break; 22457327Shibler default: 22557327Shibler printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit, 22657327Shibler inqbuf.type, inqbuf.qual, inqbuf.version); 22757327Shibler break; 22857327Shibler } 22965662Shibler if (sc->sc_blks) 23065662Shibler printf(", %d %d byte blocks", 23165662Shibler sc->sc_blks >> sc->sc_bshift, sc->sc_blksize); 23265662Shibler printf("\n"); 23341480Smckusick sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */ 23449304Shibler scsi_delay(0); 23541480Smckusick return(inqbuf.type); 23649304Shibler failed: 23749304Shibler scsi_delay(0); 23849304Shibler return(-1); 23941480Smckusick } 24041480Smckusick 24141480Smckusick int 24241480Smckusick sdinit(hd) 24341480Smckusick register struct hp_device *hd; 24441480Smckusick { 24541480Smckusick register struct sd_softc *sc = &sd_softc[hd->hp_unit]; 24641480Smckusick 24741480Smckusick sc->sc_hd = hd; 24853929Shibler sc->sc_flags = 0; 24966072Shibler /* 25066072Shibler * XXX formerly 0 meant unused but now pid 0 can legitimately 25166072Shibler * use this interface (sdgetcapacity). 25266072Shibler */ 25366072Shibler sc->sc_format_pid = -1; 25441480Smckusick sc->sc_punit = sdpunit(hd->hp_flags); 25541480Smckusick sc->sc_type = sdident(sc, hd); 25641480Smckusick if (sc->sc_type < 0) 25741480Smckusick return(0); 25841480Smckusick sc->sc_dq.dq_ctlr = hd->hp_ctlr; 25941480Smckusick sc->sc_dq.dq_unit = hd->hp_unit; 26041480Smckusick sc->sc_dq.dq_slave = hd->hp_slave; 26141480Smckusick sc->sc_dq.dq_driver = &sddriver; 26241480Smckusick 26353929Shibler sc->sc_flags |= SDF_ALIVE; 26441480Smckusick return(1); 26541480Smckusick } 26641480Smckusick 26741480Smckusick void 26841480Smckusick sdreset(sc, hd) 26941480Smckusick register struct sd_softc *sc; 27041480Smckusick register struct hp_device *hd; 27141480Smckusick { 27241480Smckusick sdstats[hd->hp_unit].sdresets++; 27341480Smckusick } 27441480Smckusick 27557327Shibler /* 27665662Shibler * Determine capacity of a drive. 27765662Shibler * Returns -1 on a failure, 0 on success, 1 on a failure that is probably 27865662Shibler * due to missing media. 27965662Shibler */ 28065662Shibler int 28165662Shibler sdgetcapacity(sc, hd, dev) 28265662Shibler struct sd_softc *sc; 28365662Shibler struct hp_device *hd; 28465662Shibler dev_t dev; 28565662Shibler { 28665662Shibler static struct scsi_fmt_cdb cap = { 28765662Shibler 10, 28865662Shibler CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 28965662Shibler }; 29066072Shibler u_char *capbuf; 29166072Shibler int i, capbufsize; 29265662Shibler 29366072Shibler /* 29466072Shibler * Cannot use stack space for this buffer since stack KVA may not 29566072Shibler * be valid (i.e. in context of this process) when the operation 29666072Shibler * actually starts. 29766072Shibler */ 29866072Shibler capbufsize = 8; 29966072Shibler capbuf = malloc(capbufsize, M_DEVBUF, M_WAITOK); 30066072Shibler 30165662Shibler if (dev == NODEV) { 30265662Shibler i = scsi_immed_command(hd->hp_ctlr, hd->hp_slave, sc->sc_punit, 30366072Shibler &cap, capbuf, capbufsize, B_READ); 30465662Shibler } else { 30566072Shibler struct buf *bp; 30666072Shibler 30765662Shibler /* 30865662Shibler * XXX this is horrible 30965662Shibler */ 31066072Shibler if (sc->sc_format_pid >= 0) 31165662Shibler panic("sdgetcapacity"); 31266072Shibler bp = malloc(sizeof *bp, M_DEVBUF, M_WAITOK); 31365662Shibler sc->sc_format_pid = curproc->p_pid; 31465662Shibler bcopy((caddr_t)&cap, (caddr_t)&sdcmd[hd->hp_unit], sizeof cap); 31566072Shibler bp->b_dev = dev; 31666072Shibler bp->b_flags = B_READ | B_BUSY; 31766072Shibler bp->b_un.b_addr = (caddr_t)capbuf; 31866072Shibler bp->b_bcount = capbufsize; 31966072Shibler sdstrategy(bp); 32066072Shibler i = biowait(bp) ? sdsense[hd->hp_unit].status : 0; 32166072Shibler free(bp, M_DEVBUF); 32266072Shibler sc->sc_format_pid = -1; 32365662Shibler } 32465662Shibler if (i) { 32565662Shibler if (i != STS_CHECKCOND || (sc->sc_flags & SDF_RMEDIA) == 0) { 32665662Shibler #ifdef DEBUG 32765662Shibler if (sddebug & SDB_CAPACITY) 32865662Shibler printf("sd%d: read_capacity returns %d\n", 32965662Shibler hd->hp_unit, i); 33065662Shibler #endif 33166072Shibler free(capbuf, M_DEVBUF); 33265662Shibler return (-1); 33365662Shibler } 33465662Shibler /* 33565662Shibler * XXX assume unformatted or non-existant media 33665662Shibler */ 33765662Shibler sc->sc_blks = 0; 33865662Shibler sc->sc_blksize = DEV_BSIZE; 33965662Shibler sc->sc_bshift = 0; 34065662Shibler #ifdef DEBUG 34165662Shibler if (sddebug & SDB_CAPACITY) 34265662Shibler printf("sd%d: removable media not present\n", 34365662Shibler hd->hp_unit); 34465662Shibler #endif 34566072Shibler free(capbuf, M_DEVBUF); 34665662Shibler return (1); 34765662Shibler } 34865662Shibler sc->sc_blks = *(u_int *)&capbuf[0]; 34965662Shibler sc->sc_blksize = *(int *)&capbuf[4]; 35066072Shibler free(capbuf, M_DEVBUF); 35165662Shibler sc->sc_bshift = 0; 35265662Shibler 35365662Shibler /* return value of read capacity is last valid block number */ 35465662Shibler sc->sc_blks++; 35565662Shibler 35665662Shibler if (sc->sc_blksize != DEV_BSIZE) { 35765662Shibler if (sc->sc_blksize < DEV_BSIZE) { 35866072Shibler printf("sd%d: need at least %d byte blocks - %s\n", 35966072Shibler hd->hp_unit, DEV_BSIZE, "drive ignored"); 36065662Shibler return (-1); 36165662Shibler } 36265662Shibler for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) 36365662Shibler ++sc->sc_bshift; 36465662Shibler sc->sc_blks <<= sc->sc_bshift; 36565662Shibler } 36665662Shibler #ifdef DEBUG 36765662Shibler if (sddebug & SDB_CAPACITY) 36865662Shibler printf("sd%d: blks=%d, blksize=%d, bshift=%d\n", hd->hp_unit, 36965662Shibler sc->sc_blks, sc->sc_blksize, sc->sc_bshift); 37065662Shibler #endif 37165662Shibler return (0); 37265662Shibler } 37365662Shibler 37465662Shibler /* 37557327Shibler * Read or constuct a disklabel 37657327Shibler */ 37741480Smckusick int 37857327Shibler sdgetinfo(dev) 37957327Shibler dev_t dev; 38057327Shibler { 38157327Shibler int unit = sdunit(dev); 38257327Shibler register struct sd_softc *sc = &sd_softc[unit]; 38357327Shibler register struct disklabel *lp = &sc->sc_info.si_label; 38457327Shibler register struct partition *pi; 38557327Shibler char *msg, *readdisklabel(); 38665662Shibler #ifdef COMPAT_NOLABEL 38765662Shibler int usedefault = 1; 38857327Shibler 38957327Shibler /* 39065662Shibler * For CD-ROM just define a single partition 39157327Shibler */ 39265662Shibler if (sc->sc_type == 5) 39365662Shibler usedefault = 0; 39465662Shibler #endif 39565662Shibler 39657327Shibler bzero((caddr_t)lp, sizeof *lp); 39765662Shibler msg = NULL; 39857327Shibler 39957327Shibler /* 40065662Shibler * If removable media or the size unavailable at boot time 40165662Shibler * (i.e. unformatted hard disk), attempt to set the capacity 40265662Shibler * now. 40357327Shibler */ 40465662Shibler if ((sc->sc_flags & SDF_RMEDIA) || sc->sc_blks == 0) { 40565662Shibler switch (sdgetcapacity(sc, sc->sc_hd, dev)) { 40665662Shibler case 0: 40765662Shibler break; 40865662Shibler case -1: 40965662Shibler /* 41065662Shibler * Hard error, just return (open will fail). 41165662Shibler */ 41265662Shibler return (EIO); 41365662Shibler case 1: 41465662Shibler /* 41565662Shibler * XXX return 0 so open can continue just in case 41665662Shibler * the media is unformatted and we want to format it. 41765662Shibler * We set the error flag so they cannot do much else. 41865662Shibler */ 41965662Shibler sc->sc_flags |= SDF_ERROR; 42065662Shibler msg = "unformatted/missing media"; 42165662Shibler #ifdef COMPAT_NOLABEL 42265662Shibler usedefault = 0; 42365662Shibler #endif 42465662Shibler break; 42565662Shibler } 42665662Shibler } 42757327Shibler 42865662Shibler /* 42965662Shibler * Set some default values to use while reading the label 43065662Shibler * (or to use if there isn't a label) and try reading it. 43165662Shibler */ 43265662Shibler if (msg == NULL) { 43365662Shibler lp->d_type = DTYPE_SCSI; 43465662Shibler lp->d_secsize = DEV_BSIZE; 43565662Shibler lp->d_nsectors = 32; 43665662Shibler lp->d_ntracks = 20; 43765662Shibler lp->d_ncylinders = 1; 43865662Shibler lp->d_secpercyl = 32*20; 43965662Shibler lp->d_npartitions = 3; 44065662Shibler lp->d_partitions[2].p_offset = 0; 44165662Shibler /* XXX we can open a device even without SDF_ALIVE */ 44265662Shibler if (sc->sc_blksize == 0) 44365662Shibler sc->sc_blksize = DEV_BSIZE; 44465662Shibler /* XXX ensure size is at least one device block */ 44565662Shibler lp->d_partitions[2].p_size = 44665662Shibler roundup(LABELSECTOR+1, btodb(sc->sc_blksize)); 44765662Shibler msg = readdisklabel(sdlabdev(dev), sdstrategy, lp); 44865662Shibler if (msg == NULL) 44965662Shibler return (0); 45065662Shibler } 45165662Shibler 45257327Shibler pi = lp->d_partitions; 45357327Shibler printf("sd%d: WARNING: %s, ", unit, msg); 45457327Shibler #ifdef COMPAT_NOLABEL 45565662Shibler if (usedefault) { 45665662Shibler printf("using old default partitioning\n"); 45765662Shibler sdmakedisklabel(unit, lp); 45865662Shibler return(0); 45965662Shibler } 46065662Shibler #endif 46157327Shibler printf("defining `c' partition as entire disk\n"); 46257327Shibler pi[2].p_size = sc->sc_blks; 463*67184Shibler /* XXX reset other info since readdisklabel screws with it */ 464*67184Shibler lp->d_npartitions = 3; 465*67184Shibler pi[0].p_size = 0; 46657327Shibler return(0); 46757327Shibler } 46857327Shibler 46957327Shibler int 47049132Skarels sdopen(dev, flags, mode, p) 47141480Smckusick dev_t dev; 47249132Skarels int flags, mode; 47349132Skarels struct proc *p; 47441480Smckusick { 47541480Smckusick register int unit = sdunit(dev); 47641480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 47757327Shibler int mask, error; 47841480Smckusick 47941480Smckusick if (unit >= NSD) 48041480Smckusick return(ENXIO); 48167054Shibler /* 48267054Shibler * If a drive's position was fully qualified (i.e. not wildcarded in 48367054Shibler * any way, we allow root to open the device even though it wasn't 48467054Shibler * found at autoconfig time. This allows initial formatting of disks. 48567054Shibler * However, if any part of the specification was wildcarded, we won't 48667054Shibler * be able to locate the drive so there is nothing we can do. 48767054Shibler */ 48867054Shibler if ((sc->sc_flags & SDF_ALIVE) == 0 && 48967054Shibler (suser(p->p_ucred, &p->p_acflag) || 49067054Shibler sc->sc_hd->hp_ctlr < 0 || sc->sc_hd->hp_slave < 0)) 49141480Smckusick return(ENXIO); 49257327Shibler if (sc->sc_flags & SDF_ERROR) 49357327Shibler return(EIO); 49441480Smckusick 49557327Shibler /* 49657327Shibler * Wait for any pending opens/closes to complete 49757327Shibler */ 49857327Shibler while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING)) 49957327Shibler sleep((caddr_t)sc, PRIBIO); 50057327Shibler /* 50157327Shibler * On first open, get label and partition info. 50257327Shibler * We may block reading the label, so be careful 50357327Shibler * to stop any other opens. 50457327Shibler */ 50557327Shibler if (sc->sc_info.si_open == 0) { 50657327Shibler sc->sc_flags |= SDF_OPENING; 50757327Shibler error = sdgetinfo(dev); 50857327Shibler sc->sc_flags &= ~SDF_OPENING; 50957327Shibler wakeup((caddr_t)sc); 51057327Shibler if (error) 51157327Shibler return(error); 51257327Shibler } 51341480Smckusick if (sc->sc_hd->hp_dk >= 0) 51441480Smckusick dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms; 51557327Shibler 51657327Shibler mask = 1 << sdpart(dev); 51757327Shibler if (mode == S_IFCHR) 51857327Shibler sc->sc_info.si_copen |= mask; 51957327Shibler else 52057327Shibler sc->sc_info.si_bopen |= mask; 52157327Shibler sc->sc_info.si_open |= mask; 52241480Smckusick return(0); 52341480Smckusick } 52441480Smckusick 52553929Shibler int 52653929Shibler sdclose(dev, flag, mode, p) 52753929Shibler dev_t dev; 52853929Shibler int flag, mode; 52953929Shibler struct proc *p; 53053929Shibler { 53153929Shibler int unit = sdunit(dev); 53253929Shibler register struct sd_softc *sc = &sd_softc[unit]; 53357327Shibler register struct sdinfo *si = &sc->sc_info; 53457327Shibler int mask, s; 53553929Shibler 53657327Shibler mask = 1 << sdpart(dev); 53757327Shibler if (mode == S_IFCHR) 53857327Shibler si->si_copen &= ~mask; 53957327Shibler else 54057327Shibler si->si_bopen &= ~mask; 54157327Shibler si->si_open = si->si_bopen | si->si_copen; 54253929Shibler /* 54357327Shibler * On last close, we wait for all activity to cease since 54457327Shibler * the label/parition info will become invalid. Since we 54557327Shibler * might sleep, we must block any opens while we are here. 54657327Shibler * Note we don't have to about other closes since we know 54757327Shibler * we are the last one. 54853929Shibler */ 54957327Shibler if (si->si_open == 0) { 55057327Shibler sc->sc_flags |= SDF_CLOSING; 55153929Shibler s = splbio(); 55253929Shibler while (sdtab[unit].b_active) { 55353929Shibler sc->sc_flags |= SDF_WANTED; 55453929Shibler sleep((caddr_t)&sdtab[unit], PRIBIO); 55553929Shibler } 55653929Shibler splx(s); 55757327Shibler sc->sc_flags &= ~(SDF_CLOSING|SDF_WLABEL|SDF_ERROR); 55857327Shibler wakeup((caddr_t)sc); 55953929Shibler } 56066072Shibler sc->sc_format_pid = -1; 56157327Shibler return(0); 56253929Shibler } 56353929Shibler 56441480Smckusick /* 56541480Smckusick * This routine is called for partial block transfers and non-aligned 56641480Smckusick * transfers (the latter only being possible on devices with a block size 56741480Smckusick * larger than DEV_BSIZE). The operation is performed in three steps 56841480Smckusick * using a locally allocated buffer: 56941480Smckusick * 1. transfer any initial partial block 57041480Smckusick * 2. transfer full blocks 57141480Smckusick * 3. transfer any final partial block 57241480Smckusick */ 57341480Smckusick static void 57441480Smckusick sdlblkstrat(bp, bsize) 57541480Smckusick register struct buf *bp; 57641480Smckusick register int bsize; 57741480Smckusick { 57841480Smckusick register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf), 57941480Smckusick M_DEVBUF, M_WAITOK); 58041480Smckusick caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); 58141480Smckusick register int bn, resid; 58241480Smckusick register caddr_t addr; 58341480Smckusick 58441480Smckusick bzero((caddr_t)cbp, sizeof(*cbp)); 58549132Skarels cbp->b_proc = curproc; /* XXX */ 58641480Smckusick cbp->b_dev = bp->b_dev; 58741480Smckusick bn = bp->b_blkno; 58841480Smckusick resid = bp->b_bcount; 58941480Smckusick addr = bp->b_un.b_addr; 59041480Smckusick #ifdef DEBUG 59141480Smckusick if (sddebug & SDB_PARTIAL) 59241480Smckusick printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", 59341480Smckusick bp, bp->b_flags, bn, resid, addr); 59441480Smckusick #endif 59541480Smckusick 59641480Smckusick while (resid > 0) { 59741480Smckusick register int boff = dbtob(bn) & (bsize - 1); 59841480Smckusick register int count; 59941480Smckusick 60041480Smckusick if (boff || resid < bsize) { 60141480Smckusick sdstats[sdunit(bp->b_dev)].sdpartials++; 60255068Spendry count = min(resid, bsize - boff); 60341480Smckusick cbp->b_flags = B_BUSY | B_PHYS | B_READ; 60441480Smckusick cbp->b_blkno = bn - btodb(boff); 60541480Smckusick cbp->b_un.b_addr = cbuf; 60641480Smckusick cbp->b_bcount = bsize; 60741480Smckusick #ifdef DEBUG 60841480Smckusick if (sddebug & SDB_PARTIAL) 60941480Smckusick printf(" readahead: bn %x cnt %x off %x addr %x\n", 61041480Smckusick cbp->b_blkno, count, boff, addr); 61141480Smckusick #endif 61241480Smckusick sdstrategy(cbp); 61341480Smckusick biowait(cbp); 61441480Smckusick if (cbp->b_flags & B_ERROR) { 61541480Smckusick bp->b_flags |= B_ERROR; 61641480Smckusick bp->b_error = cbp->b_error; 61741480Smckusick break; 61841480Smckusick } 61941480Smckusick if (bp->b_flags & B_READ) { 62041480Smckusick bcopy(&cbuf[boff], addr, count); 62141480Smckusick goto done; 62241480Smckusick } 62341480Smckusick bcopy(addr, &cbuf[boff], count); 62441480Smckusick #ifdef DEBUG 62541480Smckusick if (sddebug & SDB_PARTIAL) 62641480Smckusick printf(" writeback: bn %x cnt %x off %x addr %x\n", 62741480Smckusick cbp->b_blkno, count, boff, addr); 62841480Smckusick #endif 62941480Smckusick } else { 63041480Smckusick count = resid & ~(bsize - 1); 63141480Smckusick cbp->b_blkno = bn; 63241480Smckusick cbp->b_un.b_addr = addr; 63341480Smckusick cbp->b_bcount = count; 63441480Smckusick #ifdef DEBUG 63541480Smckusick if (sddebug & SDB_PARTIAL) 63641480Smckusick printf(" fulltrans: bn %x cnt %x addr %x\n", 63741480Smckusick cbp->b_blkno, count, addr); 63841480Smckusick #endif 63941480Smckusick } 64041480Smckusick cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); 64141480Smckusick sdstrategy(cbp); 64241480Smckusick biowait(cbp); 64341480Smckusick if (cbp->b_flags & B_ERROR) { 64441480Smckusick bp->b_flags |= B_ERROR; 64541480Smckusick bp->b_error = cbp->b_error; 64641480Smckusick break; 64741480Smckusick } 64841480Smckusick done: 64941480Smckusick bn += btodb(count); 65041480Smckusick resid -= count; 65141480Smckusick addr += count; 65241480Smckusick #ifdef DEBUG 65341480Smckusick if (sddebug & SDB_PARTIAL) 65441480Smckusick printf(" done: bn %x resid %x addr %x\n", 65541480Smckusick bn, resid, addr); 65641480Smckusick #endif 65741480Smckusick } 65841480Smckusick free(cbuf, M_DEVBUF); 65941480Smckusick free(cbp, M_DEVBUF); 66041480Smckusick } 66141480Smckusick 66241480Smckusick void 66341480Smckusick sdstrategy(bp) 66441480Smckusick register struct buf *bp; 66541480Smckusick { 66657327Shibler int unit = sdunit(bp->b_dev); 66741480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 66841480Smckusick register struct buf *dp = &sdtab[unit]; 66957327Shibler register struct partition *pinfo; 67045750Smckusick register daddr_t bn; 67145750Smckusick register int sz, s; 67241480Smckusick 67366072Shibler if (sc->sc_format_pid >= 0) { 67449132Skarels if (sc->sc_format_pid != curproc->p_pid) { /* XXX */ 67541480Smckusick bp->b_error = EPERM; 67657327Shibler goto bad; 67741480Smckusick } 67841480Smckusick bp->b_cylin = 0; 67941480Smckusick } else { 68065662Shibler if (sc->sc_flags & SDF_ERROR) { 68165662Shibler bp->b_error = EIO; 68265662Shibler goto bad; 68365662Shibler } 68441480Smckusick bn = bp->b_blkno; 68545750Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 68657327Shibler pinfo = &sc->sc_info.si_label.d_partitions[sdpart(bp->b_dev)]; 68757327Shibler if (bn < 0 || bn + sz > pinfo->p_size) { 68857327Shibler sz = pinfo->p_size - bn; 68945750Smckusick if (sz == 0) { 69041480Smckusick bp->b_resid = bp->b_bcount; 69141480Smckusick goto done; 69241480Smckusick } 69345750Smckusick if (sz < 0) { 69445750Smckusick bp->b_error = EINVAL; 69557327Shibler goto bad; 69645750Smckusick } 69745750Smckusick bp->b_bcount = dbtob(sz); 69841480Smckusick } 69941480Smckusick /* 70057327Shibler * Check for write to write protected label 70157327Shibler */ 70257327Shibler if (bn + pinfo->p_offset <= LABELSECTOR && 70357327Shibler #if LABELSECTOR != 0 70457327Shibler bn + pinfo->p_offset + sz > LABELSECTOR && 70557327Shibler #endif 70657327Shibler !(bp->b_flags & B_READ) && !(sc->sc_flags & SDF_WLABEL)) { 70757327Shibler bp->b_error = EROFS; 70857327Shibler goto bad; 70957327Shibler } 71057327Shibler /* 71141480Smckusick * Non-aligned or partial-block transfers handled specially. 71241480Smckusick */ 71341480Smckusick s = sc->sc_blksize - 1; 71441480Smckusick if ((dbtob(bn) & s) || (bp->b_bcount & s)) { 71541480Smckusick sdlblkstrat(bp, sc->sc_blksize); 71641480Smckusick goto done; 71741480Smckusick } 71857327Shibler bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift; 71941480Smckusick } 72041480Smckusick s = splbio(); 72141480Smckusick disksort(dp, bp); 72241480Smckusick if (dp->b_active == 0) { 72341480Smckusick dp->b_active = 1; 72441480Smckusick sdustart(unit); 72541480Smckusick } 72641480Smckusick splx(s); 72741480Smckusick return; 72857327Shibler bad: 72957327Shibler bp->b_flags |= B_ERROR; 73041480Smckusick done: 73145750Smckusick biodone(bp); 73241480Smckusick } 73341480Smckusick 73441480Smckusick void 73541480Smckusick sdustart(unit) 73641480Smckusick register int unit; 73741480Smckusick { 73841480Smckusick if (scsireq(&sd_softc[unit].sc_dq)) 73941480Smckusick sdstart(unit); 74041480Smckusick } 74141480Smckusick 74250039Skarels /* 74350039Skarels * Return: 74450039Skarels * 0 if not really an error 74550039Skarels * <0 if we should do a retry 74650039Skarels * >0 if a fatal error 74750039Skarels */ 74845750Smckusick static int 74941480Smckusick sderror(unit, sc, hp, stat) 75041480Smckusick int unit, stat; 75141480Smckusick register struct sd_softc *sc; 75241480Smckusick register struct hp_device *hp; 75341480Smckusick { 75450039Skarels int cond = 1; 75545750Smckusick 75641480Smckusick sdsense[unit].status = stat; 75741480Smckusick if (stat & STS_CHECKCOND) { 75841480Smckusick struct scsi_xsense *sp; 75941480Smckusick 76041480Smckusick scsi_request_sense(hp->hp_ctlr, hp->hp_slave, 76141480Smckusick sc->sc_punit, sdsense[unit].sense, 76241480Smckusick sizeof(sdsense[unit].sense)); 76341480Smckusick sp = (struct scsi_xsense *)sdsense[unit].sense; 76441480Smckusick printf("sd%d: scsi sense class %d, code %d", unit, 76541480Smckusick sp->class, sp->code); 76641480Smckusick if (sp->class == 7) { 76741480Smckusick printf(", key %d", sp->key); 76841480Smckusick if (sp->valid) 76941480Smckusick printf(", blk %d", *(int *)&sp->info1); 77050039Skarels switch (sp->key) { 77150039Skarels /* no sense, try again */ 77250039Skarels case 0: 77350039Skarels cond = -1; 77450039Skarels break; 77550039Skarels /* recovered error, not a problem */ 77650039Skarels case 1: 77750039Skarels cond = 0; 77850039Skarels break; 77957327Shibler /* possible media change */ 78057327Shibler case 6: 78157327Shibler /* 78257327Shibler * For removable media, if we are doing the 78357327Shibler * first open (i.e. reading the label) go 78457327Shibler * ahead and retry, otherwise someone has 78557327Shibler * changed the media out from under us and 78657327Shibler * we should abort any further operations 78757327Shibler * until a close is done. 78857327Shibler */ 78957327Shibler if (sc->sc_flags & SDF_RMEDIA) { 79057327Shibler if (sc->sc_flags & SDF_OPENING) 79157327Shibler cond = -1; 79257327Shibler else 79357327Shibler sc->sc_flags |= SDF_ERROR; 79457327Shibler } 79557327Shibler break; 79650039Skarels } 79741480Smckusick } 79841480Smckusick printf("\n"); 79941480Smckusick } 80050039Skarels return(cond); 80141480Smckusick } 80241480Smckusick 80341480Smckusick static void 80441480Smckusick sdfinish(unit, sc, bp) 80541480Smckusick int unit; 80641480Smckusick register struct sd_softc *sc; 80741480Smckusick register struct buf *bp; 80841480Smckusick { 80953929Shibler register struct buf *dp = &sdtab[unit]; 81053929Shibler 81153929Shibler dp->b_errcnt = 0; 81253929Shibler dp->b_actf = bp->b_actf; 81341480Smckusick bp->b_resid = 0; 81445750Smckusick biodone(bp); 81541480Smckusick scsifree(&sc->sc_dq); 81653929Shibler if (dp->b_actf) 81741480Smckusick sdustart(unit); 81853929Shibler else { 81953929Shibler dp->b_active = 0; 82053929Shibler if (sc->sc_flags & SDF_WANTED) { 82153929Shibler sc->sc_flags &= ~SDF_WANTED; 82253929Shibler wakeup((caddr_t)dp); 82353929Shibler } 82453929Shibler } 82541480Smckusick } 82641480Smckusick 82741480Smckusick void 82841480Smckusick sdstart(unit) 82941480Smckusick register int unit; 83041480Smckusick { 83141480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 83241480Smckusick register struct hp_device *hp = sc->sc_hd; 83341480Smckusick 83441480Smckusick /* 83541480Smckusick * we have the SCSI bus -- in format mode, we may or may not need dma 83641480Smckusick * so check now. 83741480Smckusick */ 83866072Shibler if (sc->sc_format_pid >= 0 && legal_cmds[sdcmd[unit].cdb[0]] > 0) { 83941480Smckusick register struct buf *bp = sdtab[unit].b_actf; 84041480Smckusick register int sts; 84141480Smckusick 84265662Shibler sdtab[unit].b_errcnt = 0; 84365662Shibler while (1) { 84465662Shibler sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave, 84565662Shibler sc->sc_punit, &sdcmd[unit], 84665662Shibler bp->b_un.b_addr, bp->b_bcount, 84765662Shibler bp->b_flags & B_READ); 84865662Shibler sdsense[unit].status = sts; 84965662Shibler if ((sts & 0xfe) == 0 || 85065662Shibler (sts = sderror(unit, sc, hp, sts)) == 0) 85165662Shibler break; 85265662Shibler if (sts > 0 || sdtab[unit].b_errcnt++ >= SDRETRY) { 85365662Shibler bp->b_flags |= B_ERROR; 85465662Shibler bp->b_error = EIO; 85565662Shibler break; 85665662Shibler } 85741480Smckusick } 85841480Smckusick sdfinish(unit, sc, bp); 85941480Smckusick 86041480Smckusick } else if (scsiustart(hp->hp_ctlr)) 86141480Smckusick sdgo(unit); 86241480Smckusick } 86341480Smckusick 86441480Smckusick void 86541480Smckusick sdgo(unit) 86641480Smckusick register int unit; 86741480Smckusick { 86841480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 86941480Smckusick register struct hp_device *hp = sc->sc_hd; 87041480Smckusick register struct buf *bp = sdtab[unit].b_actf; 87141480Smckusick register int pad; 87241480Smckusick register struct scsi_fmt_cdb *cmd; 87341480Smckusick 87466072Shibler if (sc->sc_format_pid >= 0) { 87541480Smckusick cmd = &sdcmd[unit]; 87641480Smckusick pad = 0; 87741480Smckusick } else { 87865662Shibler /* 87965662Shibler * Drive is in an error state, abort all operations 88065662Shibler */ 88165662Shibler if (sc->sc_flags & SDF_ERROR) { 88265662Shibler bp->b_flags |= B_ERROR; 88365662Shibler bp->b_error = EIO; 88465662Shibler sdfinish(unit, sc, bp); 88565662Shibler return; 88665662Shibler } 88741480Smckusick cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd; 88841480Smckusick *(int *)(&cmd->cdb[2]) = bp->b_cylin; 88941480Smckusick pad = howmany(bp->b_bcount, sc->sc_blksize); 89041480Smckusick *(u_short *)(&cmd->cdb[7]) = pad; 89141480Smckusick pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0; 89241480Smckusick #ifdef DEBUG 89341480Smckusick if (pad) 89441480Smckusick printf("sd%d: partial block xfer -- %x bytes\n", 89541480Smckusick unit, bp->b_bcount); 89641480Smckusick #endif 89741480Smckusick sdstats[unit].sdtransfers++; 89841480Smckusick } 89957327Shibler #ifdef USELEDS 90057327Shibler if (inledcontrol == 0) 90157327Shibler ledcontrol(0, 0, LED_DISK); 90257327Shibler #endif 90341480Smckusick if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) { 90441480Smckusick if (hp->hp_dk >= 0) { 90541480Smckusick dk_busy |= 1 << hp->hp_dk; 90641480Smckusick ++dk_seek[hp->hp_dk]; 90741480Smckusick ++dk_xfer[hp->hp_dk]; 90841480Smckusick dk_wds[hp->hp_dk] += bp->b_bcount >> 6; 90941480Smckusick } 91041480Smckusick return; 91141480Smckusick } 91241480Smckusick #ifdef DEBUG 91341480Smckusick if (sddebug & SDB_ERROR) 91441480Smckusick printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n", 91541480Smckusick unit, bp->b_flags & B_READ? "read" : "write", 91641480Smckusick bp->b_un.b_addr, bp->b_cylin, bp->b_bcount, 91741480Smckusick sdtab[unit].b_errcnt); 91841480Smckusick #endif 91941480Smckusick bp->b_flags |= B_ERROR; 92041480Smckusick bp->b_error = EIO; 92141480Smckusick sdfinish(unit, sc, bp); 92241480Smckusick } 92341480Smckusick 92441480Smckusick void 92541480Smckusick sdintr(unit, stat) 92641480Smckusick register int unit; 92741480Smckusick int stat; 92841480Smckusick { 92941480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 93041480Smckusick register struct buf *bp = sdtab[unit].b_actf; 93141480Smckusick register struct hp_device *hp = sc->sc_hd; 93250039Skarels int cond; 93341480Smckusick 93441480Smckusick if (bp == NULL) { 93541480Smckusick printf("sd%d: bp == NULL\n", unit); 93641480Smckusick return; 93741480Smckusick } 93841480Smckusick if (hp->hp_dk >= 0) 93941480Smckusick dk_busy &=~ (1 << hp->hp_dk); 94041480Smckusick if (stat) { 94141480Smckusick #ifdef DEBUG 94241480Smckusick if (sddebug & SDB_ERROR) 94341480Smckusick printf("sd%d: sdintr: bad scsi status 0x%x\n", 94441480Smckusick unit, stat); 94541480Smckusick #endif 94650039Skarels cond = sderror(unit, sc, hp, stat); 94750039Skarels if (cond) { 94850039Skarels if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) { 94950038Skarels #ifdef DEBUG 95050039Skarels if (sddebug & SDB_ERROR) 95150039Skarels printf("sd%d: retry #%d\n", 95250039Skarels unit, sdtab[unit].b_errcnt); 95350038Skarels #endif 95450039Skarels sdstart(unit); 95550039Skarels return; 95650039Skarels } 95750039Skarels bp->b_flags |= B_ERROR; 95850039Skarels bp->b_error = EIO; 95945750Smckusick } 96041480Smckusick } 96141480Smckusick sdfinish(unit, sc, bp); 96241480Smckusick } 96341480Smckusick 96441480Smckusick int 96549132Skarels sdread(dev, uio, flags) 96641480Smckusick dev_t dev; 96741480Smckusick struct uio *uio; 96849132Skarels int flags; 96941480Smckusick { 97041480Smckusick register int unit = sdunit(dev); 97141480Smckusick register int pid; 97241480Smckusick 97366072Shibler if ((pid = sd_softc[unit].sc_format_pid) >= 0 && 97449132Skarels pid != uio->uio_procp->p_pid) 97541480Smckusick return (EPERM); 97641480Smckusick 97749132Skarels return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio)); 97841480Smckusick } 97941480Smckusick 98041480Smckusick int 98149132Skarels sdwrite(dev, uio, flags) 98241480Smckusick dev_t dev; 98341480Smckusick struct uio *uio; 98449132Skarels int flags; 98541480Smckusick { 98641480Smckusick register int unit = sdunit(dev); 98741480Smckusick register int pid; 98841480Smckusick 98966072Shibler if ((pid = sd_softc[unit].sc_format_pid) >= 0 && 99049132Skarels pid != uio->uio_procp->p_pid) 99141480Smckusick return (EPERM); 99241480Smckusick 99349132Skarels return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio)); 99441480Smckusick } 99541480Smckusick 99641480Smckusick int 99749132Skarels sdioctl(dev, cmd, data, flag, p) 99841480Smckusick dev_t dev; 99941480Smckusick int cmd; 100041480Smckusick caddr_t data; 100141480Smckusick int flag; 100249132Skarels struct proc *p; 100341480Smckusick { 100457327Shibler int unit = sdunit(dev); 100541480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 100657327Shibler register struct disklabel *lp = &sc->sc_info.si_label; 100757327Shibler int error, flags; 100841480Smckusick 100941480Smckusick switch (cmd) { 101041480Smckusick default: 101141480Smckusick return (EINVAL); 101241480Smckusick 101357327Shibler case DIOCGDINFO: 101457327Shibler *(struct disklabel *)data = *lp; 101557327Shibler return (0); 101657327Shibler 101757327Shibler case DIOCGPART: 101857327Shibler ((struct partinfo *)data)->disklab = lp; 101957327Shibler ((struct partinfo *)data)->part = 102057327Shibler &lp->d_partitions[sdpart(dev)]; 102157327Shibler return (0); 102257327Shibler 102357327Shibler case DIOCWLABEL: 102457327Shibler if ((flag & FWRITE) == 0) 102557327Shibler return (EBADF); 102657327Shibler if (*(int *)data) 102757327Shibler sc->sc_flags |= SDF_WLABEL; 102857327Shibler else 102957327Shibler sc->sc_flags &= ~SDF_WLABEL; 103057327Shibler return (0); 103157327Shibler 103257327Shibler case DIOCSDINFO: 103357327Shibler if ((flag & FWRITE) == 0) 103457327Shibler return (EBADF); 103557327Shibler error = setdisklabel(lp, (struct disklabel *)data, 103657327Shibler (sc->sc_flags & SDF_WLABEL) ? 0 103757327Shibler : sc->sc_info.si_open); 103857327Shibler return (error); 103957327Shibler 104057327Shibler case DIOCWDINFO: 104157327Shibler if ((flag & FWRITE) == 0) 104257327Shibler return (EBADF); 104357327Shibler error = setdisklabel(lp, (struct disklabel *)data, 104457327Shibler (sc->sc_flags & SDF_WLABEL) ? 0 104557327Shibler : sc->sc_info.si_open); 104657327Shibler if (error) 104757327Shibler return (error); 104857327Shibler flags = sc->sc_flags; 104957327Shibler sc->sc_flags = SDF_ALIVE | SDF_WLABEL; 105057327Shibler error = writedisklabel(sdlabdev(dev), sdstrategy, lp); 105157327Shibler sc->sc_flags = flags; 105257327Shibler return (error); 105357327Shibler 105441480Smckusick case SDIOCSFORMAT: 105541480Smckusick /* take this device into or out of "format" mode */ 105649132Skarels if (suser(p->p_ucred, &p->p_acflag)) 105741480Smckusick return(EPERM); 105841480Smckusick 105941480Smckusick if (*(int *)data) { 106066072Shibler if (sc->sc_format_pid >= 0) 106141480Smckusick return (EPERM); 106249132Skarels sc->sc_format_pid = p->p_pid; 106341480Smckusick } else 106466072Shibler sc->sc_format_pid = -1; 106541480Smckusick return (0); 106641480Smckusick 106741480Smckusick case SDIOCGFORMAT: 106841480Smckusick /* find out who has the device in format mode */ 106941480Smckusick *(int *)data = sc->sc_format_pid; 107041480Smckusick return (0); 107141480Smckusick 107241480Smckusick case SDIOCSCSICOMMAND: 107341480Smckusick /* 107441480Smckusick * Save what user gave us as SCSI cdb to use with next 107541480Smckusick * read or write to the char device. 107641480Smckusick */ 107749132Skarels if (sc->sc_format_pid != p->p_pid) 107841480Smckusick return (EPERM); 107941480Smckusick if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) 108041480Smckusick return (EINVAL); 108141480Smckusick bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0])); 108241480Smckusick return (0); 108341480Smckusick 108441480Smckusick case SDIOCSENSE: 108541480Smckusick /* 108641480Smckusick * return the SCSI sense data saved after the last 108741480Smckusick * operation that completed with "check condition" status. 108841480Smckusick */ 108941480Smckusick bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0])); 109041480Smckusick return (0); 109141480Smckusick 109241480Smckusick } 109341480Smckusick /*NOTREACHED*/ 109441480Smckusick } 109541480Smckusick 109641480Smckusick int 109741480Smckusick sdsize(dev) 109841480Smckusick dev_t dev; 109941480Smckusick { 110041480Smckusick register int unit = sdunit(dev); 110141480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 110257327Shibler int psize, didopen = 0; 110341480Smckusick 110441480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 110541480Smckusick return(-1); 110641480Smckusick 110757327Shibler /* 110857327Shibler * We get called very early on (via swapconf) 110957327Shibler * without the device being open so we may need 111057327Shibler * to handle it here. 111157327Shibler */ 111257327Shibler if (sc->sc_info.si_open == 0) { 111357327Shibler if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) 111457327Shibler return(-1); 111557327Shibler didopen = 1; 111657327Shibler } 111757327Shibler psize = sc->sc_info.si_label.d_partitions[sdpart(dev)].p_size; 111857327Shibler if (didopen) 111957327Shibler (void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); 112057327Shibler return (psize); 112141480Smckusick } 112241480Smckusick 112341480Smckusick /* 112441480Smckusick * Non-interrupt driven, non-dma dump routine. 112541480Smckusick */ 112641480Smckusick int 112741480Smckusick sddump(dev) 112841480Smckusick dev_t dev; 112941480Smckusick { 113041480Smckusick int part = sdpart(dev); 113141480Smckusick int unit = sdunit(dev); 113241480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 113341480Smckusick register struct hp_device *hp = sc->sc_hd; 113457327Shibler register struct partition *pinfo; 113541480Smckusick register daddr_t baddr; 113641480Smckusick register int maddr; 113741480Smckusick register int pages, i; 113841480Smckusick int stat; 113966072Shibler extern int lowram, dumpsize; 114041480Smckusick 114141480Smckusick /* is drive ok? */ 114241480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 114341480Smckusick return (ENXIO); 114457327Shibler pinfo = &sc->sc_info.si_label.d_partitions[part]; 114541480Smckusick /* dump parameters in range? */ 114657327Shibler if (dumplo < 0 || dumplo >= pinfo->p_size || 114757327Shibler pinfo->p_fstype != FS_SWAP) 114841480Smckusick return (EINVAL); 114966072Shibler pages = dumpsize; 115057327Shibler if (dumplo + ctod(pages) > pinfo->p_size) 115157327Shibler pages = dtoc(pinfo->p_size - dumplo); 115241480Smckusick maddr = lowram; 115357327Shibler baddr = dumplo + pinfo->p_offset; 115441480Smckusick /* scsi bus idle? */ 115541480Smckusick if (!scsireq(&sc->sc_dq)) { 115641480Smckusick scsireset(hp->hp_ctlr); 115741480Smckusick sdreset(sc, sc->sc_hd); 115841480Smckusick printf("[ drive %d reset ] ", unit); 115941480Smckusick } 116041480Smckusick for (i = 0; i < pages; i++) { 116141480Smckusick #define NPGMB (1024*1024/NBPG) 116241480Smckusick /* print out how many Mbs we have dumped */ 116341480Smckusick if (i && (i % NPGMB) == 0) 116441480Smckusick printf("%d ", i / NPGMB); 116541480Smckusick #undef NPBMG 116652614Smckusick pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr, 116751576Smckusick VM_PROT_READ, TRUE); 116841480Smckusick stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, 116941480Smckusick vmmap, NBPG, baddr, sc->sc_bshift); 117041480Smckusick if (stat) { 117141480Smckusick printf("sddump: scsi write error 0x%x\n", stat); 117241480Smckusick return (EIO); 117341480Smckusick } 117441480Smckusick maddr += NBPG; 117541480Smckusick baddr += ctod(1); 117641480Smckusick } 117741480Smckusick return (0); 117841480Smckusick } 117941480Smckusick #endif 1180