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*65662Shibler * @(#)sd.c 8.2 (Berkeley) 01/12/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 20*65662Shibler 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 74*65662Shibler #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]; 127*65662Shibler 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) { 139*65662Shibler 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) { 152*65662Shibler /* 153*65662Shibler * Not ready -- might be removable media 154*65662Shibler * device with no media. Assume as much, 155*65662Shibler * if it really isn't, the inquiry commmand 156*65662Shibler * below will fail. 157*65662Shibler */ 15845750Smckusick case 2: 159*65662Shibler 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 } 210*65662Shibler if (inqbuf.qual & 0x80) 211*65662Shibler sc->sc_flags |= SDF_RMEDIA; 21245750Smckusick 213*65662Shibler if (sdgetcapacity(sc, hd, NODEV) < 0) 214*65662Shibler goto failed; 215*65662Shibler 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 } 229*65662Shibler if (sc->sc_blks) 230*65662Shibler printf(", %d %d byte blocks", 231*65662Shibler sc->sc_blks >> sc->sc_bshift, sc->sc_blksize); 232*65662Shibler 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; 24941480Smckusick sc->sc_punit = sdpunit(hd->hp_flags); 25041480Smckusick sc->sc_type = sdident(sc, hd); 25141480Smckusick if (sc->sc_type < 0) 25241480Smckusick return(0); 25341480Smckusick sc->sc_dq.dq_ctlr = hd->hp_ctlr; 25441480Smckusick sc->sc_dq.dq_unit = hd->hp_unit; 25541480Smckusick sc->sc_dq.dq_slave = hd->hp_slave; 25641480Smckusick sc->sc_dq.dq_driver = &sddriver; 25741480Smckusick 25853929Shibler sc->sc_flags |= SDF_ALIVE; 25941480Smckusick return(1); 26041480Smckusick } 26141480Smckusick 26241480Smckusick void 26341480Smckusick sdreset(sc, hd) 26441480Smckusick register struct sd_softc *sc; 26541480Smckusick register struct hp_device *hd; 26641480Smckusick { 26741480Smckusick sdstats[hd->hp_unit].sdresets++; 26841480Smckusick } 26941480Smckusick 27057327Shibler /* 271*65662Shibler * Determine capacity of a drive. 272*65662Shibler * Returns -1 on a failure, 0 on success, 1 on a failure that is probably 273*65662Shibler * due to missing media. 274*65662Shibler */ 275*65662Shibler int 276*65662Shibler sdgetcapacity(sc, hd, dev) 277*65662Shibler struct sd_softc *sc; 278*65662Shibler struct hp_device *hd; 279*65662Shibler dev_t dev; 280*65662Shibler { 281*65662Shibler static struct scsi_fmt_cdb cap = { 282*65662Shibler 10, 283*65662Shibler CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 284*65662Shibler }; 285*65662Shibler u_char capbuf[8]; 286*65662Shibler struct buf tbuf; 287*65662Shibler int i; 288*65662Shibler 289*65662Shibler if (dev == NODEV) { 290*65662Shibler i = scsi_immed_command(hd->hp_ctlr, hd->hp_slave, sc->sc_punit, 291*65662Shibler &cap, capbuf, sizeof(capbuf), B_READ); 292*65662Shibler } else { 293*65662Shibler /* 294*65662Shibler * XXX this is horrible 295*65662Shibler */ 296*65662Shibler if (sc->sc_format_pid) 297*65662Shibler panic("sdgetcapacity"); 298*65662Shibler sc->sc_format_pid = curproc->p_pid; 299*65662Shibler bcopy((caddr_t)&cap, (caddr_t)&sdcmd[hd->hp_unit], sizeof cap); 300*65662Shibler tbuf.b_dev = dev; 301*65662Shibler tbuf.b_flags = B_READ | B_BUSY; 302*65662Shibler tbuf.b_un.b_addr = (caddr_t)capbuf; 303*65662Shibler tbuf.b_bcount = sizeof capbuf; 304*65662Shibler sdstrategy(&tbuf); 305*65662Shibler i = biowait(&tbuf) ? sdsense[hd->hp_unit].status : 0; 306*65662Shibler sc->sc_format_pid = 0; 307*65662Shibler } 308*65662Shibler if (i) { 309*65662Shibler if (i != STS_CHECKCOND || (sc->sc_flags & SDF_RMEDIA) == 0) { 310*65662Shibler #ifdef DEBUG 311*65662Shibler if (sddebug & SDB_CAPACITY) 312*65662Shibler printf("sd%d: read_capacity returns %d\n", 313*65662Shibler hd->hp_unit, i); 314*65662Shibler #endif 315*65662Shibler return (-1); 316*65662Shibler } 317*65662Shibler /* 318*65662Shibler * XXX assume unformatted or non-existant media 319*65662Shibler */ 320*65662Shibler sc->sc_blks = 0; 321*65662Shibler sc->sc_blksize = DEV_BSIZE; 322*65662Shibler sc->sc_bshift = 0; 323*65662Shibler #ifdef DEBUG 324*65662Shibler if (sddebug & SDB_CAPACITY) 325*65662Shibler printf("sd%d: removable media not present\n", 326*65662Shibler hd->hp_unit); 327*65662Shibler #endif 328*65662Shibler return (1); 329*65662Shibler } 330*65662Shibler sc->sc_blks = *(u_int *)&capbuf[0]; 331*65662Shibler sc->sc_blksize = *(int *)&capbuf[4]; 332*65662Shibler sc->sc_bshift = 0; 333*65662Shibler 334*65662Shibler /* return value of read capacity is last valid block number */ 335*65662Shibler sc->sc_blks++; 336*65662Shibler 337*65662Shibler if (sc->sc_blksize != DEV_BSIZE) { 338*65662Shibler if (sc->sc_blksize < DEV_BSIZE) { 339*65662Shibler printf("sd%d: need %d byte blocks - drive ignored\n", 340*65662Shibler hd->hp_unit, DEV_BSIZE); 341*65662Shibler return (-1); 342*65662Shibler } 343*65662Shibler for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) 344*65662Shibler ++sc->sc_bshift; 345*65662Shibler sc->sc_blks <<= sc->sc_bshift; 346*65662Shibler } 347*65662Shibler #ifdef DEBUG 348*65662Shibler if (sddebug & SDB_CAPACITY) 349*65662Shibler printf("sd%d: blks=%d, blksize=%d, bshift=%d\n", hd->hp_unit, 350*65662Shibler sc->sc_blks, sc->sc_blksize, sc->sc_bshift); 351*65662Shibler #endif 352*65662Shibler return (0); 353*65662Shibler } 354*65662Shibler 355*65662Shibler /* 35657327Shibler * Read or constuct a disklabel 35757327Shibler */ 35841480Smckusick int 35957327Shibler sdgetinfo(dev) 36057327Shibler dev_t dev; 36157327Shibler { 36257327Shibler int unit = sdunit(dev); 36357327Shibler register struct sd_softc *sc = &sd_softc[unit]; 36457327Shibler register struct disklabel *lp = &sc->sc_info.si_label; 36557327Shibler register struct partition *pi; 36657327Shibler char *msg, *readdisklabel(); 367*65662Shibler #ifdef COMPAT_NOLABEL 368*65662Shibler int usedefault = 1; 36957327Shibler 37057327Shibler /* 371*65662Shibler * For CD-ROM just define a single partition 37257327Shibler */ 373*65662Shibler if (sc->sc_type == 5) 374*65662Shibler usedefault = 0; 375*65662Shibler #endif 376*65662Shibler 37757327Shibler bzero((caddr_t)lp, sizeof *lp); 378*65662Shibler msg = NULL; 37957327Shibler 38057327Shibler /* 381*65662Shibler * If removable media or the size unavailable at boot time 382*65662Shibler * (i.e. unformatted hard disk), attempt to set the capacity 383*65662Shibler * now. 38457327Shibler */ 385*65662Shibler if ((sc->sc_flags & SDF_RMEDIA) || sc->sc_blks == 0) { 386*65662Shibler switch (sdgetcapacity(sc, sc->sc_hd, dev)) { 387*65662Shibler case 0: 388*65662Shibler break; 389*65662Shibler case -1: 390*65662Shibler /* 391*65662Shibler * Hard error, just return (open will fail). 392*65662Shibler */ 393*65662Shibler return (EIO); 394*65662Shibler case 1: 395*65662Shibler /* 396*65662Shibler * XXX return 0 so open can continue just in case 397*65662Shibler * the media is unformatted and we want to format it. 398*65662Shibler * We set the error flag so they cannot do much else. 399*65662Shibler */ 400*65662Shibler sc->sc_flags |= SDF_ERROR; 401*65662Shibler msg = "unformatted/missing media"; 402*65662Shibler #ifdef COMPAT_NOLABEL 403*65662Shibler usedefault = 0; 404*65662Shibler #endif 405*65662Shibler break; 406*65662Shibler } 407*65662Shibler } 40857327Shibler 409*65662Shibler /* 410*65662Shibler * Set some default values to use while reading the label 411*65662Shibler * (or to use if there isn't a label) and try reading it. 412*65662Shibler */ 413*65662Shibler if (msg == NULL) { 414*65662Shibler lp->d_type = DTYPE_SCSI; 415*65662Shibler lp->d_secsize = DEV_BSIZE; 416*65662Shibler lp->d_nsectors = 32; 417*65662Shibler lp->d_ntracks = 20; 418*65662Shibler lp->d_ncylinders = 1; 419*65662Shibler lp->d_secpercyl = 32*20; 420*65662Shibler lp->d_npartitions = 3; 421*65662Shibler lp->d_partitions[2].p_offset = 0; 422*65662Shibler /* XXX we can open a device even without SDF_ALIVE */ 423*65662Shibler if (sc->sc_blksize == 0) 424*65662Shibler sc->sc_blksize = DEV_BSIZE; 425*65662Shibler /* XXX ensure size is at least one device block */ 426*65662Shibler lp->d_partitions[2].p_size = 427*65662Shibler roundup(LABELSECTOR+1, btodb(sc->sc_blksize)); 428*65662Shibler msg = readdisklabel(sdlabdev(dev), sdstrategy, lp); 429*65662Shibler if (msg == NULL) 430*65662Shibler return (0); 431*65662Shibler } 432*65662Shibler 43357327Shibler pi = lp->d_partitions; 43457327Shibler printf("sd%d: WARNING: %s, ", unit, msg); 43557327Shibler #ifdef COMPAT_NOLABEL 436*65662Shibler if (usedefault) { 437*65662Shibler printf("using old default partitioning\n"); 438*65662Shibler sdmakedisklabel(unit, lp); 439*65662Shibler return(0); 440*65662Shibler } 441*65662Shibler #endif 44257327Shibler printf("defining `c' partition as entire disk\n"); 44357327Shibler pi[2].p_size = sc->sc_blks; 44457327Shibler return(0); 44557327Shibler } 44657327Shibler 44757327Shibler int 44849132Skarels sdopen(dev, flags, mode, p) 44941480Smckusick dev_t dev; 45049132Skarels int flags, mode; 45149132Skarels struct proc *p; 45241480Smckusick { 45341480Smckusick register int unit = sdunit(dev); 45441480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 45557327Shibler int mask, error; 45641480Smckusick 45741480Smckusick if (unit >= NSD) 45841480Smckusick return(ENXIO); 45949132Skarels if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag)) 46041480Smckusick return(ENXIO); 46157327Shibler if (sc->sc_flags & SDF_ERROR) 46257327Shibler return(EIO); 46341480Smckusick 46457327Shibler /* 46557327Shibler * Wait for any pending opens/closes to complete 46657327Shibler */ 46757327Shibler while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING)) 46857327Shibler sleep((caddr_t)sc, PRIBIO); 46957327Shibler /* 47057327Shibler * On first open, get label and partition info. 47157327Shibler * We may block reading the label, so be careful 47257327Shibler * to stop any other opens. 47357327Shibler */ 47457327Shibler if (sc->sc_info.si_open == 0) { 47557327Shibler sc->sc_flags |= SDF_OPENING; 47657327Shibler error = sdgetinfo(dev); 47757327Shibler sc->sc_flags &= ~SDF_OPENING; 47857327Shibler wakeup((caddr_t)sc); 47957327Shibler if (error) 48057327Shibler return(error); 48157327Shibler } 48241480Smckusick if (sc->sc_hd->hp_dk >= 0) 48341480Smckusick dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms; 48457327Shibler 48557327Shibler mask = 1 << sdpart(dev); 48657327Shibler if (mode == S_IFCHR) 48757327Shibler sc->sc_info.si_copen |= mask; 48857327Shibler else 48957327Shibler sc->sc_info.si_bopen |= mask; 49057327Shibler sc->sc_info.si_open |= mask; 49141480Smckusick return(0); 49241480Smckusick } 49341480Smckusick 49453929Shibler int 49553929Shibler sdclose(dev, flag, mode, p) 49653929Shibler dev_t dev; 49753929Shibler int flag, mode; 49853929Shibler struct proc *p; 49953929Shibler { 50053929Shibler int unit = sdunit(dev); 50153929Shibler register struct sd_softc *sc = &sd_softc[unit]; 50257327Shibler register struct sdinfo *si = &sc->sc_info; 50357327Shibler int mask, s; 50453929Shibler 50557327Shibler mask = 1 << sdpart(dev); 50657327Shibler if (mode == S_IFCHR) 50757327Shibler si->si_copen &= ~mask; 50857327Shibler else 50957327Shibler si->si_bopen &= ~mask; 51057327Shibler si->si_open = si->si_bopen | si->si_copen; 51153929Shibler /* 51257327Shibler * On last close, we wait for all activity to cease since 51357327Shibler * the label/parition info will become invalid. Since we 51457327Shibler * might sleep, we must block any opens while we are here. 51557327Shibler * Note we don't have to about other closes since we know 51657327Shibler * we are the last one. 51753929Shibler */ 51857327Shibler if (si->si_open == 0) { 51957327Shibler sc->sc_flags |= SDF_CLOSING; 52053929Shibler s = splbio(); 52153929Shibler while (sdtab[unit].b_active) { 52253929Shibler sc->sc_flags |= SDF_WANTED; 52353929Shibler sleep((caddr_t)&sdtab[unit], PRIBIO); 52453929Shibler } 52553929Shibler splx(s); 52657327Shibler sc->sc_flags &= ~(SDF_CLOSING|SDF_WLABEL|SDF_ERROR); 52757327Shibler wakeup((caddr_t)sc); 52853929Shibler } 52953929Shibler sc->sc_format_pid = 0; 53057327Shibler return(0); 53153929Shibler } 53253929Shibler 53341480Smckusick /* 53441480Smckusick * This routine is called for partial block transfers and non-aligned 53541480Smckusick * transfers (the latter only being possible on devices with a block size 53641480Smckusick * larger than DEV_BSIZE). The operation is performed in three steps 53741480Smckusick * using a locally allocated buffer: 53841480Smckusick * 1. transfer any initial partial block 53941480Smckusick * 2. transfer full blocks 54041480Smckusick * 3. transfer any final partial block 54141480Smckusick */ 54241480Smckusick static void 54341480Smckusick sdlblkstrat(bp, bsize) 54441480Smckusick register struct buf *bp; 54541480Smckusick register int bsize; 54641480Smckusick { 54741480Smckusick register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf), 54841480Smckusick M_DEVBUF, M_WAITOK); 54941480Smckusick caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); 55041480Smckusick register int bn, resid; 55141480Smckusick register caddr_t addr; 55241480Smckusick 55341480Smckusick bzero((caddr_t)cbp, sizeof(*cbp)); 55449132Skarels cbp->b_proc = curproc; /* XXX */ 55541480Smckusick cbp->b_dev = bp->b_dev; 55641480Smckusick bn = bp->b_blkno; 55741480Smckusick resid = bp->b_bcount; 55841480Smckusick addr = bp->b_un.b_addr; 55941480Smckusick #ifdef DEBUG 56041480Smckusick if (sddebug & SDB_PARTIAL) 56141480Smckusick printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", 56241480Smckusick bp, bp->b_flags, bn, resid, addr); 56341480Smckusick #endif 56441480Smckusick 56541480Smckusick while (resid > 0) { 56641480Smckusick register int boff = dbtob(bn) & (bsize - 1); 56741480Smckusick register int count; 56841480Smckusick 56941480Smckusick if (boff || resid < bsize) { 57041480Smckusick sdstats[sdunit(bp->b_dev)].sdpartials++; 57155068Spendry count = min(resid, bsize - boff); 57241480Smckusick cbp->b_flags = B_BUSY | B_PHYS | B_READ; 57341480Smckusick cbp->b_blkno = bn - btodb(boff); 57441480Smckusick cbp->b_un.b_addr = cbuf; 57541480Smckusick cbp->b_bcount = bsize; 57641480Smckusick #ifdef DEBUG 57741480Smckusick if (sddebug & SDB_PARTIAL) 57841480Smckusick printf(" readahead: bn %x cnt %x off %x addr %x\n", 57941480Smckusick cbp->b_blkno, count, boff, addr); 58041480Smckusick #endif 58141480Smckusick sdstrategy(cbp); 58241480Smckusick biowait(cbp); 58341480Smckusick if (cbp->b_flags & B_ERROR) { 58441480Smckusick bp->b_flags |= B_ERROR; 58541480Smckusick bp->b_error = cbp->b_error; 58641480Smckusick break; 58741480Smckusick } 58841480Smckusick if (bp->b_flags & B_READ) { 58941480Smckusick bcopy(&cbuf[boff], addr, count); 59041480Smckusick goto done; 59141480Smckusick } 59241480Smckusick bcopy(addr, &cbuf[boff], count); 59341480Smckusick #ifdef DEBUG 59441480Smckusick if (sddebug & SDB_PARTIAL) 59541480Smckusick printf(" writeback: bn %x cnt %x off %x addr %x\n", 59641480Smckusick cbp->b_blkno, count, boff, addr); 59741480Smckusick #endif 59841480Smckusick } else { 59941480Smckusick count = resid & ~(bsize - 1); 60041480Smckusick cbp->b_blkno = bn; 60141480Smckusick cbp->b_un.b_addr = addr; 60241480Smckusick cbp->b_bcount = count; 60341480Smckusick #ifdef DEBUG 60441480Smckusick if (sddebug & SDB_PARTIAL) 60541480Smckusick printf(" fulltrans: bn %x cnt %x addr %x\n", 60641480Smckusick cbp->b_blkno, count, addr); 60741480Smckusick #endif 60841480Smckusick } 60941480Smckusick cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); 61041480Smckusick sdstrategy(cbp); 61141480Smckusick biowait(cbp); 61241480Smckusick if (cbp->b_flags & B_ERROR) { 61341480Smckusick bp->b_flags |= B_ERROR; 61441480Smckusick bp->b_error = cbp->b_error; 61541480Smckusick break; 61641480Smckusick } 61741480Smckusick done: 61841480Smckusick bn += btodb(count); 61941480Smckusick resid -= count; 62041480Smckusick addr += count; 62141480Smckusick #ifdef DEBUG 62241480Smckusick if (sddebug & SDB_PARTIAL) 62341480Smckusick printf(" done: bn %x resid %x addr %x\n", 62441480Smckusick bn, resid, addr); 62541480Smckusick #endif 62641480Smckusick } 62741480Smckusick free(cbuf, M_DEVBUF); 62841480Smckusick free(cbp, M_DEVBUF); 62941480Smckusick } 63041480Smckusick 63141480Smckusick void 63241480Smckusick sdstrategy(bp) 63341480Smckusick register struct buf *bp; 63441480Smckusick { 63557327Shibler int unit = sdunit(bp->b_dev); 63641480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 63741480Smckusick register struct buf *dp = &sdtab[unit]; 63857327Shibler register struct partition *pinfo; 63945750Smckusick register daddr_t bn; 64045750Smckusick register int sz, s; 64141480Smckusick 64241480Smckusick if (sc->sc_format_pid) { 64349132Skarels if (sc->sc_format_pid != curproc->p_pid) { /* XXX */ 64441480Smckusick bp->b_error = EPERM; 64557327Shibler goto bad; 64641480Smckusick } 64741480Smckusick bp->b_cylin = 0; 64841480Smckusick } else { 649*65662Shibler if (sc->sc_flags & SDF_ERROR) { 650*65662Shibler bp->b_error = EIO; 651*65662Shibler goto bad; 652*65662Shibler } 65341480Smckusick bn = bp->b_blkno; 65445750Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 65557327Shibler pinfo = &sc->sc_info.si_label.d_partitions[sdpart(bp->b_dev)]; 65657327Shibler if (bn < 0 || bn + sz > pinfo->p_size) { 65757327Shibler sz = pinfo->p_size - bn; 65845750Smckusick if (sz == 0) { 65941480Smckusick bp->b_resid = bp->b_bcount; 66041480Smckusick goto done; 66141480Smckusick } 66245750Smckusick if (sz < 0) { 66345750Smckusick bp->b_error = EINVAL; 66457327Shibler goto bad; 66545750Smckusick } 66645750Smckusick bp->b_bcount = dbtob(sz); 66741480Smckusick } 66841480Smckusick /* 66957327Shibler * Check for write to write protected label 67057327Shibler */ 67157327Shibler if (bn + pinfo->p_offset <= LABELSECTOR && 67257327Shibler #if LABELSECTOR != 0 67357327Shibler bn + pinfo->p_offset + sz > LABELSECTOR && 67457327Shibler #endif 67557327Shibler !(bp->b_flags & B_READ) && !(sc->sc_flags & SDF_WLABEL)) { 67657327Shibler bp->b_error = EROFS; 67757327Shibler goto bad; 67857327Shibler } 67957327Shibler /* 68041480Smckusick * Non-aligned or partial-block transfers handled specially. 68141480Smckusick */ 68241480Smckusick s = sc->sc_blksize - 1; 68341480Smckusick if ((dbtob(bn) & s) || (bp->b_bcount & s)) { 68441480Smckusick sdlblkstrat(bp, sc->sc_blksize); 68541480Smckusick goto done; 68641480Smckusick } 68757327Shibler bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift; 68841480Smckusick } 68941480Smckusick s = splbio(); 69041480Smckusick disksort(dp, bp); 69141480Smckusick if (dp->b_active == 0) { 69241480Smckusick dp->b_active = 1; 69341480Smckusick sdustart(unit); 69441480Smckusick } 69541480Smckusick splx(s); 69641480Smckusick return; 69757327Shibler bad: 69857327Shibler bp->b_flags |= B_ERROR; 69941480Smckusick done: 70045750Smckusick biodone(bp); 70141480Smckusick } 70241480Smckusick 70341480Smckusick void 70441480Smckusick sdustart(unit) 70541480Smckusick register int unit; 70641480Smckusick { 70741480Smckusick if (scsireq(&sd_softc[unit].sc_dq)) 70841480Smckusick sdstart(unit); 70941480Smckusick } 71041480Smckusick 71150039Skarels /* 71250039Skarels * Return: 71350039Skarels * 0 if not really an error 71450039Skarels * <0 if we should do a retry 71550039Skarels * >0 if a fatal error 71650039Skarels */ 71745750Smckusick static int 71841480Smckusick sderror(unit, sc, hp, stat) 71941480Smckusick int unit, stat; 72041480Smckusick register struct sd_softc *sc; 72141480Smckusick register struct hp_device *hp; 72241480Smckusick { 72350039Skarels int cond = 1; 72445750Smckusick 72541480Smckusick sdsense[unit].status = stat; 72641480Smckusick if (stat & STS_CHECKCOND) { 72741480Smckusick struct scsi_xsense *sp; 72841480Smckusick 72941480Smckusick scsi_request_sense(hp->hp_ctlr, hp->hp_slave, 73041480Smckusick sc->sc_punit, sdsense[unit].sense, 73141480Smckusick sizeof(sdsense[unit].sense)); 73241480Smckusick sp = (struct scsi_xsense *)sdsense[unit].sense; 73341480Smckusick printf("sd%d: scsi sense class %d, code %d", unit, 73441480Smckusick sp->class, sp->code); 73541480Smckusick if (sp->class == 7) { 73641480Smckusick printf(", key %d", sp->key); 73741480Smckusick if (sp->valid) 73841480Smckusick printf(", blk %d", *(int *)&sp->info1); 73950039Skarels switch (sp->key) { 74050039Skarels /* no sense, try again */ 74150039Skarels case 0: 74250039Skarels cond = -1; 74350039Skarels break; 74450039Skarels /* recovered error, not a problem */ 74550039Skarels case 1: 74650039Skarels cond = 0; 74750039Skarels break; 74857327Shibler /* possible media change */ 74957327Shibler case 6: 75057327Shibler /* 75157327Shibler * For removable media, if we are doing the 75257327Shibler * first open (i.e. reading the label) go 75357327Shibler * ahead and retry, otherwise someone has 75457327Shibler * changed the media out from under us and 75557327Shibler * we should abort any further operations 75657327Shibler * until a close is done. 75757327Shibler */ 75857327Shibler if (sc->sc_flags & SDF_RMEDIA) { 75957327Shibler if (sc->sc_flags & SDF_OPENING) 76057327Shibler cond = -1; 76157327Shibler else 76257327Shibler sc->sc_flags |= SDF_ERROR; 76357327Shibler } 76457327Shibler break; 76550039Skarels } 76641480Smckusick } 76741480Smckusick printf("\n"); 76841480Smckusick } 76950039Skarels return(cond); 77041480Smckusick } 77141480Smckusick 77241480Smckusick static void 77341480Smckusick sdfinish(unit, sc, bp) 77441480Smckusick int unit; 77541480Smckusick register struct sd_softc *sc; 77641480Smckusick register struct buf *bp; 77741480Smckusick { 77853929Shibler register struct buf *dp = &sdtab[unit]; 77953929Shibler 78053929Shibler dp->b_errcnt = 0; 78153929Shibler dp->b_actf = bp->b_actf; 78241480Smckusick bp->b_resid = 0; 78345750Smckusick biodone(bp); 78441480Smckusick scsifree(&sc->sc_dq); 78553929Shibler if (dp->b_actf) 78641480Smckusick sdustart(unit); 78753929Shibler else { 78853929Shibler dp->b_active = 0; 78953929Shibler if (sc->sc_flags & SDF_WANTED) { 79053929Shibler sc->sc_flags &= ~SDF_WANTED; 79153929Shibler wakeup((caddr_t)dp); 79253929Shibler } 79353929Shibler } 79441480Smckusick } 79541480Smckusick 79641480Smckusick void 79741480Smckusick sdstart(unit) 79841480Smckusick register int unit; 79941480Smckusick { 80041480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 80141480Smckusick register struct hp_device *hp = sc->sc_hd; 80241480Smckusick 80341480Smckusick /* 80441480Smckusick * we have the SCSI bus -- in format mode, we may or may not need dma 80541480Smckusick * so check now. 80641480Smckusick */ 80741480Smckusick if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) { 80841480Smckusick register struct buf *bp = sdtab[unit].b_actf; 80941480Smckusick register int sts; 81041480Smckusick 811*65662Shibler sdtab[unit].b_errcnt = 0; 812*65662Shibler while (1) { 813*65662Shibler sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave, 814*65662Shibler sc->sc_punit, &sdcmd[unit], 815*65662Shibler bp->b_un.b_addr, bp->b_bcount, 816*65662Shibler bp->b_flags & B_READ); 817*65662Shibler sdsense[unit].status = sts; 818*65662Shibler if ((sts & 0xfe) == 0 || 819*65662Shibler (sts = sderror(unit, sc, hp, sts)) == 0) 820*65662Shibler break; 821*65662Shibler if (sts > 0 || sdtab[unit].b_errcnt++ >= SDRETRY) { 822*65662Shibler bp->b_flags |= B_ERROR; 823*65662Shibler bp->b_error = EIO; 824*65662Shibler break; 825*65662Shibler } 82641480Smckusick } 82741480Smckusick sdfinish(unit, sc, bp); 82841480Smckusick 82941480Smckusick } else if (scsiustart(hp->hp_ctlr)) 83041480Smckusick sdgo(unit); 83141480Smckusick } 83241480Smckusick 83341480Smckusick void 83441480Smckusick sdgo(unit) 83541480Smckusick register int unit; 83641480Smckusick { 83741480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 83841480Smckusick register struct hp_device *hp = sc->sc_hd; 83941480Smckusick register struct buf *bp = sdtab[unit].b_actf; 84041480Smckusick register int pad; 84141480Smckusick register struct scsi_fmt_cdb *cmd; 84241480Smckusick 84341480Smckusick if (sc->sc_format_pid) { 84441480Smckusick cmd = &sdcmd[unit]; 84541480Smckusick pad = 0; 84641480Smckusick } else { 847*65662Shibler /* 848*65662Shibler * Drive is in an error state, abort all operations 849*65662Shibler */ 850*65662Shibler if (sc->sc_flags & SDF_ERROR) { 851*65662Shibler bp->b_flags |= B_ERROR; 852*65662Shibler bp->b_error = EIO; 853*65662Shibler sdfinish(unit, sc, bp); 854*65662Shibler return; 855*65662Shibler } 85641480Smckusick cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd; 85741480Smckusick *(int *)(&cmd->cdb[2]) = bp->b_cylin; 85841480Smckusick pad = howmany(bp->b_bcount, sc->sc_blksize); 85941480Smckusick *(u_short *)(&cmd->cdb[7]) = pad; 86041480Smckusick pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0; 86141480Smckusick #ifdef DEBUG 86241480Smckusick if (pad) 86341480Smckusick printf("sd%d: partial block xfer -- %x bytes\n", 86441480Smckusick unit, bp->b_bcount); 86541480Smckusick #endif 86641480Smckusick sdstats[unit].sdtransfers++; 86741480Smckusick } 86857327Shibler #ifdef USELEDS 86957327Shibler if (inledcontrol == 0) 87057327Shibler ledcontrol(0, 0, LED_DISK); 87157327Shibler #endif 87241480Smckusick if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) { 87341480Smckusick if (hp->hp_dk >= 0) { 87441480Smckusick dk_busy |= 1 << hp->hp_dk; 87541480Smckusick ++dk_seek[hp->hp_dk]; 87641480Smckusick ++dk_xfer[hp->hp_dk]; 87741480Smckusick dk_wds[hp->hp_dk] += bp->b_bcount >> 6; 87841480Smckusick } 87941480Smckusick return; 88041480Smckusick } 88141480Smckusick #ifdef DEBUG 88241480Smckusick if (sddebug & SDB_ERROR) 88341480Smckusick printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n", 88441480Smckusick unit, bp->b_flags & B_READ? "read" : "write", 88541480Smckusick bp->b_un.b_addr, bp->b_cylin, bp->b_bcount, 88641480Smckusick sdtab[unit].b_errcnt); 88741480Smckusick #endif 88841480Smckusick bp->b_flags |= B_ERROR; 88941480Smckusick bp->b_error = EIO; 89041480Smckusick sdfinish(unit, sc, bp); 89141480Smckusick } 89241480Smckusick 89341480Smckusick void 89441480Smckusick sdintr(unit, stat) 89541480Smckusick register int unit; 89641480Smckusick int stat; 89741480Smckusick { 89841480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 89941480Smckusick register struct buf *bp = sdtab[unit].b_actf; 90041480Smckusick register struct hp_device *hp = sc->sc_hd; 90150039Skarels int cond; 90241480Smckusick 90341480Smckusick if (bp == NULL) { 90441480Smckusick printf("sd%d: bp == NULL\n", unit); 90541480Smckusick return; 90641480Smckusick } 90741480Smckusick if (hp->hp_dk >= 0) 90841480Smckusick dk_busy &=~ (1 << hp->hp_dk); 90941480Smckusick if (stat) { 91041480Smckusick #ifdef DEBUG 91141480Smckusick if (sddebug & SDB_ERROR) 91241480Smckusick printf("sd%d: sdintr: bad scsi status 0x%x\n", 91341480Smckusick unit, stat); 91441480Smckusick #endif 91550039Skarels cond = sderror(unit, sc, hp, stat); 91650039Skarels if (cond) { 91750039Skarels if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) { 91850038Skarels #ifdef DEBUG 91950039Skarels if (sddebug & SDB_ERROR) 92050039Skarels printf("sd%d: retry #%d\n", 92150039Skarels unit, sdtab[unit].b_errcnt); 92250038Skarels #endif 92350039Skarels sdstart(unit); 92450039Skarels return; 92550039Skarels } 92650039Skarels bp->b_flags |= B_ERROR; 92750039Skarels bp->b_error = EIO; 92845750Smckusick } 92941480Smckusick } 93041480Smckusick sdfinish(unit, sc, bp); 93141480Smckusick } 93241480Smckusick 93341480Smckusick int 93449132Skarels sdread(dev, uio, flags) 93541480Smckusick dev_t dev; 93641480Smckusick struct uio *uio; 93749132Skarels int flags; 93841480Smckusick { 93941480Smckusick register int unit = sdunit(dev); 94041480Smckusick register int pid; 94141480Smckusick 94249132Skarels if ((pid = sd_softc[unit].sc_format_pid) && 94349132Skarels pid != uio->uio_procp->p_pid) 94441480Smckusick return (EPERM); 94541480Smckusick 94649132Skarels return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio)); 94741480Smckusick } 94841480Smckusick 94941480Smckusick int 95049132Skarels sdwrite(dev, uio, flags) 95141480Smckusick dev_t dev; 95241480Smckusick struct uio *uio; 95349132Skarels int flags; 95441480Smckusick { 95541480Smckusick register int unit = sdunit(dev); 95641480Smckusick register int pid; 95741480Smckusick 95849132Skarels if ((pid = sd_softc[unit].sc_format_pid) && 95949132Skarels pid != uio->uio_procp->p_pid) 96041480Smckusick return (EPERM); 96141480Smckusick 96249132Skarels return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio)); 96341480Smckusick } 96441480Smckusick 96541480Smckusick int 96649132Skarels sdioctl(dev, cmd, data, flag, p) 96741480Smckusick dev_t dev; 96841480Smckusick int cmd; 96941480Smckusick caddr_t data; 97041480Smckusick int flag; 97149132Skarels struct proc *p; 97241480Smckusick { 97357327Shibler int unit = sdunit(dev); 97441480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 97557327Shibler register struct disklabel *lp = &sc->sc_info.si_label; 97657327Shibler int error, flags; 97741480Smckusick 97841480Smckusick switch (cmd) { 97941480Smckusick default: 98041480Smckusick return (EINVAL); 98141480Smckusick 98257327Shibler case DIOCGDINFO: 98357327Shibler *(struct disklabel *)data = *lp; 98457327Shibler return (0); 98557327Shibler 98657327Shibler case DIOCGPART: 98757327Shibler ((struct partinfo *)data)->disklab = lp; 98857327Shibler ((struct partinfo *)data)->part = 98957327Shibler &lp->d_partitions[sdpart(dev)]; 99057327Shibler return (0); 99157327Shibler 99257327Shibler case DIOCWLABEL: 99357327Shibler if ((flag & FWRITE) == 0) 99457327Shibler return (EBADF); 99557327Shibler if (*(int *)data) 99657327Shibler sc->sc_flags |= SDF_WLABEL; 99757327Shibler else 99857327Shibler sc->sc_flags &= ~SDF_WLABEL; 99957327Shibler return (0); 100057327Shibler 100157327Shibler case DIOCSDINFO: 100257327Shibler if ((flag & FWRITE) == 0) 100357327Shibler return (EBADF); 100457327Shibler error = setdisklabel(lp, (struct disklabel *)data, 100557327Shibler (sc->sc_flags & SDF_WLABEL) ? 0 100657327Shibler : sc->sc_info.si_open); 100757327Shibler return (error); 100857327Shibler 100957327Shibler case DIOCWDINFO: 101057327Shibler if ((flag & FWRITE) == 0) 101157327Shibler return (EBADF); 101257327Shibler error = setdisklabel(lp, (struct disklabel *)data, 101357327Shibler (sc->sc_flags & SDF_WLABEL) ? 0 101457327Shibler : sc->sc_info.si_open); 101557327Shibler if (error) 101657327Shibler return (error); 101757327Shibler flags = sc->sc_flags; 101857327Shibler sc->sc_flags = SDF_ALIVE | SDF_WLABEL; 101957327Shibler error = writedisklabel(sdlabdev(dev), sdstrategy, lp); 102057327Shibler sc->sc_flags = flags; 102157327Shibler return (error); 102257327Shibler 102341480Smckusick case SDIOCSFORMAT: 102441480Smckusick /* take this device into or out of "format" mode */ 102549132Skarels if (suser(p->p_ucred, &p->p_acflag)) 102641480Smckusick return(EPERM); 102741480Smckusick 102841480Smckusick if (*(int *)data) { 102941480Smckusick if (sc->sc_format_pid) 103041480Smckusick return (EPERM); 103149132Skarels sc->sc_format_pid = p->p_pid; 103241480Smckusick } else 103341480Smckusick sc->sc_format_pid = 0; 103441480Smckusick return (0); 103541480Smckusick 103641480Smckusick case SDIOCGFORMAT: 103741480Smckusick /* find out who has the device in format mode */ 103841480Smckusick *(int *)data = sc->sc_format_pid; 103941480Smckusick return (0); 104041480Smckusick 104141480Smckusick case SDIOCSCSICOMMAND: 104241480Smckusick /* 104341480Smckusick * Save what user gave us as SCSI cdb to use with next 104441480Smckusick * read or write to the char device. 104541480Smckusick */ 104649132Skarels if (sc->sc_format_pid != p->p_pid) 104741480Smckusick return (EPERM); 104841480Smckusick if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) 104941480Smckusick return (EINVAL); 105041480Smckusick bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0])); 105141480Smckusick return (0); 105241480Smckusick 105341480Smckusick case SDIOCSENSE: 105441480Smckusick /* 105541480Smckusick * return the SCSI sense data saved after the last 105641480Smckusick * operation that completed with "check condition" status. 105741480Smckusick */ 105841480Smckusick bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0])); 105941480Smckusick return (0); 106041480Smckusick 106141480Smckusick } 106241480Smckusick /*NOTREACHED*/ 106341480Smckusick } 106441480Smckusick 106541480Smckusick int 106641480Smckusick sdsize(dev) 106741480Smckusick dev_t dev; 106841480Smckusick { 106941480Smckusick register int unit = sdunit(dev); 107041480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 107157327Shibler int psize, didopen = 0; 107241480Smckusick 107341480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 107441480Smckusick return(-1); 107541480Smckusick 107657327Shibler /* 107757327Shibler * We get called very early on (via swapconf) 107857327Shibler * without the device being open so we may need 107957327Shibler * to handle it here. 108057327Shibler */ 108157327Shibler if (sc->sc_info.si_open == 0) { 108257327Shibler if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL)) 108357327Shibler return(-1); 108457327Shibler didopen = 1; 108557327Shibler } 108657327Shibler psize = sc->sc_info.si_label.d_partitions[sdpart(dev)].p_size; 108757327Shibler if (didopen) 108857327Shibler (void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL); 108957327Shibler return (psize); 109041480Smckusick } 109141480Smckusick 109241480Smckusick /* 109341480Smckusick * Non-interrupt driven, non-dma dump routine. 109441480Smckusick */ 109541480Smckusick int 109641480Smckusick sddump(dev) 109741480Smckusick dev_t dev; 109841480Smckusick { 109941480Smckusick int part = sdpart(dev); 110041480Smckusick int unit = sdunit(dev); 110141480Smckusick register struct sd_softc *sc = &sd_softc[unit]; 110241480Smckusick register struct hp_device *hp = sc->sc_hd; 110357327Shibler register struct partition *pinfo; 110441480Smckusick register daddr_t baddr; 110541480Smckusick register int maddr; 110641480Smckusick register int pages, i; 110741480Smckusick int stat; 110841480Smckusick extern int lowram; 110941480Smckusick 111041480Smckusick /* is drive ok? */ 111141480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) 111241480Smckusick return (ENXIO); 111357327Shibler pinfo = &sc->sc_info.si_label.d_partitions[part]; 111441480Smckusick /* dump parameters in range? */ 111557327Shibler if (dumplo < 0 || dumplo >= pinfo->p_size || 111657327Shibler pinfo->p_fstype != FS_SWAP) 111741480Smckusick return (EINVAL); 111857327Shibler pages = physmem; 111957327Shibler if (dumplo + ctod(pages) > pinfo->p_size) 112057327Shibler pages = dtoc(pinfo->p_size - dumplo); 112141480Smckusick maddr = lowram; 112257327Shibler baddr = dumplo + pinfo->p_offset; 112341480Smckusick /* scsi bus idle? */ 112441480Smckusick if (!scsireq(&sc->sc_dq)) { 112541480Smckusick scsireset(hp->hp_ctlr); 112641480Smckusick sdreset(sc, sc->sc_hd); 112741480Smckusick printf("[ drive %d reset ] ", unit); 112841480Smckusick } 112941480Smckusick for (i = 0; i < pages; i++) { 113041480Smckusick #define NPGMB (1024*1024/NBPG) 113141480Smckusick /* print out how many Mbs we have dumped */ 113241480Smckusick if (i && (i % NPGMB) == 0) 113341480Smckusick printf("%d ", i / NPGMB); 113441480Smckusick #undef NPBMG 113552614Smckusick pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr, 113651576Smckusick VM_PROT_READ, TRUE); 113741480Smckusick stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, 113841480Smckusick vmmap, NBPG, baddr, sc->sc_bshift); 113941480Smckusick if (stat) { 114041480Smckusick printf("sddump: scsi write error 0x%x\n", stat); 114141480Smckusick return (EIO); 114241480Smckusick } 114341480Smckusick maddr += NBPG; 114441480Smckusick baddr += ctod(1); 114541480Smckusick } 114641480Smckusick return (0); 114741480Smckusick } 114841480Smckusick #endif 1149