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*69452Smckusick * @(#)sd.c 8.9 (Berkeley) 05/14/95
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
41*69452Smckusick #include <vm/vm.h>
4256507Sbostic
4341480Smckusick extern int scsi_test_unit_rdy();
4441480Smckusick extern int scsi_request_sense();
4541480Smckusick extern int scsi_inquiry();
4641480Smckusick extern int scsi_read_capacity();
4741480Smckusick extern int scsi_tt_write();
4841480Smckusick extern int scsireq();
4941480Smckusick extern int scsiustart();
5041480Smckusick extern int scsigo();
5141480Smckusick extern void scsifree();
5241480Smckusick extern void scsireset();
5349304Shibler extern void scsi_delay();
5441480Smckusick
5541480Smckusick extern void disksort();
5641480Smckusick extern void biodone();
5741480Smckusick extern int physio();
5841480Smckusick extern void TBIS();
5941480Smckusick
6041480Smckusick int sdinit();
6141480Smckusick void sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr();
6241480Smckusick
6341480Smckusick struct driver sddriver = {
6441480Smckusick sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr,
6541480Smckusick };
6641480Smckusick
6741480Smckusick #ifdef DEBUG
6841480Smckusick int sddebug = 1;
6941480Smckusick #define SDB_ERROR 0x01
7041480Smckusick #define SDB_PARTIAL 0x02
7165662Shibler #define SDB_CAPACITY 0x04
7241480Smckusick #endif
7341480Smckusick
7457327Shibler struct sd_softc sd_softc[NSD];
7557327Shibler struct sdstats sdstats[NSD];
7641480Smckusick struct buf sdtab[NSD];
7741480Smckusick struct scsi_fmt_cdb sdcmd[NSD];
7841480Smckusick struct scsi_fmt_sense sdsense[NSD];
7941480Smckusick
8041480Smckusick static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT };
8141480Smckusick static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT };
8241480Smckusick
8341480Smckusick /*
8441480Smckusick * Table of scsi commands users are allowed to access via "format"
8541480Smckusick * mode. 0 means not legal. 1 means "immediate" (doesn't need dma).
8641480Smckusick * -1 means needs dma and/or wait for intr.
8741480Smckusick */
8841480Smckusick static char legal_cmds[256] = {
8941480Smckusick /***** 0 1 2 3 4 5 6 7 8 9 A B C D E F */
9041480Smckusick /*00*/ 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9141480Smckusick /*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
9241480Smckusick /*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9341480Smckusick /*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9441480Smckusick /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9541480Smckusick /*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9641480Smckusick /*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9741480Smckusick /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9841480Smckusick /*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9941480Smckusick /*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10041480Smckusick /*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10141480Smckusick /*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10241480Smckusick /*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10341480Smckusick /*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10441480Smckusick /*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10541480Smckusick /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
10641480Smckusick };
10741480Smckusick
10841480Smckusick static struct scsi_inquiry inqbuf;
10941480Smckusick static struct scsi_fmt_cdb inq = {
11041480Smckusick 6,
11141480Smckusick CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
11241480Smckusick };
11341480Smckusick
11441480Smckusick static int
sdident(sc,hd)11541480Smckusick sdident(sc, hd)
11641480Smckusick struct sd_softc *sc;
11741480Smckusick struct hp_device *hd;
11841480Smckusick {
11941480Smckusick int unit;
12041480Smckusick register int ctlr, slave;
12141480Smckusick register int i;
12241480Smckusick register int tries = 10;
12349304Shibler char idstr[32];
12465662Shibler int isrm = 0;
12541480Smckusick
12641480Smckusick ctlr = hd->hp_ctlr;
12741480Smckusick slave = hd->hp_slave;
12841480Smckusick unit = sc->sc_punit;
12949304Shibler scsi_delay(-1);
13041480Smckusick
13141480Smckusick /*
13241480Smckusick * See if unit exists and is a disk then read block size & nblocks.
13341480Smckusick */
13441480Smckusick while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) {
13545750Smckusick if (i == -1 || --tries < 0) {
13665662Shibler if (isrm)
13745750Smckusick break;
13841480Smckusick /* doesn't exist or not a CCS device */
13949304Shibler goto failed;
14045750Smckusick }
14141480Smckusick if (i == STS_CHECKCOND) {
14241480Smckusick u_char sensebuf[128];
14341480Smckusick struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
14441480Smckusick
14541480Smckusick scsi_request_sense(ctlr, slave, unit, sensebuf,
14641480Smckusick sizeof(sensebuf));
14745750Smckusick if (sp->class == 7)
14845750Smckusick switch (sp->key) {
14965662Shibler /*
15065662Shibler * Not ready -- might be removable media
15165662Shibler * device with no media. Assume as much,
15265662Shibler * if it really isn't, the inquiry commmand
15365662Shibler * below will fail.
15465662Shibler */
15545750Smckusick case 2:
15665662Shibler isrm = 1;
15745750Smckusick break;
15841480Smckusick /* drive doing an RTZ -- give it a while */
15945750Smckusick case 6:
16045750Smckusick DELAY(1000000);
16145750Smckusick break;
16245750Smckusick default:
16345750Smckusick break;
16445750Smckusick }
16541480Smckusick }
16641480Smckusick DELAY(1000);
16741480Smckusick }
16845750Smckusick /*
16945750Smckusick * Find out about device
17045750Smckusick */
17145750Smckusick if (scsi_immed_command(ctlr, slave, unit, &inq,
17245750Smckusick (u_char *)&inqbuf, sizeof(inqbuf), B_READ))
17349304Shibler goto failed;
17441480Smckusick switch (inqbuf.type) {
17541480Smckusick case 0: /* disk */
17641480Smckusick case 4: /* WORM */
17741480Smckusick case 5: /* CD-ROM */
17841480Smckusick case 7: /* Magneto-optical */
17941480Smckusick break;
18041480Smckusick default: /* not a disk */
18149304Shibler goto failed;
18241480Smckusick }
18345750Smckusick /*
18449304Shibler * Get a usable id string
18545750Smckusick */
18657327Shibler switch (inqbuf.version) {
18757327Shibler case 1:
18857327Shibler case 2:
18949304Shibler bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28);
19049304Shibler for (i = 27; i > 23; --i)
19149304Shibler if (idstr[i] != ' ')
19249304Shibler break;
19349304Shibler idstr[i+1] = 0;
19449304Shibler for (i = 23; i > 7; --i)
19549304Shibler if (idstr[i] != ' ')
19649304Shibler break;
19749304Shibler idstr[i+1] = 0;
19849304Shibler for (i = 7; i >= 0; --i)
19949304Shibler if (idstr[i] != ' ')
20049304Shibler break;
20149304Shibler idstr[i+1] = 0;
20257327Shibler break;
20357327Shibler default:
20457327Shibler bcopy("UNKNOWN", &idstr[0], 8);
20557327Shibler bcopy("DRIVE TYPE", &idstr[8], 11);
20645750Smckusick }
20765662Shibler if (inqbuf.qual & 0x80)
20865662Shibler sc->sc_flags |= SDF_RMEDIA;
20945750Smckusick
21065662Shibler if (sdgetcapacity(sc, hd, NODEV) < 0)
21165662Shibler goto failed;
21265662Shibler
21357327Shibler switch (inqbuf.version) {
21457327Shibler case 1:
21557327Shibler case 2:
21641480Smckusick printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8],
21741480Smckusick &idstr[24]);
21857327Shibler if (inqbuf.version == 2)
21957327Shibler printf(" (SCSI-2)");
22057327Shibler break;
22157327Shibler default:
22257327Shibler printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit,
22357327Shibler inqbuf.type, inqbuf.qual, inqbuf.version);
22457327Shibler break;
22557327Shibler }
22665662Shibler if (sc->sc_blks)
22765662Shibler printf(", %d %d byte blocks",
22865662Shibler sc->sc_blks >> sc->sc_bshift, sc->sc_blksize);
22965662Shibler printf("\n");
23041480Smckusick sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */
23149304Shibler scsi_delay(0);
23241480Smckusick return(inqbuf.type);
23349304Shibler failed:
23449304Shibler scsi_delay(0);
23549304Shibler return(-1);
23641480Smckusick }
23741480Smckusick
23841480Smckusick int
sdinit(hd)23941480Smckusick sdinit(hd)
24041480Smckusick register struct hp_device *hd;
24141480Smckusick {
24241480Smckusick register struct sd_softc *sc = &sd_softc[hd->hp_unit];
24341480Smckusick
24441480Smckusick sc->sc_hd = hd;
24553929Shibler sc->sc_flags = 0;
24666072Shibler /*
24766072Shibler * XXX formerly 0 meant unused but now pid 0 can legitimately
24866072Shibler * use this interface (sdgetcapacity).
24966072Shibler */
25066072Shibler sc->sc_format_pid = -1;
25141480Smckusick sc->sc_punit = sdpunit(hd->hp_flags);
25241480Smckusick sc->sc_type = sdident(sc, hd);
25341480Smckusick if (sc->sc_type < 0)
25441480Smckusick return(0);
25541480Smckusick sc->sc_dq.dq_ctlr = hd->hp_ctlr;
25641480Smckusick sc->sc_dq.dq_unit = hd->hp_unit;
25741480Smckusick sc->sc_dq.dq_slave = hd->hp_slave;
25841480Smckusick sc->sc_dq.dq_driver = &sddriver;
25941480Smckusick
26053929Shibler sc->sc_flags |= SDF_ALIVE;
26141480Smckusick return(1);
26241480Smckusick }
26341480Smckusick
26441480Smckusick void
sdreset(sc,hd)26541480Smckusick sdreset(sc, hd)
26641480Smckusick register struct sd_softc *sc;
26741480Smckusick register struct hp_device *hd;
26841480Smckusick {
26941480Smckusick sdstats[hd->hp_unit].sdresets++;
27041480Smckusick }
27141480Smckusick
27257327Shibler /*
27365662Shibler * Determine capacity of a drive.
27465662Shibler * Returns -1 on a failure, 0 on success, 1 on a failure that is probably
27565662Shibler * due to missing media.
27665662Shibler */
27765662Shibler int
sdgetcapacity(sc,hd,dev)27865662Shibler sdgetcapacity(sc, hd, dev)
27965662Shibler struct sd_softc *sc;
28065662Shibler struct hp_device *hd;
28165662Shibler dev_t dev;
28265662Shibler {
28365662Shibler static struct scsi_fmt_cdb cap = {
28465662Shibler 10,
28565662Shibler CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0
28665662Shibler };
28766072Shibler u_char *capbuf;
28866072Shibler int i, capbufsize;
28965662Shibler
29066072Shibler /*
29166072Shibler * Cannot use stack space for this buffer since stack KVA may not
29266072Shibler * be valid (i.e. in context of this process) when the operation
29366072Shibler * actually starts.
29466072Shibler */
29566072Shibler capbufsize = 8;
29666072Shibler capbuf = malloc(capbufsize, M_DEVBUF, M_WAITOK);
29766072Shibler
29865662Shibler if (dev == NODEV) {
29965662Shibler i = scsi_immed_command(hd->hp_ctlr, hd->hp_slave, sc->sc_punit,
30066072Shibler &cap, capbuf, capbufsize, B_READ);
30165662Shibler } else {
30266072Shibler struct buf *bp;
30366072Shibler
30465662Shibler /*
30565662Shibler * XXX this is horrible
30665662Shibler */
30766072Shibler if (sc->sc_format_pid >= 0)
30865662Shibler panic("sdgetcapacity");
30966072Shibler bp = malloc(sizeof *bp, M_DEVBUF, M_WAITOK);
31065662Shibler sc->sc_format_pid = curproc->p_pid;
31165662Shibler bcopy((caddr_t)&cap, (caddr_t)&sdcmd[hd->hp_unit], sizeof cap);
31266072Shibler bp->b_dev = dev;
31366072Shibler bp->b_flags = B_READ | B_BUSY;
31466072Shibler bp->b_un.b_addr = (caddr_t)capbuf;
31566072Shibler bp->b_bcount = capbufsize;
31666072Shibler sdstrategy(bp);
31766072Shibler i = biowait(bp) ? sdsense[hd->hp_unit].status : 0;
31866072Shibler free(bp, M_DEVBUF);
31966072Shibler sc->sc_format_pid = -1;
32065662Shibler }
32165662Shibler if (i) {
32265662Shibler if (i != STS_CHECKCOND || (sc->sc_flags & SDF_RMEDIA) == 0) {
32365662Shibler #ifdef DEBUG
32465662Shibler if (sddebug & SDB_CAPACITY)
32565662Shibler printf("sd%d: read_capacity returns %d\n",
32665662Shibler hd->hp_unit, i);
32765662Shibler #endif
32866072Shibler free(capbuf, M_DEVBUF);
32965662Shibler return (-1);
33065662Shibler }
33165662Shibler /*
33265662Shibler * XXX assume unformatted or non-existant media
33365662Shibler */
33465662Shibler sc->sc_blks = 0;
33565662Shibler sc->sc_blksize = DEV_BSIZE;
33665662Shibler sc->sc_bshift = 0;
33765662Shibler #ifdef DEBUG
33865662Shibler if (sddebug & SDB_CAPACITY)
33965662Shibler printf("sd%d: removable media not present\n",
34065662Shibler hd->hp_unit);
34165662Shibler #endif
34266072Shibler free(capbuf, M_DEVBUF);
34365662Shibler return (1);
34465662Shibler }
34565662Shibler sc->sc_blks = *(u_int *)&capbuf[0];
34665662Shibler sc->sc_blksize = *(int *)&capbuf[4];
34766072Shibler free(capbuf, M_DEVBUF);
34865662Shibler sc->sc_bshift = 0;
34965662Shibler
35065662Shibler /* return value of read capacity is last valid block number */
35165662Shibler sc->sc_blks++;
35265662Shibler
35365662Shibler if (sc->sc_blksize != DEV_BSIZE) {
35465662Shibler if (sc->sc_blksize < DEV_BSIZE) {
35566072Shibler printf("sd%d: need at least %d byte blocks - %s\n",
35666072Shibler hd->hp_unit, DEV_BSIZE, "drive ignored");
35765662Shibler return (-1);
35865662Shibler }
35965662Shibler for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)
36065662Shibler ++sc->sc_bshift;
36165662Shibler sc->sc_blks <<= sc->sc_bshift;
36265662Shibler }
36365662Shibler #ifdef DEBUG
36465662Shibler if (sddebug & SDB_CAPACITY)
36565662Shibler printf("sd%d: blks=%d, blksize=%d, bshift=%d\n", hd->hp_unit,
36665662Shibler sc->sc_blks, sc->sc_blksize, sc->sc_bshift);
36765662Shibler #endif
36865662Shibler return (0);
36965662Shibler }
37065662Shibler
37165662Shibler /*
37257327Shibler * Read or constuct a disklabel
37357327Shibler */
37441480Smckusick int
sdgetinfo(dev)37557327Shibler sdgetinfo(dev)
37657327Shibler dev_t dev;
37757327Shibler {
37857327Shibler int unit = sdunit(dev);
37957327Shibler register struct sd_softc *sc = &sd_softc[unit];
38057327Shibler register struct disklabel *lp = &sc->sc_info.si_label;
38157327Shibler register struct partition *pi;
38257327Shibler char *msg, *readdisklabel();
38365662Shibler #ifdef COMPAT_NOLABEL
38465662Shibler int usedefault = 1;
38557327Shibler
38657327Shibler /*
38765662Shibler * For CD-ROM just define a single partition
38857327Shibler */
38965662Shibler if (sc->sc_type == 5)
39065662Shibler usedefault = 0;
39165662Shibler #endif
39265662Shibler
39357327Shibler bzero((caddr_t)lp, sizeof *lp);
39465662Shibler msg = NULL;
39557327Shibler
39657327Shibler /*
39765662Shibler * If removable media or the size unavailable at boot time
39865662Shibler * (i.e. unformatted hard disk), attempt to set the capacity
39965662Shibler * now.
40057327Shibler */
40165662Shibler if ((sc->sc_flags & SDF_RMEDIA) || sc->sc_blks == 0) {
40265662Shibler switch (sdgetcapacity(sc, sc->sc_hd, dev)) {
40365662Shibler case 0:
40465662Shibler break;
40565662Shibler case -1:
40665662Shibler /*
40765662Shibler * Hard error, just return (open will fail).
40865662Shibler */
40965662Shibler return (EIO);
41065662Shibler case 1:
41165662Shibler /*
41265662Shibler * XXX return 0 so open can continue just in case
41365662Shibler * the media is unformatted and we want to format it.
41465662Shibler * We set the error flag so they cannot do much else.
41565662Shibler */
41665662Shibler sc->sc_flags |= SDF_ERROR;
41765662Shibler msg = "unformatted/missing media";
41865662Shibler #ifdef COMPAT_NOLABEL
41965662Shibler usedefault = 0;
42065662Shibler #endif
42165662Shibler break;
42265662Shibler }
42365662Shibler }
42457327Shibler
42565662Shibler /*
42665662Shibler * Set some default values to use while reading the label
42765662Shibler * (or to use if there isn't a label) and try reading it.
42865662Shibler */
42965662Shibler if (msg == NULL) {
43065662Shibler lp->d_type = DTYPE_SCSI;
43165662Shibler lp->d_secsize = DEV_BSIZE;
43265662Shibler lp->d_nsectors = 32;
43365662Shibler lp->d_ntracks = 20;
43465662Shibler lp->d_ncylinders = 1;
43565662Shibler lp->d_secpercyl = 32*20;
43665662Shibler lp->d_npartitions = 3;
43765662Shibler lp->d_partitions[2].p_offset = 0;
43865662Shibler /* XXX we can open a device even without SDF_ALIVE */
43965662Shibler if (sc->sc_blksize == 0)
44065662Shibler sc->sc_blksize = DEV_BSIZE;
44165662Shibler /* XXX ensure size is at least one device block */
44265662Shibler lp->d_partitions[2].p_size =
44365662Shibler roundup(LABELSECTOR+1, btodb(sc->sc_blksize));
44465662Shibler msg = readdisklabel(sdlabdev(dev), sdstrategy, lp);
44565662Shibler if (msg == NULL)
44665662Shibler return (0);
44765662Shibler }
44865662Shibler
44957327Shibler pi = lp->d_partitions;
45057327Shibler printf("sd%d: WARNING: %s, ", unit, msg);
45157327Shibler #ifdef COMPAT_NOLABEL
45265662Shibler if (usedefault) {
45365662Shibler printf("using old default partitioning\n");
45465662Shibler sdmakedisklabel(unit, lp);
45565662Shibler return(0);
45665662Shibler }
45765662Shibler #endif
45857327Shibler printf("defining `c' partition as entire disk\n");
45957327Shibler pi[2].p_size = sc->sc_blks;
46067184Shibler /* XXX reset other info since readdisklabel screws with it */
46167184Shibler lp->d_npartitions = 3;
46267184Shibler pi[0].p_size = 0;
46357327Shibler return(0);
46457327Shibler }
46557327Shibler
46657327Shibler int
sdopen(dev,flags,mode,p)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];
47469353Smckusick int error, mask;
47541480Smckusick
47669353Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
47741480Smckusick return(ENXIO);
47841480Smckusick
47957327Shibler /*
48057327Shibler * Wait for any pending opens/closes to complete
48157327Shibler */
48257327Shibler while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING))
48357327Shibler sleep((caddr_t)sc, PRIBIO);
48469353Smckusick
48557327Shibler /*
48657327Shibler * On first open, get label and partition info.
48757327Shibler * We may block reading the label, so be careful
48857327Shibler * to stop any other opens.
48957327Shibler */
49057327Shibler if (sc->sc_info.si_open == 0) {
49157327Shibler sc->sc_flags |= SDF_OPENING;
49257327Shibler error = sdgetinfo(dev);
49357327Shibler sc->sc_flags &= ~SDF_OPENING;
49457327Shibler wakeup((caddr_t)sc);
49557327Shibler if (error)
49657327Shibler return(error);
49757327Shibler }
49841480Smckusick if (sc->sc_hd->hp_dk >= 0)
49941480Smckusick dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms;
50057327Shibler
50157327Shibler mask = 1 << sdpart(dev);
50257327Shibler if (mode == S_IFCHR)
50357327Shibler sc->sc_info.si_copen |= mask;
50457327Shibler else
50557327Shibler sc->sc_info.si_bopen |= mask;
50657327Shibler sc->sc_info.si_open |= mask;
50741480Smckusick return(0);
50841480Smckusick }
50941480Smckusick
51053929Shibler int
sdclose(dev,flag,mode,p)51153929Shibler sdclose(dev, flag, mode, p)
51253929Shibler dev_t dev;
51353929Shibler int flag, mode;
51453929Shibler struct proc *p;
51553929Shibler {
51653929Shibler int unit = sdunit(dev);
51753929Shibler register struct sd_softc *sc = &sd_softc[unit];
51857327Shibler register struct sdinfo *si = &sc->sc_info;
51957327Shibler int mask, s;
52053929Shibler
52157327Shibler mask = 1 << sdpart(dev);
52257327Shibler if (mode == S_IFCHR)
52357327Shibler si->si_copen &= ~mask;
52457327Shibler else
52557327Shibler si->si_bopen &= ~mask;
52657327Shibler si->si_open = si->si_bopen | si->si_copen;
52753929Shibler /*
52857327Shibler * On last close, we wait for all activity to cease since
52957327Shibler * the label/parition info will become invalid. Since we
53057327Shibler * might sleep, we must block any opens while we are here.
53157327Shibler * Note we don't have to about other closes since we know
53257327Shibler * we are the last one.
53353929Shibler */
53457327Shibler if (si->si_open == 0) {
53557327Shibler sc->sc_flags |= SDF_CLOSING;
53653929Shibler s = splbio();
53753929Shibler while (sdtab[unit].b_active) {
53853929Shibler sc->sc_flags |= SDF_WANTED;
53953929Shibler sleep((caddr_t)&sdtab[unit], PRIBIO);
54053929Shibler }
54153929Shibler splx(s);
54257327Shibler sc->sc_flags &= ~(SDF_CLOSING|SDF_WLABEL|SDF_ERROR);
54357327Shibler wakeup((caddr_t)sc);
54453929Shibler }
54566072Shibler sc->sc_format_pid = -1;
54657327Shibler return(0);
54753929Shibler }
54853929Shibler
54941480Smckusick /*
55041480Smckusick * This routine is called for partial block transfers and non-aligned
55141480Smckusick * transfers (the latter only being possible on devices with a block size
55241480Smckusick * larger than DEV_BSIZE). The operation is performed in three steps
55341480Smckusick * using a locally allocated buffer:
55441480Smckusick * 1. transfer any initial partial block
55541480Smckusick * 2. transfer full blocks
55641480Smckusick * 3. transfer any final partial block
55741480Smckusick */
55841480Smckusick static void
sdlblkstrat(bp,bsize)55941480Smckusick sdlblkstrat(bp, bsize)
56041480Smckusick register struct buf *bp;
56141480Smckusick register int bsize;
56241480Smckusick {
56341480Smckusick register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf),
56441480Smckusick M_DEVBUF, M_WAITOK);
56541480Smckusick caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK);
56641480Smckusick register int bn, resid;
56741480Smckusick register caddr_t addr;
56841480Smckusick
56941480Smckusick bzero((caddr_t)cbp, sizeof(*cbp));
57049132Skarels cbp->b_proc = curproc; /* XXX */
57141480Smckusick cbp->b_dev = bp->b_dev;
57241480Smckusick bn = bp->b_blkno;
57341480Smckusick resid = bp->b_bcount;
57441480Smckusick addr = bp->b_un.b_addr;
57541480Smckusick #ifdef DEBUG
57641480Smckusick if (sddebug & SDB_PARTIAL)
57741480Smckusick printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n",
57841480Smckusick bp, bp->b_flags, bn, resid, addr);
57941480Smckusick #endif
58041480Smckusick
58141480Smckusick while (resid > 0) {
58241480Smckusick register int boff = dbtob(bn) & (bsize - 1);
58341480Smckusick register int count;
58441480Smckusick
58541480Smckusick if (boff || resid < bsize) {
58641480Smckusick sdstats[sdunit(bp->b_dev)].sdpartials++;
58755068Spendry count = min(resid, bsize - boff);
58841480Smckusick cbp->b_flags = B_BUSY | B_PHYS | B_READ;
58941480Smckusick cbp->b_blkno = bn - btodb(boff);
59041480Smckusick cbp->b_un.b_addr = cbuf;
59141480Smckusick cbp->b_bcount = bsize;
59241480Smckusick #ifdef DEBUG
59341480Smckusick if (sddebug & SDB_PARTIAL)
59441480Smckusick printf(" readahead: bn %x cnt %x off %x addr %x\n",
59541480Smckusick cbp->b_blkno, count, boff, addr);
59641480Smckusick #endif
59741480Smckusick sdstrategy(cbp);
59841480Smckusick biowait(cbp);
59941480Smckusick if (cbp->b_flags & B_ERROR) {
60041480Smckusick bp->b_flags |= B_ERROR;
60141480Smckusick bp->b_error = cbp->b_error;
60241480Smckusick break;
60341480Smckusick }
60441480Smckusick if (bp->b_flags & B_READ) {
60541480Smckusick bcopy(&cbuf[boff], addr, count);
60641480Smckusick goto done;
60741480Smckusick }
60841480Smckusick bcopy(addr, &cbuf[boff], count);
60941480Smckusick #ifdef DEBUG
61041480Smckusick if (sddebug & SDB_PARTIAL)
61141480Smckusick printf(" writeback: bn %x cnt %x off %x addr %x\n",
61241480Smckusick cbp->b_blkno, count, boff, addr);
61341480Smckusick #endif
61441480Smckusick } else {
61541480Smckusick count = resid & ~(bsize - 1);
61641480Smckusick cbp->b_blkno = bn;
61741480Smckusick cbp->b_un.b_addr = addr;
61841480Smckusick cbp->b_bcount = count;
61941480Smckusick #ifdef DEBUG
62041480Smckusick if (sddebug & SDB_PARTIAL)
62141480Smckusick printf(" fulltrans: bn %x cnt %x addr %x\n",
62241480Smckusick cbp->b_blkno, count, addr);
62341480Smckusick #endif
62441480Smckusick }
62541480Smckusick cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ);
62641480Smckusick sdstrategy(cbp);
62741480Smckusick biowait(cbp);
62841480Smckusick if (cbp->b_flags & B_ERROR) {
62941480Smckusick bp->b_flags |= B_ERROR;
63041480Smckusick bp->b_error = cbp->b_error;
63141480Smckusick break;
63241480Smckusick }
63341480Smckusick done:
63441480Smckusick bn += btodb(count);
63541480Smckusick resid -= count;
63641480Smckusick addr += count;
63741480Smckusick #ifdef DEBUG
63841480Smckusick if (sddebug & SDB_PARTIAL)
63941480Smckusick printf(" done: bn %x resid %x addr %x\n",
64041480Smckusick bn, resid, addr);
64141480Smckusick #endif
64241480Smckusick }
64341480Smckusick free(cbuf, M_DEVBUF);
64441480Smckusick free(cbp, M_DEVBUF);
64541480Smckusick }
64641480Smckusick
64741480Smckusick void
sdstrategy(bp)64841480Smckusick sdstrategy(bp)
64941480Smckusick register struct buf *bp;
65041480Smckusick {
65157327Shibler int unit = sdunit(bp->b_dev);
65241480Smckusick register struct sd_softc *sc = &sd_softc[unit];
65341480Smckusick register struct buf *dp = &sdtab[unit];
65457327Shibler register struct partition *pinfo;
65545750Smckusick register daddr_t bn;
65645750Smckusick register int sz, s;
65741480Smckusick
65866072Shibler if (sc->sc_format_pid >= 0) {
65949132Skarels if (sc->sc_format_pid != curproc->p_pid) { /* XXX */
66041480Smckusick bp->b_error = EPERM;
66157327Shibler goto bad;
66241480Smckusick }
66341480Smckusick bp->b_cylin = 0;
66441480Smckusick } else {
66565662Shibler if (sc->sc_flags & SDF_ERROR) {
66665662Shibler bp->b_error = EIO;
66765662Shibler goto bad;
66865662Shibler }
66941480Smckusick bn = bp->b_blkno;
67045750Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE);
67157327Shibler pinfo = &sc->sc_info.si_label.d_partitions[sdpart(bp->b_dev)];
67257327Shibler if (bn < 0 || bn + sz > pinfo->p_size) {
67357327Shibler sz = pinfo->p_size - bn;
67445750Smckusick if (sz == 0) {
67541480Smckusick bp->b_resid = bp->b_bcount;
67641480Smckusick goto done;
67741480Smckusick }
67845750Smckusick if (sz < 0) {
67945750Smckusick bp->b_error = EINVAL;
68057327Shibler goto bad;
68145750Smckusick }
68245750Smckusick bp->b_bcount = dbtob(sz);
68341480Smckusick }
68441480Smckusick /*
68557327Shibler * Check for write to write protected label
68657327Shibler */
68757327Shibler if (bn + pinfo->p_offset <= LABELSECTOR &&
68857327Shibler #if LABELSECTOR != 0
68957327Shibler bn + pinfo->p_offset + sz > LABELSECTOR &&
69057327Shibler #endif
69157327Shibler !(bp->b_flags & B_READ) && !(sc->sc_flags & SDF_WLABEL)) {
69257327Shibler bp->b_error = EROFS;
69357327Shibler goto bad;
69457327Shibler }
69557327Shibler /*
69641480Smckusick * Non-aligned or partial-block transfers handled specially.
69741480Smckusick */
69841480Smckusick s = sc->sc_blksize - 1;
69941480Smckusick if ((dbtob(bn) & s) || (bp->b_bcount & s)) {
70041480Smckusick sdlblkstrat(bp, sc->sc_blksize);
70141480Smckusick goto done;
70241480Smckusick }
70357327Shibler bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift;
70441480Smckusick }
70541480Smckusick s = splbio();
70641480Smckusick disksort(dp, bp);
70741480Smckusick if (dp->b_active == 0) {
70841480Smckusick dp->b_active = 1;
70941480Smckusick sdustart(unit);
71041480Smckusick }
71141480Smckusick splx(s);
71241480Smckusick return;
71357327Shibler bad:
71457327Shibler bp->b_flags |= B_ERROR;
71541480Smckusick done:
71645750Smckusick biodone(bp);
71741480Smckusick }
71841480Smckusick
71941480Smckusick void
sdustart(unit)72041480Smckusick sdustart(unit)
72141480Smckusick register int unit;
72241480Smckusick {
72341480Smckusick if (scsireq(&sd_softc[unit].sc_dq))
72441480Smckusick sdstart(unit);
72541480Smckusick }
72641480Smckusick
72750039Skarels /*
72850039Skarels * Return:
72950039Skarels * 0 if not really an error
73050039Skarels * <0 if we should do a retry
73150039Skarels * >0 if a fatal error
73250039Skarels */
73345750Smckusick static int
sderror(unit,sc,hp,stat)73441480Smckusick sderror(unit, sc, hp, stat)
73541480Smckusick int unit, stat;
73641480Smckusick register struct sd_softc *sc;
73741480Smckusick register struct hp_device *hp;
73841480Smckusick {
73950039Skarels int cond = 1;
74045750Smckusick
74141480Smckusick sdsense[unit].status = stat;
74241480Smckusick if (stat & STS_CHECKCOND) {
74341480Smckusick struct scsi_xsense *sp;
74441480Smckusick
74541480Smckusick scsi_request_sense(hp->hp_ctlr, hp->hp_slave,
74641480Smckusick sc->sc_punit, sdsense[unit].sense,
74741480Smckusick sizeof(sdsense[unit].sense));
74841480Smckusick sp = (struct scsi_xsense *)sdsense[unit].sense;
74941480Smckusick printf("sd%d: scsi sense class %d, code %d", unit,
75041480Smckusick sp->class, sp->code);
75141480Smckusick if (sp->class == 7) {
75241480Smckusick printf(", key %d", sp->key);
75341480Smckusick if (sp->valid)
75441480Smckusick printf(", blk %d", *(int *)&sp->info1);
75550039Skarels switch (sp->key) {
75650039Skarels /* no sense, try again */
75750039Skarels case 0:
75850039Skarels cond = -1;
75950039Skarels break;
76050039Skarels /* recovered error, not a problem */
76150039Skarels case 1:
76250039Skarels cond = 0;
76350039Skarels break;
76457327Shibler /* possible media change */
76557327Shibler case 6:
76657327Shibler /*
76757327Shibler * For removable media, if we are doing the
76857327Shibler * first open (i.e. reading the label) go
76957327Shibler * ahead and retry, otherwise someone has
77057327Shibler * changed the media out from under us and
77157327Shibler * we should abort any further operations
77257327Shibler * until a close is done.
77357327Shibler */
77457327Shibler if (sc->sc_flags & SDF_RMEDIA) {
77557327Shibler if (sc->sc_flags & SDF_OPENING)
77657327Shibler cond = -1;
77757327Shibler else
77857327Shibler sc->sc_flags |= SDF_ERROR;
77957327Shibler }
78057327Shibler break;
78150039Skarels }
78241480Smckusick }
78341480Smckusick printf("\n");
78441480Smckusick }
78550039Skarels return(cond);
78641480Smckusick }
78741480Smckusick
78841480Smckusick static void
sdfinish(unit,sc,bp)78941480Smckusick sdfinish(unit, sc, bp)
79041480Smckusick int unit;
79141480Smckusick register struct sd_softc *sc;
79241480Smckusick register struct buf *bp;
79341480Smckusick {
79453929Shibler register struct buf *dp = &sdtab[unit];
79553929Shibler
79653929Shibler dp->b_errcnt = 0;
79753929Shibler dp->b_actf = bp->b_actf;
79841480Smckusick bp->b_resid = 0;
79945750Smckusick biodone(bp);
80041480Smckusick scsifree(&sc->sc_dq);
80153929Shibler if (dp->b_actf)
80241480Smckusick sdustart(unit);
80353929Shibler else {
80453929Shibler dp->b_active = 0;
80553929Shibler if (sc->sc_flags & SDF_WANTED) {
80653929Shibler sc->sc_flags &= ~SDF_WANTED;
80753929Shibler wakeup((caddr_t)dp);
80853929Shibler }
80953929Shibler }
81041480Smckusick }
81141480Smckusick
81241480Smckusick void
sdstart(unit)81341480Smckusick sdstart(unit)
81441480Smckusick register int unit;
81541480Smckusick {
81641480Smckusick register struct sd_softc *sc = &sd_softc[unit];
81741480Smckusick register struct hp_device *hp = sc->sc_hd;
81841480Smckusick
81941480Smckusick /*
82041480Smckusick * we have the SCSI bus -- in format mode, we may or may not need dma
82141480Smckusick * so check now.
82241480Smckusick */
82366072Shibler if (sc->sc_format_pid >= 0 && legal_cmds[sdcmd[unit].cdb[0]] > 0) {
82441480Smckusick register struct buf *bp = sdtab[unit].b_actf;
82541480Smckusick register int sts;
82641480Smckusick
82765662Shibler sdtab[unit].b_errcnt = 0;
82865662Shibler while (1) {
82965662Shibler sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave,
83065662Shibler sc->sc_punit, &sdcmd[unit],
83165662Shibler bp->b_un.b_addr, bp->b_bcount,
83265662Shibler bp->b_flags & B_READ);
83365662Shibler sdsense[unit].status = sts;
83465662Shibler if ((sts & 0xfe) == 0 ||
83565662Shibler (sts = sderror(unit, sc, hp, sts)) == 0)
83665662Shibler break;
83765662Shibler if (sts > 0 || sdtab[unit].b_errcnt++ >= SDRETRY) {
83865662Shibler bp->b_flags |= B_ERROR;
83965662Shibler bp->b_error = EIO;
84065662Shibler break;
84165662Shibler }
84241480Smckusick }
84341480Smckusick sdfinish(unit, sc, bp);
84441480Smckusick
84541480Smckusick } else if (scsiustart(hp->hp_ctlr))
84641480Smckusick sdgo(unit);
84741480Smckusick }
84841480Smckusick
84941480Smckusick void
sdgo(unit)85041480Smckusick sdgo(unit)
85141480Smckusick register int unit;
85241480Smckusick {
85341480Smckusick register struct sd_softc *sc = &sd_softc[unit];
85441480Smckusick register struct hp_device *hp = sc->sc_hd;
85541480Smckusick register struct buf *bp = sdtab[unit].b_actf;
85641480Smckusick register int pad;
85741480Smckusick register struct scsi_fmt_cdb *cmd;
85841480Smckusick
85966072Shibler if (sc->sc_format_pid >= 0) {
86041480Smckusick cmd = &sdcmd[unit];
86141480Smckusick pad = 0;
86241480Smckusick } else {
86365662Shibler /*
86465662Shibler * Drive is in an error state, abort all operations
86565662Shibler */
86665662Shibler if (sc->sc_flags & SDF_ERROR) {
86765662Shibler bp->b_flags |= B_ERROR;
86865662Shibler bp->b_error = EIO;
86965662Shibler sdfinish(unit, sc, bp);
87065662Shibler return;
87165662Shibler }
87241480Smckusick cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd;
87341480Smckusick *(int *)(&cmd->cdb[2]) = bp->b_cylin;
87441480Smckusick pad = howmany(bp->b_bcount, sc->sc_blksize);
87541480Smckusick *(u_short *)(&cmd->cdb[7]) = pad;
87641480Smckusick pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0;
87741480Smckusick #ifdef DEBUG
87841480Smckusick if (pad)
87941480Smckusick printf("sd%d: partial block xfer -- %x bytes\n",
88041480Smckusick unit, bp->b_bcount);
88141480Smckusick #endif
88241480Smckusick sdstats[unit].sdtransfers++;
88341480Smckusick }
88457327Shibler #ifdef USELEDS
88557327Shibler if (inledcontrol == 0)
88657327Shibler ledcontrol(0, 0, LED_DISK);
88757327Shibler #endif
88841480Smckusick if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) {
88941480Smckusick if (hp->hp_dk >= 0) {
89041480Smckusick dk_busy |= 1 << hp->hp_dk;
89141480Smckusick ++dk_seek[hp->hp_dk];
89241480Smckusick ++dk_xfer[hp->hp_dk];
89341480Smckusick dk_wds[hp->hp_dk] += bp->b_bcount >> 6;
89441480Smckusick }
89541480Smckusick return;
89641480Smckusick }
89741480Smckusick #ifdef DEBUG
89841480Smckusick if (sddebug & SDB_ERROR)
89941480Smckusick printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n",
90041480Smckusick unit, bp->b_flags & B_READ? "read" : "write",
90141480Smckusick bp->b_un.b_addr, bp->b_cylin, bp->b_bcount,
90241480Smckusick sdtab[unit].b_errcnt);
90341480Smckusick #endif
90441480Smckusick bp->b_flags |= B_ERROR;
90541480Smckusick bp->b_error = EIO;
90641480Smckusick sdfinish(unit, sc, bp);
90741480Smckusick }
90841480Smckusick
90941480Smckusick void
sdintr(unit,stat)91041480Smckusick sdintr(unit, stat)
91141480Smckusick register int unit;
91241480Smckusick int stat;
91341480Smckusick {
91441480Smckusick register struct sd_softc *sc = &sd_softc[unit];
91541480Smckusick register struct buf *bp = sdtab[unit].b_actf;
91641480Smckusick register struct hp_device *hp = sc->sc_hd;
91750039Skarels int cond;
91841480Smckusick
91941480Smckusick if (bp == NULL) {
92041480Smckusick printf("sd%d: bp == NULL\n", unit);
92141480Smckusick return;
92241480Smckusick }
92341480Smckusick if (hp->hp_dk >= 0)
92441480Smckusick dk_busy &=~ (1 << hp->hp_dk);
92541480Smckusick if (stat) {
92641480Smckusick #ifdef DEBUG
92741480Smckusick if (sddebug & SDB_ERROR)
92841480Smckusick printf("sd%d: sdintr: bad scsi status 0x%x\n",
92941480Smckusick unit, stat);
93041480Smckusick #endif
93150039Skarels cond = sderror(unit, sc, hp, stat);
93250039Skarels if (cond) {
93350039Skarels if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) {
93450038Skarels #ifdef DEBUG
93550039Skarels if (sddebug & SDB_ERROR)
93650039Skarels printf("sd%d: retry #%d\n",
93750039Skarels unit, sdtab[unit].b_errcnt);
93850038Skarels #endif
93950039Skarels sdstart(unit);
94050039Skarels return;
94150039Skarels }
94250039Skarels bp->b_flags |= B_ERROR;
94350039Skarels bp->b_error = EIO;
94445750Smckusick }
94541480Smckusick }
94641480Smckusick sdfinish(unit, sc, bp);
94741480Smckusick }
94841480Smckusick
94941480Smckusick int
sdread(dev,uio,flags)95049132Skarels sdread(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
95866072Shibler if ((pid = sd_softc[unit].sc_format_pid) >= 0 &&
95949132Skarels pid != uio->uio_procp->p_pid)
96041480Smckusick return (EPERM);
96141480Smckusick
96249132Skarels return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio));
96341480Smckusick }
96441480Smckusick
96541480Smckusick int
sdwrite(dev,uio,flags)96649132Skarels sdwrite(dev, uio, flags)
96741480Smckusick dev_t dev;
96841480Smckusick struct uio *uio;
96949132Skarels int flags;
97041480Smckusick {
97141480Smckusick register int unit = sdunit(dev);
97241480Smckusick register int pid;
97341480Smckusick
97466072Shibler if ((pid = sd_softc[unit].sc_format_pid) >= 0 &&
97549132Skarels pid != uio->uio_procp->p_pid)
97641480Smckusick return (EPERM);
97741480Smckusick
97849132Skarels return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio));
97941480Smckusick }
98041480Smckusick
98141480Smckusick int
sdioctl(dev,cmd,data,flag,p)98249132Skarels sdioctl(dev, cmd, data, flag, p)
98341480Smckusick dev_t dev;
98468179Scgd u_long cmd;
98541480Smckusick caddr_t data;
98641480Smckusick int flag;
98749132Skarels struct proc *p;
98841480Smckusick {
98957327Shibler int unit = sdunit(dev);
99041480Smckusick register struct sd_softc *sc = &sd_softc[unit];
99157327Shibler register struct disklabel *lp = &sc->sc_info.si_label;
99257327Shibler int error, flags;
99341480Smckusick
99441480Smckusick switch (cmd) {
99541480Smckusick default:
99641480Smckusick return (EINVAL);
99741480Smckusick
99857327Shibler case DIOCGDINFO:
99957327Shibler *(struct disklabel *)data = *lp;
100057327Shibler return (0);
100157327Shibler
100257327Shibler case DIOCGPART:
100357327Shibler ((struct partinfo *)data)->disklab = lp;
100457327Shibler ((struct partinfo *)data)->part =
100557327Shibler &lp->d_partitions[sdpart(dev)];
100657327Shibler return (0);
100757327Shibler
100857327Shibler case DIOCWLABEL:
100957327Shibler if ((flag & FWRITE) == 0)
101057327Shibler return (EBADF);
101157327Shibler if (*(int *)data)
101257327Shibler sc->sc_flags |= SDF_WLABEL;
101357327Shibler else
101457327Shibler sc->sc_flags &= ~SDF_WLABEL;
101557327Shibler return (0);
101657327Shibler
101757327Shibler case DIOCSDINFO:
101857327Shibler if ((flag & FWRITE) == 0)
101957327Shibler return (EBADF);
102057327Shibler error = setdisklabel(lp, (struct disklabel *)data,
102157327Shibler (sc->sc_flags & SDF_WLABEL) ? 0
102257327Shibler : sc->sc_info.si_open);
102357327Shibler return (error);
102457327Shibler
102557327Shibler case DIOCWDINFO:
102657327Shibler if ((flag & FWRITE) == 0)
102757327Shibler return (EBADF);
102857327Shibler error = setdisklabel(lp, (struct disklabel *)data,
102957327Shibler (sc->sc_flags & SDF_WLABEL) ? 0
103057327Shibler : sc->sc_info.si_open);
103157327Shibler if (error)
103257327Shibler return (error);
103357327Shibler flags = sc->sc_flags;
103457327Shibler sc->sc_flags = SDF_ALIVE | SDF_WLABEL;
103557327Shibler error = writedisklabel(sdlabdev(dev), sdstrategy, lp);
103657327Shibler sc->sc_flags = flags;
103757327Shibler return (error);
103857327Shibler
103941480Smckusick case SDIOCSFORMAT:
104041480Smckusick /* take this device into or out of "format" mode */
104149132Skarels if (suser(p->p_ucred, &p->p_acflag))
104241480Smckusick return(EPERM);
104341480Smckusick
104441480Smckusick if (*(int *)data) {
104566072Shibler if (sc->sc_format_pid >= 0)
104641480Smckusick return (EPERM);
104749132Skarels sc->sc_format_pid = p->p_pid;
104841480Smckusick } else
104966072Shibler sc->sc_format_pid = -1;
105041480Smckusick return (0);
105141480Smckusick
105241480Smckusick case SDIOCGFORMAT:
105341480Smckusick /* find out who has the device in format mode */
105441480Smckusick *(int *)data = sc->sc_format_pid;
105541480Smckusick return (0);
105641480Smckusick
105741480Smckusick case SDIOCSCSICOMMAND:
105841480Smckusick /*
105941480Smckusick * Save what user gave us as SCSI cdb to use with next
106041480Smckusick * read or write to the char device.
106141480Smckusick */
106249132Skarels if (sc->sc_format_pid != p->p_pid)
106341480Smckusick return (EPERM);
106441480Smckusick if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0)
106541480Smckusick return (EINVAL);
106641480Smckusick bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0]));
106741480Smckusick return (0);
106841480Smckusick
106941480Smckusick case SDIOCSENSE:
107041480Smckusick /*
107141480Smckusick * return the SCSI sense data saved after the last
107241480Smckusick * operation that completed with "check condition" status.
107341480Smckusick */
107441480Smckusick bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0]));
107541480Smckusick return (0);
107641480Smckusick
107741480Smckusick }
107841480Smckusick /*NOTREACHED*/
107941480Smckusick }
108041480Smckusick
108141480Smckusick int
sdsize(dev)108241480Smckusick sdsize(dev)
108341480Smckusick dev_t dev;
108441480Smckusick {
108541480Smckusick register int unit = sdunit(dev);
108641480Smckusick register struct sd_softc *sc = &sd_softc[unit];
108757327Shibler int psize, didopen = 0;
108841480Smckusick
108941480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
109041480Smckusick return(-1);
109141480Smckusick
109257327Shibler /*
109357327Shibler * We get called very early on (via swapconf)
109457327Shibler * without the device being open so we may need
109557327Shibler * to handle it here.
109657327Shibler */
109757327Shibler if (sc->sc_info.si_open == 0) {
109857327Shibler if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL))
109957327Shibler return(-1);
110057327Shibler didopen = 1;
110157327Shibler }
110257327Shibler psize = sc->sc_info.si_label.d_partitions[sdpart(dev)].p_size;
110357327Shibler if (didopen)
110457327Shibler (void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL);
110557327Shibler return (psize);
110641480Smckusick }
110741480Smckusick
110841480Smckusick /*
110941480Smckusick * Non-interrupt driven, non-dma dump routine.
111041480Smckusick */
111141480Smckusick int
sddump(dev)111241480Smckusick sddump(dev)
111341480Smckusick dev_t dev;
111441480Smckusick {
111541480Smckusick int part = sdpart(dev);
111641480Smckusick int unit = sdunit(dev);
111741480Smckusick register struct sd_softc *sc = &sd_softc[unit];
111841480Smckusick register struct hp_device *hp = sc->sc_hd;
111957327Shibler register struct partition *pinfo;
112041480Smckusick register daddr_t baddr;
112141480Smckusick register int maddr;
112241480Smckusick register int pages, i;
112341480Smckusick int stat;
112466072Shibler extern int lowram, dumpsize;
112541480Smckusick
112641480Smckusick /* is drive ok? */
112741480Smckusick if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
112841480Smckusick return (ENXIO);
112957327Shibler pinfo = &sc->sc_info.si_label.d_partitions[part];
113041480Smckusick /* dump parameters in range? */
113157327Shibler if (dumplo < 0 || dumplo >= pinfo->p_size ||
113257327Shibler pinfo->p_fstype != FS_SWAP)
113341480Smckusick return (EINVAL);
113466072Shibler pages = dumpsize;
113557327Shibler if (dumplo + ctod(pages) > pinfo->p_size)
113657327Shibler pages = dtoc(pinfo->p_size - dumplo);
113741480Smckusick maddr = lowram;
113857327Shibler baddr = dumplo + pinfo->p_offset;
113941480Smckusick /* scsi bus idle? */
114041480Smckusick if (!scsireq(&sc->sc_dq)) {
114141480Smckusick scsireset(hp->hp_ctlr);
114241480Smckusick sdreset(sc, sc->sc_hd);
114341480Smckusick printf("[ drive %d reset ] ", unit);
114441480Smckusick }
114541480Smckusick for (i = 0; i < pages; i++) {
114641480Smckusick #define NPGMB (1024*1024/NBPG)
114741480Smckusick /* print out how many Mbs we have dumped */
114841480Smckusick if (i && (i % NPGMB) == 0)
114941480Smckusick printf("%d ", i / NPGMB);
115041480Smckusick #undef NPBMG
115152614Smckusick pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr,
115251576Smckusick VM_PROT_READ, TRUE);
115341480Smckusick stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit,
115441480Smckusick vmmap, NBPG, baddr, sc->sc_bshift);
115541480Smckusick if (stat) {
115641480Smckusick printf("sddump: scsi write error 0x%x\n", stat);
115741480Smckusick return (EIO);
115841480Smckusick }
115941480Smckusick maddr += NBPG;
116041480Smckusick baddr += ctod(1);
116141480Smckusick }
116241480Smckusick return (0);
116341480Smckusick }
116441480Smckusick #endif
1165