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*66072Shibler * @(#)sd.c 8.3 (Berkeley) 02/13/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; 249*66072Shibler /* 250*66072Shibler * XXX formerly 0 meant unused but now pid 0 can legitimately 251*66072Shibler * use this interface (sdgetcapacity). 252*66072Shibler */ 253*66072Shibler 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 }; 290*66072Shibler u_char *capbuf; 291*66072Shibler int i, capbufsize; 29265662Shibler 293*66072Shibler /* 294*66072Shibler * Cannot use stack space for this buffer since stack KVA may not 295*66072Shibler * be valid (i.e. in context of this process) when the operation 296*66072Shibler * actually starts. 297*66072Shibler */ 298*66072Shibler capbufsize = 8; 299*66072Shibler capbuf = malloc(capbufsize, M_DEVBUF, M_WAITOK); 300*66072Shibler 30165662Shibler if (dev == NODEV) { 30265662Shibler i = scsi_immed_command(hd->hp_ctlr, hd->hp_slave, sc->sc_punit, 303*66072Shibler &cap, capbuf, capbufsize, B_READ); 30465662Shibler } else { 305*66072Shibler struct buf *bp; 306*66072Shibler 30765662Shibler /* 30865662Shibler * XXX this is horrible 30965662Shibler */ 310*66072Shibler if (sc->sc_format_pid >= 0) 31165662Shibler panic("sdgetcapacity"); 312*66072Shibler 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); 315*66072Shibler bp->b_dev = dev; 316*66072Shibler bp->b_flags = B_READ | B_BUSY; 317*66072Shibler bp->b_un.b_addr = (caddr_t)capbuf; 318*66072Shibler bp->b_bcount = capbufsize; 319*66072Shibler sdstrategy(bp); 320*66072Shibler i = biowait(bp) ? sdsense[hd->hp_unit].status : 0; 321*66072Shibler free(bp, M_DEVBUF); 322*66072Shibler 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 331*66072Shibler 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 345*66072Shibler free(capbuf, M_DEVBUF); 34665662Shibler return (1); 34765662Shibler } 34865662Shibler sc->sc_blks = *(u_int *)&capbuf[0]; 34965662Shibler sc->sc_blksize = *(int *)&capbuf[4]; 350*66072Shibler 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) { 358*66072Shibler printf("sd%d: need at least %d byte blocks - %s\n", 359*66072Shibler 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; 46357327Shibler return(0); 46457327Shibler } 46557327Shibler 46657327Shibler int 46749132Skarels sdopen(dev, flags, mode, p) 46841480Smckusick dev_t dev; 46949132Skarels int flags, mode; 47049132Skarels struct proc *p; 47141480Smckusick { 47241480Smckusick register int unit = sdunit(dev); 47341480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 47457327Shibler int mask, error; 47541480Smckusick 47641480Smckusick if (unit >= NSD) 47741480Smckusick return(ENXIO); 47849132Skarels if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag)) 47941480Smckusick return(ENXIO); 48057327Shibler if (sc->sc_flags & SDF_ERROR) 48157327Shibler return(EIO); 48241480Smckusick 48357327Shibler /* 48457327Shibler * Wait for any pending opens/closes to complete 48557327Shibler */ 48657327Shibler while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING)) 48757327Shibler sleep((caddr_t)sc, PRIBIO); 48857327Shibler /* 48957327Shibler * On first open, get label and partition info. 49057327Shibler * We may block reading the label, so be careful 49157327Shibler * to stop any other opens. 49257327Shibler */ 49357327Shibler if (sc->sc_info.si_open == 0) { 49457327Shibler sc->sc_flags |= SDF_OPENING; 49557327Shibler error = sdgetinfo(dev); 49657327Shibler sc->sc_flags &= ~SDF_OPENING; 49757327Shibler wakeup((caddr_t)sc); 49857327Shibler if (error) 49957327Shibler return(error); 50057327Shibler } 50141480Smckusick if (sc->sc_hd->hp_dk >= 0) 50241480Smckusick dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms; 50357327Shibler 50457327Shibler mask = 1 << sdpart(dev); 50557327Shibler if (mode == S_IFCHR) 50657327Shibler sc->sc_info.si_copen |= mask; 50757327Shibler else 50857327Shibler sc->sc_info.si_bopen |= mask; 50957327Shibler sc->sc_info.si_open |= mask; 51041480Smckusick return(0); 51141480Smckusick } 51241480Smckusick 51353929Shibler int 51453929Shibler sdclose(dev, flag, mode, p) 51553929Shibler dev_t dev; 51653929Shibler int flag, mode; 51753929Shibler struct proc *p; 51853929Shibler { 51953929Shibler int unit = sdunit(dev); 52053929Shibler register struct sd_softc *sc = &sd_softc[unit]; 52157327Shibler register struct sdinfo *si = &sc->sc_info; 52257327Shibler int mask, s; 52353929Shibler 52457327Shibler mask = 1 << sdpart(dev); 52557327Shibler if (mode == S_IFCHR) 52657327Shibler si->si_copen &= ~mask; 52757327Shibler else 52857327Shibler si->si_bopen &= ~mask; 52957327Shibler si->si_open = si->si_bopen | si->si_copen; 53053929Shibler /* 53157327Shibler * On last close, we wait for all activity to cease since 53257327Shibler * the label/parition info will become invalid. Since we 53357327Shibler * might sleep, we must block any opens while we are here. 53457327Shibler * Note we don't have to about other closes since we know 53557327Shibler * we are the last one. 53653929Shibler */ 53757327Shibler if (si->si_open == 0) { 53857327Shibler sc->sc_flags |= SDF_CLOSING; 53953929Shibler s = splbio(); 54053929Shibler while (sdtab[unit].b_active) { 54153929Shibler sc->sc_flags |= SDF_WANTED; 54253929Shibler sleep((caddr_t)&sdtab[unit], PRIBIO); 54353929Shibler } 54453929Shibler splx(s); 54557327Shibler sc->sc_flags &= ~(SDF_CLOSING|SDF_WLABEL|SDF_ERROR); 54657327Shibler wakeup((caddr_t)sc); 54753929Shibler } 548*66072Shibler sc->sc_format_pid = -1; 54957327Shibler return(0); 55053929Shibler } 55153929Shibler 55241480Smckusick /* 55341480Smckusick * This routine is called for partial block transfers and non-aligned 55441480Smckusick * transfers (the latter only being possible on devices with a block size 55541480Smckusick * larger than DEV_BSIZE). The operation is performed in three steps 55641480Smckusick * using a locally allocated buffer: 55741480Smckusick * 1. transfer any initial partial block 55841480Smckusick * 2. transfer full blocks 55941480Smckusick * 3. transfer any final partial block 56041480Smckusick */ 56141480Smckusick static void 56241480Smckusick sdlblkstrat(bp, bsize) 56341480Smckusick register struct buf *bp; 56441480Smckusick register int bsize; 56541480Smckusick { 56641480Smckusick register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf), 56741480Smckusick M_DEVBUF, M_WAITOK); 56841480Smckusick caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); 56941480Smckusick register int bn, resid; 57041480Smckusick register caddr_t addr; 57141480Smckusick 57241480Smckusick bzero((caddr_t)cbp, sizeof(*cbp)); 57349132Skarels cbp->b_proc = curproc; /* XXX */ 57441480Smckusick cbp->b_dev = bp->b_dev; 57541480Smckusick bn = bp->b_blkno; 57641480Smckusick resid = bp->b_bcount; 57741480Smckusick addr = bp->b_un.b_addr; 57841480Smckusick #ifdef DEBUG 57941480Smckusick if (sddebug & SDB_PARTIAL) 58041480Smckusick printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", 58141480Smckusick bp, bp->b_flags, bn, resid, addr); 58241480Smckusick #endif 58341480Smckusick 58441480Smckusick while (resid > 0) { 58541480Smckusick register int boff = dbtob(bn) & (bsize - 1); 58641480Smckusick register int count; 58741480Smckusick 58841480Smckusick if (boff || resid < bsize) { 58941480Smckusick sdstats[sdunit(bp->b_dev)].sdpartials++; 59055068Spendry count = min(resid, bsize - boff); 59141480Smckusick cbp->b_flags = B_BUSY | B_PHYS | B_READ; 59241480Smckusick cbp->b_blkno = bn - btodb(boff); 59341480Smckusick cbp->b_un.b_addr = cbuf; 59441480Smckusick cbp->b_bcount = bsize; 59541480Smckusick #ifdef DEBUG 59641480Smckusick if (sddebug & SDB_PARTIAL) 59741480Smckusick printf(" readahead: bn %x cnt %x off %x addr %x\n", 59841480Smckusick cbp->b_blkno, count, boff, addr); 59941480Smckusick #endif 60041480Smckusick sdstrategy(cbp); 60141480Smckusick biowait(cbp); 60241480Smckusick if (cbp->b_flags & B_ERROR) { 60341480Smckusick bp->b_flags |= B_ERROR; 60441480Smckusick bp->b_error = cbp->b_error; 60541480Smckusick break; 60641480Smckusick } 60741480Smckusick if (bp->b_flags & B_READ) { 60841480Smckusick bcopy(&cbuf[boff], addr, count); 60941480Smckusick goto done; 61041480Smckusick } 61141480Smckusick bcopy(addr, &cbuf[boff], count); 61241480Smckusick #ifdef DEBUG 61341480Smckusick if (sddebug & SDB_PARTIAL) 61441480Smckusick printf(" writeback: bn %x cnt %x off %x addr %x\n", 61541480Smckusick cbp->b_blkno, count, boff, addr); 61641480Smckusick #endif 61741480Smckusick } else { 61841480Smckusick count = resid & ~(bsize - 1); 61941480Smckusick cbp->b_blkno = bn; 62041480Smckusick cbp->b_un.b_addr = addr; 62141480Smckusick cbp->b_bcount = count; 62241480Smckusick #ifdef DEBUG 62341480Smckusick if (sddebug & SDB_PARTIAL) 62441480Smckusick printf(" fulltrans: bn %x cnt %x addr %x\n", 62541480Smckusick cbp->b_blkno, count, addr); 62641480Smckusick #endif 62741480Smckusick } 62841480Smckusick cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); 62941480Smckusick sdstrategy(cbp); 63041480Smckusick biowait(cbp); 63141480Smckusick if (cbp->b_flags & B_ERROR) { 63241480Smckusick bp->b_flags |= B_ERROR; 63341480Smckusick bp->b_error = cbp->b_error; 63441480Smckusick break; 63541480Smckusick } 63641480Smckusick done: 63741480Smckusick bn += btodb(count); 63841480Smckusick resid -= count; 63941480Smckusick addr += count; 64041480Smckusick #ifdef DEBUG 64141480Smckusick if (sddebug & SDB_PARTIAL) 64241480Smckusick printf(" done: bn %x resid %x addr %x\n", 64341480Smckusick bn, resid, addr); 64441480Smckusick #endif 64541480Smckusick } 64641480Smckusick free(cbuf, M_DEVBUF); 64741480Smckusick free(cbp, M_DEVBUF); 64841480Smckusick } 64941480Smckusick 65041480Smckusick void 65141480Smckusick sdstrategy(bp) 65241480Smckusick register struct buf *bp; 65341480Smckusick { 65457327Shibler int unit = sdunit(bp->b_dev); 65541480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 65641480Smckusick register struct buf *dp = &sdtab[unit]; 65757327Shibler register struct partition *pinfo; 65845750Smckusick register daddr_t bn; 65945750Smckusick register int sz, s; 66041480Smckusick 661*66072Shibler if (sc->sc_format_pid >= 0) { 66249132Skarels if (sc->sc_format_pid != curproc->p_pid) { /* XXX */ 66341480Smckusick bp->b_error = EPERM; 66457327Shibler goto bad; 66541480Smckusick } 66641480Smckusick bp->b_cylin = 0; 66741480Smckusick } else { 66865662Shibler if (sc->sc_flags & SDF_ERROR) { 66965662Shibler bp->b_error = EIO; 67065662Shibler goto bad; 67165662Shibler } 67241480Smckusick bn = bp->b_blkno; 67345750Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 67457327Shibler pinfo = &sc->sc_info.si_label.d_partitions[sdpart(bp->b_dev)]; 67557327Shibler if (bn < 0 || bn + sz > pinfo->p_size) { 67657327Shibler sz = pinfo->p_size - bn; 67745750Smckusick if (sz == 0) { 67841480Smckusick bp->b_resid = bp->b_bcount; 67941480Smckusick goto done; 68041480Smckusick } 68145750Smckusick if (sz < 0) { 68245750Smckusick bp->b_error = EINVAL; 68357327Shibler goto bad; 68445750Smckusick } 68545750Smckusick bp->b_bcount = dbtob(sz); 68641480Smckusick } 68741480Smckusick /* 68857327Shibler * Check for write to write protected label 68957327Shibler */ 69057327Shibler if (bn + pinfo->p_offset <= LABELSECTOR && 69157327Shibler #if LABELSECTOR != 0 69257327Shibler bn + pinfo->p_offset + sz > LABELSECTOR && 69357327Shibler #endif 69457327Shibler !(bp->b_flags & B_READ) && !(sc->sc_flags & SDF_WLABEL)) { 69557327Shibler bp->b_error = EROFS; 69657327Shibler goto bad; 69757327Shibler } 69857327Shibler /* 69941480Smckusick * Non-aligned or partial-block transfers handled specially. 70041480Smckusick */ 70141480Smckusick s = sc->sc_blksize - 1; 70241480Smckusick if ((dbtob(bn) & s) || (bp->b_bcount & s)) { 70341480Smckusick sdlblkstrat(bp, sc->sc_blksize); 70441480Smckusick goto done; 70541480Smckusick } 70657327Shibler bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift; 70741480Smckusick } 70841480Smckusick s = splbio(); 70941480Smckusick disksort(dp, bp); 71041480Smckusick if (dp->b_active == 0) { 71141480Smckusick dp->b_active = 1; 71241480Smckusick sdustart(unit); 71341480Smckusick } 71441480Smckusick splx(s); 71541480Smckusick return; 71657327Shibler bad: 71757327Shibler bp->b_flags |= B_ERROR; 71841480Smckusick done: 71945750Smckusick biodone(bp); 72041480Smckusick } 72141480Smckusick 72241480Smckusick void 72341480Smckusick sdustart(unit) 72441480Smckusick register int unit; 72541480Smckusick { 72641480Smckusick if (scsireq(&sd_softc[unit].sc_dq)) 72741480Smckusick sdstart(unit); 72841480Smckusick } 72941480Smckusick 73050039Skarels /* 73150039Skarels * Return: 73250039Skarels * 0 if not really an error 73350039Skarels * <0 if we should do a retry 73450039Skarels * >0 if a fatal error 73550039Skarels */ 73645750Smckusick static int 73741480Smckusick sderror(unit, sc, hp, stat) 73841480Smckusick int unit, stat; 73941480Smckusick register struct sd_softc *sc; 74041480Smckusick register struct hp_device *hp; 74141480Smckusick { 74250039Skarels int cond = 1; 74345750Smckusick 74441480Smckusick sdsense[unit].status = stat; 74541480Smckusick if (stat & STS_CHECKCOND) { 74641480Smckusick struct scsi_xsense *sp; 74741480Smckusick 74841480Smckusick scsi_request_sense(hp->hp_ctlr, hp->hp_slave, 74941480Smckusick sc->sc_punit, sdsense[unit].sense, 75041480Smckusick sizeof(sdsense[unit].sense)); 75141480Smckusick sp = (struct scsi_xsense *)sdsense[unit].sense; 75241480Smckusick printf("sd%d: scsi sense class %d, code %d", unit, 75341480Smckusick sp->class, sp->code); 75441480Smckusick if (sp->class == 7) { 75541480Smckusick printf(", key %d", sp->key); 75641480Smckusick if (sp->valid) 75741480Smckusick printf(", blk %d", *(int *)&sp->info1); 75850039Skarels switch (sp->key) { 75950039Skarels /* no sense, try again */ 76050039Skarels case 0: 76150039Skarels cond = -1; 76250039Skarels break; 76350039Skarels /* recovered error, not a problem */ 76450039Skarels case 1: 76550039Skarels cond = 0; 76650039Skarels break; 76757327Shibler /* possible media change */ 76857327Shibler case 6: 76957327Shibler /* 77057327Shibler * For removable media, if we are doing the 77157327Shibler * first open (i.e. reading the label) go 77257327Shibler * ahead and retry, otherwise someone has 77357327Shibler * changed the media out from under us and 77457327Shibler * we should abort any further operations 77557327Shibler * until a close is done. 77657327Shibler */ 77757327Shibler if (sc->sc_flags & SDF_RMEDIA) { 77857327Shibler if (sc->sc_flags & SDF_OPENING) 77957327Shibler cond = -1; 78057327Shibler else 78157327Shibler sc->sc_flags |= SDF_ERROR; 78257327Shibler } 78357327Shibler break; 78450039Skarels } 78541480Smckusick } 78641480Smckusick printf("\n"); 78741480Smckusick } 78850039Skarels return(cond); 78941480Smckusick } 79041480Smckusick 79141480Smckusick static void 79241480Smckusick sdfinish(unit, sc, bp) 79341480Smckusick int unit; 79441480Smckusick register struct sd_softc *sc; 79541480Smckusick register struct buf *bp; 79641480Smckusick { 79753929Shibler register struct buf *dp = &sdtab[unit]; 79853929Shibler 79953929Shibler dp->b_errcnt = 0; 80053929Shibler dp->b_actf = bp->b_actf; 80141480Smckusick bp->b_resid = 0; 80245750Smckusick biodone(bp); 80341480Smckusick scsifree(&sc->sc_dq); 80453929Shibler if (dp->b_actf) 80541480Smckusick sdustart(unit); 80653929Shibler else { 80753929Shibler dp->b_active = 0; 80853929Shibler if (sc->sc_flags & SDF_WANTED) { 80953929Shibler sc->sc_flags &= ~SDF_WANTED; 81053929Shibler wakeup((caddr_t)dp); 81153929Shibler } 81253929Shibler } 81341480Smckusick } 81441480Smckusick 81541480Smckusick void 81641480Smckusick sdstart(unit) 81741480Smckusick register int unit; 81841480Smckusick { 81941480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 82041480Smckusick register struct hp_device *hp = sc->sc_hd; 82141480Smckusick 82241480Smckusick /* 82341480Smckusick * we have the SCSI bus -- in format mode, we may or may not need dma 82441480Smckusick * so check now. 82541480Smckusick */ 826*66072Shibler if (sc->sc_format_pid >= 0 && legal_cmds[sdcmd[unit].cdb[0]] > 0) { 82741480Smckusick register struct buf *bp = sdtab[unit].b_actf; 82841480Smckusick register int sts; 82941480Smckusick 83065662Shibler sdtab[unit].b_errcnt = 0; 83165662Shibler while (1) { 83265662Shibler sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave, 83365662Shibler sc->sc_punit, &sdcmd[unit], 83465662Shibler bp->b_un.b_addr, bp->b_bcount, 83565662Shibler bp->b_flags & B_READ); 83665662Shibler sdsense[unit].status = sts; 83765662Shibler if ((sts & 0xfe) == 0 || 83865662Shibler (sts = sderror(unit, sc, hp, sts)) == 0) 83965662Shibler break; 84065662Shibler if (sts > 0 || sdtab[unit].b_errcnt++ >= SDRETRY) { 84165662Shibler bp->b_flags |= B_ERROR; 84265662Shibler bp->b_error = EIO; 84365662Shibler break; 84465662Shibler } 84541480Smckusick } 84641480Smckusick sdfinish(unit, sc, bp); 84741480Smckusick 84841480Smckusick } else if (scsiustart(hp->hp_ctlr)) 84941480Smckusick sdgo(unit); 85041480Smckusick } 85141480Smckusick 85241480Smckusick void 85341480Smckusick sdgo(unit) 85441480Smckusick register int unit; 85541480Smckusick { 85641480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 85741480Smckusick register struct hp_device *hp = sc->sc_hd; 85841480Smckusick register struct buf *bp = sdtab[unit].b_actf; 85941480Smckusick register int pad; 86041480Smckusick register struct scsi_fmt_cdb *cmd; 86141480Smckusick 862*66072Shibler if (sc->sc_format_pid >= 0) { 86341480Smckusick cmd = &sdcmd[unit]; 86441480Smckusick pad = 0; 86541480Smckusick } else { 86665662Shibler /* 86765662Shibler * Drive is in an error state, abort all operations 86865662Shibler */ 86965662Shibler if (sc->sc_flags & SDF_ERROR) { 87065662Shibler bp->b_flags |= B_ERROR; 87165662Shibler bp->b_error = EIO; 87265662Shibler sdfinish(unit, sc, bp); 87365662Shibler return; 87465662Shibler } 87541480Smckusick cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd; 87641480Smckusick *(int *)(&cmd->cdb[2]) = bp->b_cylin; 87741480Smckusick pad = howmany(bp->b_bcount, sc->sc_blksize); 87841480Smckusick *(u_short *)(&cmd->cdb[7]) = pad; 87941480Smckusick pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0; 88041480Smckusick #ifdef DEBUG 88141480Smckusick if (pad) 88241480Smckusick printf("sd%d: partial block xfer -- %x bytes\n", 88341480Smckusick unit, bp->b_bcount); 88441480Smckusick #endif 88541480Smckusick sdstats[unit].sdtransfers++; 88641480Smckusick } 88757327Shibler #ifdef USELEDS 88857327Shibler if (inledcontrol == 0) 88957327Shibler ledcontrol(0, 0, LED_DISK); 89057327Shibler #endif 89141480Smckusick if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) { 89241480Smckusick if (hp->hp_dk >= 0) { 89341480Smckusick dk_busy |= 1 << hp->hp_dk; 89441480Smckusick ++dk_seek[hp->hp_dk]; 89541480Smckusick ++dk_xfer[hp->hp_dk]; 89641480Smckusick dk_wds[hp->hp_dk] += bp->b_bcount >> 6; 89741480Smckusick } 89841480Smckusick return; 89941480Smckusick } 90041480Smckusick #ifdef DEBUG 90141480Smckusick if (sddebug & SDB_ERROR) 90241480Smckusick printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n", 90341480Smckusick unit, bp->b_flags & B_READ? "read" : "write", 90441480Smckusick bp->b_un.b_addr, bp->b_cylin, bp->b_bcount, 90541480Smckusick sdtab[unit].b_errcnt); 90641480Smckusick #endif 90741480Smckusick bp->b_flags |= B_ERROR; 90841480Smckusick bp->b_error = EIO; 90941480Smckusick sdfinish(unit, sc, bp); 91041480Smckusick } 91141480Smckusick 91241480Smckusick void 91341480Smckusick sdintr(unit, stat) 91441480Smckusick register int unit; 91541480Smckusick int stat; 91641480Smckusick { 91741480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 91841480Smckusick register struct buf *bp = sdtab[unit].b_actf; 91941480Smckusick register struct hp_device *hp = sc->sc_hd; 92050039Skarels int cond; 92141480Smckusick 92241480Smckusick if (bp == NULL) { 92341480Smckusick printf("sd%d: bp == NULL\n", unit); 92441480Smckusick return; 92541480Smckusick } 92641480Smckusick if (hp->hp_dk >= 0) 92741480Smckusick dk_busy &=~ (1 << hp->hp_dk); 92841480Smckusick if (stat) { 92941480Smckusick #ifdef DEBUG 93041480Smckusick if (sddebug & SDB_ERROR) 93141480Smckusick printf("sd%d: sdintr: bad scsi status 0x%x\n", 93241480Smckusick unit, stat); 93341480Smckusick #endif 93450039Skarels cond = sderror(unit, sc, hp, stat); 93550039Skarels if (cond) { 93650039Skarels if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) { 93750038Skarels #ifdef DEBUG 93850039Skarels if (sddebug & SDB_ERROR) 93950039Skarels printf("sd%d: retry #%d\n", 94050039Skarels unit, sdtab[unit].b_errcnt); 94150038Skarels #endif 94250039Skarels sdstart(unit); 94350039Skarels return; 94450039Skarels } 94550039Skarels bp->b_flags |= B_ERROR; 94650039Skarels bp->b_error = EIO; 94745750Smckusick } 94841480Smckusick } 94941480Smckusick sdfinish(unit, sc, bp); 95041480Smckusick } 95141480Smckusick 95241480Smckusick int 95349132Skarels sdread(dev, uio, flags) 95441480Smckusick dev_t dev; 95541480Smckusick struct uio *uio; 95649132Skarels int flags; 95741480Smckusick { 95841480Smckusick register int unit = sdunit(dev); 95941480Smckusick register int pid; 96041480Smckusick 961*66072Shibler if ((pid = sd_softc[unit].sc_format_pid) >= 0 && 96249132Skarels pid != uio->uio_procp->p_pid) 96341480Smckusick return (EPERM); 96441480Smckusick 96549132Skarels return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio)); 96641480Smckusick } 96741480Smckusick 96841480Smckusick int 96949132Skarels sdwrite(dev, uio, flags) 97041480Smckusick dev_t dev; 97141480Smckusick struct uio *uio; 97249132Skarels int flags; 97341480Smckusick { 97441480Smckusick register int unit = sdunit(dev); 97541480Smckusick register int pid; 97641480Smckusick 977*66072Shibler if ((pid = sd_softc[unit].sc_format_pid) >= 0 && 97849132Skarels pid != uio->uio_procp->p_pid) 97941480Smckusick return (EPERM); 98041480Smckusick 98149132Skarels return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio)); 98241480Smckusick } 98341480Smckusick 98441480Smckusick int 98549132Skarels sdioctl(dev, cmd, data, flag, p) 98641480Smckusick dev_t dev; 98741480Smckusick int cmd; 98841480Smckusick caddr_t data; 98941480Smckusick int flag; 99049132Skarels struct proc *p; 99141480Smckusick { 99257327Shibler int unit = sdunit(dev); 99341480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 99457327Shibler register struct disklabel *lp = &sc->sc_info.si_label; 99557327Shibler int error, flags; 99641480Smckusick 99741480Smckusick switch (cmd) { 99841480Smckusick default: 99941480Smckusick return (EINVAL); 100041480Smckusick 100157327Shibler case DIOCGDINFO: 100257327Shibler *(struct disklabel *)data = *lp; 100357327Shibler return (0); 100457327Shibler 100557327Shibler case DIOCGPART: 100657327Shibler ((struct partinfo *)data)->disklab = lp; 100757327Shibler ((struct partinfo *)data)->part = 100857327Shibler &lp->d_partitions[sdpart(dev)]; 100957327Shibler return (0); 101057327Shibler 101157327Shibler case DIOCWLABEL: 101257327Shibler if ((flag & FWRITE) == 0) 101357327Shibler return (EBADF); 101457327Shibler if (*(int *)data) 101557327Shibler sc->sc_flags |= SDF_WLABEL; 101657327Shibler else 101757327Shibler sc->sc_flags &= ~SDF_WLABEL; 101857327Shibler return (0); 101957327Shibler 102057327Shibler case DIOCSDINFO: 102157327Shibler if ((flag & FWRITE) == 0) 102257327Shibler return (EBADF); 102357327Shibler error = setdisklabel(lp, (struct disklabel *)data, 102457327Shibler (sc->sc_flags & SDF_WLABEL) ? 0 102557327Shibler : sc->sc_info.si_open); 102657327Shibler return (error); 102757327Shibler 102857327Shibler case DIOCWDINFO: 102957327Shibler if ((flag & FWRITE) == 0) 103057327Shibler return (EBADF); 103157327Shibler error = setdisklabel(lp, (struct disklabel *)data, 103257327Shibler (sc->sc_flags & SDF_WLABEL) ? 0 103357327Shibler : sc->sc_info.si_open); 103457327Shibler if (error) 103557327Shibler return (error); 103657327Shibler flags = sc->sc_flags; 103757327Shibler sc->sc_flags = SDF_ALIVE | SDF_WLABEL; 103857327Shibler error = writedisklabel(sdlabdev(dev), sdstrategy, lp); 103957327Shibler sc->sc_flags = flags; 104057327Shibler return (error); 104157327Shibler 104241480Smckusick case SDIOCSFORMAT: 104341480Smckusick /* take this device into or out of "format" mode */ 104449132Skarels if (suser(p->p_ucred, &p->p_acflag)) 104541480Smckusick return(EPERM); 104641480Smckusick 104741480Smckusick if (*(int *)data) { 1048*66072Shibler if (sc->sc_format_pid >= 0) 104941480Smckusick return (EPERM); 105049132Skarels sc->sc_format_pid = p->p_pid; 105141480Smckusick } else 1052*66072Shibler sc->sc_format_pid = -1; 105341480Smckusick return (0); 105441480Smckusick 105541480Smckusick case SDIOCGFORMAT: 105641480Smckusick /* find out who has the device in format mode */ 105741480Smckusick *(int *)data = sc->sc_format_pid; 105841480Smckusick return (0); 105941480Smckusick 106041480Smckusick case SDIOCSCSICOMMAND: 106141480Smckusick /* 106241480Smckusick * Save what user gave us as SCSI cdb to use with next 106341480Smckusick * read or write to the char device. 106441480Smckusick */ 106549132Skarels if (sc->sc_format_pid != p->p_pid) 106641480Smckusick return (EPERM); 106741480Smckusick if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) 106841480Smckusick return (EINVAL); 106941480Smckusick bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0])); 107041480Smckusick return (0); 107141480Smckusick 107241480Smckusick case SDIOCSENSE: 107341480Smckusick /* 107441480Smckusick * return the SCSI sense data saved after the last 107541480Smckusick * operation that completed with "check condition" status. 107641480Smckusick */ 107741480Smckusick bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0])); 107841480Smckusick return (0); 107941480Smckusick 108041480Smckusick } 108141480Smckusick /*NOTREACHED*/ 108241480Smckusick } 108341480Smckusick 108441480Smckusick int 108541480Smckusick sdsize(dev) 108641480Smckusick dev_t dev; 108741480Smckusick { 108841480Smckusick register int unit = sdunit(dev); 108941480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 109057327Shibler int psize, didopen = 0; 109141480Smckusick 109241480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 109341480Smckusick return(-1); 109441480Smckusick 109557327Shibler /* 109657327Shibler * We get called very early on (via swapconf) 109757327Shibler * without the device being open so we may need 109857327Shibler * to handle it here. 109957327Shibler */ 110057327Shibler if (sc->sc_info.si_open == 0) { 110157327Shibler if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) 110257327Shibler return(-1); 110357327Shibler didopen = 1; 110457327Shibler } 110557327Shibler psize = sc->sc_info.si_label.d_partitions[sdpart(dev)].p_size; 110657327Shibler if (didopen) 110757327Shibler (void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); 110857327Shibler return (psize); 110941480Smckusick } 111041480Smckusick 111141480Smckusick /* 111241480Smckusick * Non-interrupt driven, non-dma dump routine. 111341480Smckusick */ 111441480Smckusick int 111541480Smckusick sddump(dev) 111641480Smckusick dev_t dev; 111741480Smckusick { 111841480Smckusick int part = sdpart(dev); 111941480Smckusick int unit = sdunit(dev); 112041480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 112141480Smckusick register struct hp_device *hp = sc->sc_hd; 112257327Shibler register struct partition *pinfo; 112341480Smckusick register daddr_t baddr; 112441480Smckusick register int maddr; 112541480Smckusick register int pages, i; 112641480Smckusick int stat; 1127*66072Shibler extern int lowram, dumpsize; 112841480Smckusick 112941480Smckusick /* is drive ok? */ 113041480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 113141480Smckusick return (ENXIO); 113257327Shibler pinfo = &sc->sc_info.si_label.d_partitions[part]; 113341480Smckusick /* dump parameters in range? */ 113457327Shibler if (dumplo < 0 || dumplo >= pinfo->p_size || 113557327Shibler pinfo->p_fstype != FS_SWAP) 113641480Smckusick return (EINVAL); 1137*66072Shibler pages = dumpsize; 113857327Shibler if (dumplo + ctod(pages) > pinfo->p_size) 113957327Shibler pages = dtoc(pinfo->p_size - dumplo); 114041480Smckusick maddr = lowram; 114157327Shibler baddr = dumplo + pinfo->p_offset; 114241480Smckusick /* scsi bus idle? */ 114341480Smckusick if (!scsireq(&sc->sc_dq)) { 114441480Smckusick scsireset(hp->hp_ctlr); 114541480Smckusick sdreset(sc, sc->sc_hd); 114641480Smckusick printf("[ drive %d reset ] ", unit); 114741480Smckusick } 114841480Smckusick for (i = 0; i < pages; i++) { 114941480Smckusick #define NPGMB (1024*1024/NBPG) 115041480Smckusick /* print out how many Mbs we have dumped */ 115141480Smckusick if (i && (i % NPGMB) == 0) 115241480Smckusick printf("%d ", i / NPGMB); 115341480Smckusick #undef NPBMG 115452614Smckusick pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr, 115551576Smckusick VM_PROT_READ, TRUE); 115641480Smckusick stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, 115741480Smckusick vmmap, NBPG, baddr, sc->sc_bshift); 115841480Smckusick if (stat) { 115941480Smckusick printf("sddump: scsi write error 0x%x\n", stat); 116041480Smckusick return (EIO); 116141480Smckusick } 116241480Smckusick maddr += NBPG; 116341480Smckusick baddr += ctod(1); 116441480Smckusick } 116541480Smckusick return (0); 116641480Smckusick } 116741480Smckusick #endif 1168