summaryrefslogtreecommitdiffstats
path: root/sys/scsi/sd.c
diff options
context:
space:
mode:
authordufault <dufault@FreeBSD.org>1995-03-01 22:24:47 +0000
committerdufault <dufault@FreeBSD.org>1995-03-01 22:24:47 +0000
commitc022092526531e80e9b53415fd187a53dff3bade (patch)
tree8158f942cd0116a4705af957aa3471bb2b19d72f /sys/scsi/sd.c
parentbeac11b74f9d02eab450b4902b573368f816e565 (diff)
downloadFreeBSD-src-c022092526531e80e9b53415fd187a53dff3bade.zip
FreeBSD-src-c022092526531e80e9b53415fd187a53dff3bade.tar.gz
Reviewed by: gibbs@freefall.cdrom.com julian@freefall.cdrom.com
1. Support for fixed device configuration 2. Hoisted common code to scsi_driver 3. SCSI busses dynamically allocated at boot 4. Reorg'd for LKMs
Diffstat (limited to 'sys/scsi/sd.c')
-rw-r--r--sys/scsi/sd.c293
1 files changed, 104 insertions, 189 deletions
diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c
index 584b3f2..0a37774 100644
--- a/sys/scsi/sd.c
+++ b/sys/scsi/sd.c
@@ -14,7 +14,7 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992
*
- * $Id: sd.c,v 1.49 1995/01/08 13:38:34 dufault Exp $
+ * $Id: sd.c,v 1.50 1995/01/31 11:41:46 dufault Exp $
*/
#define SPLSD splbio
@@ -43,46 +43,27 @@
u_int32 sdstrats, sdqueues;
-#define PAGESIZ 4096
#define SECSIZE 512
-#define PDLOCATION 29
-#define BOOTRECORDSIGNATURE (0x55aa & 0x00ff)
#define SDOUTSTANDING 2
-#define SDQSIZE 4
#define SD_RETRIES 4
#define MAXTRANSFER 8 /* 1 page at a time */
-
#define MAKESDDEV(maj, unit, part) (makedev(maj,((unit<<SDUNITSHIFT)+part)))
#define PARTITION(z) (minor(z) & 0x07)
-#define WHOLE_DISK(unit) ( (unit << SDUNITSHIFT) + RAWPART )
-
errval sdgetdisklabel __P((unsigned char unit));
errval sd_get_parms __P((int unit, int flags));
-void sdstrategy __P((struct buf *));
-void sdstart __P((u_int32));
+void sdstrategy __P((struct buf *bp));
-int sd_sense_handler __P((struct scsi_xfer *));
-
-struct scsi_device sd_switch =
-{
- sd_sense_handler,
- sdstart, /* have a queue, served by this */
- NULL, /* have no async handler */
- NULL, /* Use default 'done' routine */
- "sd",
- 0,
- { 0, 0 }
-};
+int sd_sense_handler __P((struct scsi_xfer *));
+void sdstart __P((u_int32));
-struct sd_data {
+struct scsi_data {
u_int32 flags;
#define SDINIT 0x04 /* device has been init'd */
#define SDHAVELABEL 0x10 /* have read the label */
#define SDDOSPART 0x20 /* Have read the DOS partition table */
#define SDWRITEPROT 0x40 /* Device in readonly mode (S/W) */
- struct scsi_link *sc_link; /* contains our targ, lun etc. */
u_int32 ad_info; /* info about the adapter */
u_int32 cmdscount; /* cmds allowed outstanding by board */
boolean wlabel; /* label is writable */
@@ -108,35 +89,53 @@ struct sd_data {
int dkunit; /* disk stats unit number */
};
-struct sd_driver {
- u_int32 size;
- struct sd_data **sd_data;
-} sd_driver;
+static int sdunit(dev_t dev) { return SDUNIT(dev); }
+static dev_t sdsetunit(dev_t dev, int unit) { return SDSETUNIT(dev, unit); }
-static u_int32 next_sd_unit = 0;
+errval sd_open(dev_t dev, int flags, struct scsi_link *sc_link);
+errval sd_ioctl(dev_t dev, int cmd, caddr_t addr, int flag,
+ struct scsi_link *sc_link);
+errval sd_close(dev_t dev, struct scsi_link *sc_link);
+void sd_strategy(struct buf *bp, struct scsi_link *sc_link);
-static struct scsi_xfer sx;
+SCSI_DEVICE_ENTRIES(sd)
-static int
-sd_goaway(struct kern_devconf *kdc, int force) /* XXX should do a lot more */
+struct scsi_device sd_switch =
{
- dev_detach(kdc);
- FREE(kdc, M_TEMP);
- return 0;
-}
+ sd_sense_handler,
+ sdstart, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "sd",
+ 0,
+ {0, 0},
+ 0, /* Link flags */
+ sdattach,
+ sdopen,
+ sizeof(struct scsi_data),
+ T_DIRECT,
+ sdunit,
+ sdsetunit,
+ sd_open,
+ sd_ioctl,
+ sd_close,
+ sd_strategy,
+};
+
+static struct scsi_xfer sx;
static int
sd_externalize(struct proc *p, struct kern_devconf *kdc, void *userp,
size_t len)
{
- return scsi_externalize(sd_driver.sd_data[kdc->kdc_unit]->sc_link,
+ return scsi_externalize(SCSI_LINK(&sd_switch, kdc->kdc_unit),
userp, &len);
}
static struct kern_devconf kdc_sd_template = {
0, 0, 0, /* filled in by dev_attach */
"sd", 0, MDDC_SCSI,
- sd_externalize, 0, sd_goaway, SCSI_EXTERNALLEN,
+ sd_externalize, 0, scsi_goaway, SCSI_EXTERNALLEN,
&kdc_scbus0, /* XXX parent */
0, /* parentdata */
DC_UNKNOWN, /* not supported */
@@ -156,87 +155,31 @@ sd_registerdev(int unit)
if(dk_ndrive < DK_NDRIVE) {
sprintf(dk_names[dk_ndrive], "sd%d", unit);
dk_wpms[dk_ndrive] = (8*1024*1024/2);
- sd_driver.sd_data[unit]->dkunit = dk_ndrive++;
+ SCSI_DATA(&sd_switch, unit)->dkunit = dk_ndrive++;
} else {
- sd_driver.sd_data[unit]->dkunit = -1;
+ SCSI_DATA(&sd_switch, unit)->dkunit = -1;
}
}
-errval sdopen();
-
/*
* The routine called by the low level scsi routine when it discovers
* a device suitable for this driver.
*/
errval
-sdattach(sc_link)
- struct scsi_link *sc_link;
+sdattach(struct scsi_link *sc_link)
{
u_int32 unit;
- struct sd_data *sd, **sdrealloc;
struct disk_parms *dp;
- SC_DEBUG(sc_link, SDEV_DB2, ("sdattach: "));
+ struct scsi_data *sd = sc_link->sd;
- /*
- * allocate the resources for another drive
- * if we have already allocate a sd_data pointer we must
- * copy the old pointers into a new region that is
- * larger and release the old region, aka realloc
- */
- /* XXX
- * This if will always be true for now, but future code may
- * preallocate more units to reduce overhead. This would be
- * done by changing the malloc to be (next_sd_unit * x) and
- * the sd_driver.size++ to be +x
- */
- unit = next_sd_unit++;
- if (unit >= sd_driver.size) {
- sdrealloc =
- malloc(sizeof(sd_driver.sd_data) * next_sd_unit,
- M_DEVBUF, M_NOWAIT);
- if (!sdrealloc) {
- printf("sd%ld: malloc failed for sdrealloc\n", unit);
- return (0);
- }
- /* Make sure we have something to copy before we copy it */
- bzero(sdrealloc, sizeof(sd_driver.sd_data) * next_sd_unit);
- if (sd_driver.size) {
- bcopy(sd_driver.sd_data, sdrealloc,
- sizeof(sd_driver.sd_data) * sd_driver.size);
- free(sd_driver.sd_data, M_DEVBUF);
- }
- sd_driver.sd_data = sdrealloc;
- sd_driver.sd_data[unit] = NULL;
- sd_driver.size++;
- }
- if (sd_driver.sd_data[unit]) {
- printf("sd%ld: Already has storage!\n", unit);
- return (0);
- }
- /*
- * alloate the per drive data area
- */
- sd = sd_driver.sd_data[unit] =
- malloc(sizeof(struct sd_data), M_DEVBUF, M_NOWAIT);
- if (!sd) {
- printf("sd%ld: malloc failed for sd_data\n", unit);
- return (0);
- }
- bzero(sd, sizeof(struct sd_data));
+ unit = sc_link->dev_unit;
dp = &(sd->params);
- /*
- * Store information needed to contact our base driver
- */
- sd->sc_link = sc_link;
- sc_link->device = &sd_switch;
- sc_link->dev_unit = unit;
- sc_link->dev = SDSETUNIT(scsi_dev_lookup(sdopen), unit);
- if (sd->sc_link->adapter->adapter_info) {
- sd->ad_info = ((*(sd->sc_link->adapter->adapter_info)) (sc_link->adapter_unit));
+ if (sc_link->adapter->adapter_info) {
+ sd->ad_info = ((*(sc_link->adapter->adapter_info)) (sc_link->adapter_unit));
sd->cmdscount = sd->ad_info & AD_INF_MAX_CMDS;
if (sd->cmdscount > SDOUTSTANDING) {
sd->cmdscount = SDOUTSTANDING;
@@ -258,8 +201,7 @@ sdattach(sc_link)
* -- this avoids the division below from falling over
*/
if(dp->secsiz == 0) dp->secsiz = 512;
- printf("sd%ld: %ldMB (%ld total sec), %d cyl, %d head, %d sec, bytes/sec %d\n",
- unit,
+ printf("%ldMB (%ld total sec), %d cyl, %d head, %d sec, bytes/sec %d\n",
dp->disksize / ((1024L * 1024L) / dp->secsiz),
dp->disksize,
dp->cyls,
@@ -268,30 +210,24 @@ sdattach(sc_link)
dp->secsiz);
sd->flags |= SDINIT;
sd_registerdev(unit);
- return (1);
+
+ return 0;
}
/*
* open the device. Make sure the partition info is a up-to-date as can be.
*/
errval
-sdopen(dev)
- int dev; /* XXX should be dev_t, but avoid promotion problems for now */
+sd_open(dev_t dev, int flags, struct scsi_link *sc_link)
{
errval errcode = 0;
u_int32 unit, part;
- struct sd_data *sd;
- struct scsi_link *sc_link;
+ struct scsi_data *sd;
unit = SDUNIT(dev);
part = PARTITION(dev);
- /*
- * Check the unit is legal
- */
- if (unit >= sd_driver.size) {
- return (ENXIO);
- }
- sd = sd_driver.sd_data[unit];
+ sd = sc_link->sd;
+
/*
* Make sure the disk has been initialised
* At some point in the future, get the scsi driver
@@ -300,11 +236,10 @@ sdopen(dev)
if ((!sd) || (!(sd->flags & SDINIT))) {
return (ENXIO);
}
- sc_link = sd->sc_link;
SC_DEBUG(sc_link, SDEV_DB1,
- ("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n",
- dev, unit, sd_driver.size, part));
+ ("sdopen: dev=0x%x (unit %d, partition %d)\n",
+ dev, unit, part));
/*
* "unit attention" errors should occur here if the
@@ -323,7 +258,7 @@ sdopen(dev)
sd->flags &= ~SDHAVELABEL;
/*
- * If somebody still has it open, then forbid re-entry.
+ * If somebody still has it open, then forbid re-entry.
*/
if (sd->openparts) {
errcode = ENXIO;
@@ -405,62 +340,42 @@ bad:
* device. Convenient now but usually a pain.
*/
errval
-sdclose(dev)
- dev_t dev;
+sd_close(dev_t dev, struct scsi_link *sc_link)
{
unsigned char unit, part;
- struct sd_data *sd;
+ struct scsi_data *sd;
unit = SDUNIT(dev);
part = PARTITION(dev);
- sd = sd_driver.sd_data[unit];
+ sd = sc_link->sd;
sd->partflags[part] &= ~SDOPEN;
sd->openparts &= ~(1 << part);
- scsi_prevent(sd->sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK);
+ scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK);
if (!(sd->openparts))
- sd->sc_link->flags &= ~SDEV_OPEN;
+ sc_link->flags &= ~SDEV_OPEN;
return 0;
}
/*
- * trim the size of the transfer if needed, called by physio
- * basically the smaller of our max and the scsi driver's
- * minphys (note we have no max)
- *
- * Trim buffer length if buffer-size is bigger than page size
- */
-void
-sdminphys(bp)
- struct buf *bp;
-{
- (*(sd_driver.sd_data[SDUNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp);
-}
-
-/*
* Actually translate the requested transfer into one the physical driver
* can understand. The transfer is described by a buf and will include
* only one physical transfer.
*/
void
-sdstrategy(bp)
- struct buf *bp;
+sd_strategy(struct buf *bp, struct scsi_link *sc_link)
{
struct buf *dp;
u_int32 opri;
- struct sd_data *sd;
+ struct scsi_data *sd;
u_int32 unit;
sdstrats++;
unit = SDUNIT((bp->b_dev));
- sd = sd_driver.sd_data[unit];
- SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdstrategy "));
- SC_DEBUG(sd->sc_link, SDEV_DB1,
- (" %d bytes @ blk%d\n", bp->b_bcount, bp->b_blkno));
- sdminphys(bp);
+ sd = sc_link->sd;
/*
* If the device has been made invalid, error out
*/
- if (!(sd->sc_link->flags & SDEV_MEDIA_LOADED)) {
+ if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
sd->flags &= ~SDHAVELABEL;
bp->b_error = EIO;
goto bad;
@@ -512,7 +427,7 @@ sdstrategy(bp)
* Use a bounce buffer if necessary
*/
#ifdef BOUNCE_BUFFERS
- if (sd->sc_link->flags & SDEV_BOUNCE)
+ if (sc_link->flags & SDEV_BOUNCE)
vm_bounce_alloc(bp);
#endif
@@ -566,11 +481,10 @@ done:
* sdstart() is called at SPLSD from sdstrategy and scsi_done
*/
void
-sdstart(unit)
- u_int32 unit;
+sdstart(u_int32 unit)
{
- register struct sd_data *sd = sd_driver.sd_data[unit];
- register struct scsi_link *sc_link = sd->sc_link;
+ register struct scsi_link *sc_link = SCSI_LINK(&sd_switch, unit);
+ register struct scsi_data *sd = sc_link->sd;
struct buf *bp = 0;
struct buf *dp;
struct scsi_rw_big cmd;
@@ -671,25 +585,26 @@ bad:
* Knows about the internals of this device
*/
errval
-sdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
+sd_ioctl(dev_t dev, int cmd, caddr_t addr, int flag,
+struct scsi_link *sc_link)
{
/* struct sd_cmd_buf *args; */
errval error = 0;
unsigned char unit, part;
- register struct sd_data *sd;
+ register struct scsi_data *sd;
/*
* Find the device that the user is talking about
*/
unit = SDUNIT(dev);
part = PARTITION(dev);
- sd = sd_driver.sd_data[unit];
- SC_DEBUG(sd->sc_link, SDEV_DB1, ("sdioctl (0x%x)", cmd));
+ sd = sc_link->sd;
+ SC_DEBUG(sc_link, SDEV_DB1, ("sdioctl (0x%x)", cmd));
/*
* If the device is not valid.. abandon ship
*/
- if (!(sd->sc_link->flags & SDEV_MEDIA_LOADED))
+ if (!(sc_link->flags & SDEV_MEDIA_LOADED))
return (EIO);
switch (cmd) {
@@ -778,7 +693,7 @@ sdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
default:
if (part == RAWPART || SCSI_SUPER(dev) )
- error = scsi_do_ioctl(dev, sd->sc_link, cmd, addr, flag);
+ error = scsi_do_ioctl(dev, cmd, addr, flag, sc_link);
else
error = ENOTTY;
break;
@@ -793,7 +708,7 @@ errval
sdgetdisklabel(unsigned char unit)
{
char *errstring;
- struct sd_data *sd = sd_driver.sd_data[unit];
+ struct scsi_data *sd = SCSI_DATA(&sd_switch, unit);
dev_t dev;
dev = makedev(0, (unit << SDUNITSHIFT) + RAWPART);
@@ -859,7 +774,7 @@ sd_size(unit, flags)
struct scsi_read_cap_data rdcap;
struct scsi_read_capacity scsi_cmd;
u_int32 size;
- struct sd_data *sd = sd_driver.sd_data[unit];
+ struct scsi_link *sc_link = SCSI_LINK(&sd_switch, unit);
/*
* make up a scsi command and ask the scsi driver to do
@@ -872,7 +787,7 @@ sd_size(unit, flags)
* If the command works, interpret the result as a 4 byte
* number of blocks
*/
- if (scsi_scsi_cmd(sd->sc_link,
+ if (scsi_scsi_cmd(sc_link,
(struct scsi_generic *) &scsi_cmd,
sizeof(scsi_cmd),
(u_char *) & rdcap,
@@ -901,7 +816,7 @@ sd_reassign_blocks(unit, block)
{
struct scsi_reassign_blocks scsi_cmd;
struct scsi_reassign_blocks_data rbdata;
- struct sd_data *sd = sd_driver.sd_data[unit];
+ struct scsi_link *sc_link = SCSI_LINK(&sd_switch, unit);
bzero(&scsi_cmd, sizeof(scsi_cmd));
bzero(&rbdata, sizeof(rbdata));
@@ -914,7 +829,7 @@ sd_reassign_blocks(unit, block)
rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff);
rbdata.defect_descriptor[0].dlbaddr_0 = ((block) & 0xff);
- return (scsi_scsi_cmd(sd->sc_link,
+ return (scsi_scsi_cmd(sc_link,
(struct scsi_generic *) &scsi_cmd,
sizeof(scsi_cmd),
(u_char *) & rbdata,
@@ -935,7 +850,8 @@ errval
sd_get_parms(unit, flags)
int unit, flags;
{
- struct sd_data *sd = sd_driver.sd_data[unit];
+ struct scsi_link *sc_link = SCSI_LINK(&sd_switch, unit);
+ struct scsi_data *sd = sc_link->sd;
struct disk_parms *disk_parms = &sd->params;
struct scsi_mode_sense scsi_cmd;
struct scsi_mode_sense_data {
@@ -948,7 +864,7 @@ sd_get_parms(unit, flags)
/*
* First check if we have it all loaded
*/
- if (sd->sc_link->flags & SDEV_MEDIA_LOADED)
+ if (sc_link->flags & SDEV_MEDIA_LOADED)
return 0;
/*
@@ -962,7 +878,7 @@ sd_get_parms(unit, flags)
* If the command worked, use the results to fill out
* the parameter structure
*/
- if (scsi_scsi_cmd(sd->sc_link,
+ if (scsi_scsi_cmd(sc_link,
(struct scsi_generic *) &scsi_cmd,
sizeof(scsi_cmd),
(u_char *) & scsi_sense,
@@ -987,7 +903,7 @@ sd_get_parms(unit, flags)
disk_parms->disksize = sectors;
} else {
- SC_DEBUG(sd->sc_link, SDEV_DB3,
+ SC_DEBUG(sc_link, SDEV_DB3,
("%d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n",
scsi_3btou(&scsi_sense.pages.rigid_geometry.ncyl_2),
scsi_sense.pages.rigid_geometry.nheads,
@@ -1022,7 +938,7 @@ sd_get_parms(unit, flags)
disk_parms->secsiz = SECSIZE;
disk_parms->sectors = sectors; /* dubious on SCSI *//*XXX */
}
- sd->sc_link->flags |= SDEV_MEDIA_LOADED;
+ sc_link->flags |= SDEV_MEDIA_LOADED;
return 0;
}
@@ -1030,18 +946,18 @@ int
sdsize(dev_t dev)
{
u_int32 unit = SDUNIT(dev), part = PARTITION(dev), val;
- struct sd_data *sd;
+ struct scsi_data *sd;
- if (unit >= sd_driver.size)
+ if ( (sd = SCSI_DATA(&sd_switch, unit)) == 0)
return -1;
- sd = sd_driver.sd_data[unit];
- if (!sd)
- return -1;
if ((sd->flags & SDINIT) == 0)
return -1;
if (sd == 0 || (sd->flags & SDHAVELABEL) == 0) {
- val = sdopen(MAKESDDEV(major(dev), unit, RAWPART), FREAD, S_IFBLK, 0);
+ /* XXX: By rights sdopen should be called like:
+ * sdopen(MAKESDDEV(major(dev), unit, RAWPART), FREAD, S_IFBLK, 0);
+ */
+ val = sdopen(MAKESDDEV(major(dev), unit, RAWPART), FREAD);
if (val != 0)
return -1;
}
@@ -1087,10 +1003,7 @@ int sd_sense_handler(struct scsi_xfer *xs)
if (inqbuf->dev_qual2 & SID_REMOVABLE)
return SCSIRET_CONTINUE;
- /* I have to retry HARDWARE ERROR for ASC 44 and ASCQ 0
- * so that the CDC-WREN IV will work during TCAL. In general,
- * I think we should just retry disk errors. Does anyone
- * have a good reason not to?
+ /* Retry all disk errors.
*/
scsi_sense_print(xs);
if (xs->retries)
@@ -1108,7 +1021,8 @@ int sd_sense_handler(struct scsi_xfer *xs)
errval
sddump(dev_t dev)
{ /* dump core after a system crash */
- register struct sd_data *sd; /* disk unit to do the IO */
+ register struct scsi_data *sd; /* disk unit to do the IO */
+ struct scsi_link *sc_link;
int32 num; /* number of sectors to write */
u_int32 unit, part;
int32 blkoff, blknum, blkcnt = MAXTRANSFER;
@@ -1133,17 +1047,18 @@ sddump(dev_t dev)
num = Maxmem;
unit = SDUNIT(dev); /* eventually support floppies? */
part = PARTITION(dev); /* file system */
- /* check for acceptable drive number */
- if (unit >= sd_driver.size)
- return (ENXIO);
- sd = sd_driver.sd_data[unit];
- if (!sd)
- return (ENXIO);
+ sc_link = SCSI_LINK(&sd_switch, unit);
+
+ if (!sc_link)
+ return ENXIO;
+
+ sd = sc_link->sd;
+
/* was it ever initialized etc. ? */
if (!(sd->flags & SDINIT))
return (ENXIO);
- if (sd->sc_link->flags & SDEV_MEDIA_LOADED != SDEV_MEDIA_LOADED)
+ if (sc_link->flags & SDEV_MEDIA_LOADED != SDEV_MEDIA_LOADED)
return (ENXIO);
if (sd->flags & SDWRITEPROT)
return (ENXIO);
@@ -1188,7 +1103,7 @@ sddump(dev_t dev)
*/
bzero(xs, sizeof(sx));
xs->flags |= SCSI_NOMASK | SCSI_NOSLEEP | INUSE | SCSI_DATA_OUT;
- xs->sc_link = sd->sc_link;
+ xs->sc_link = sc_link;
xs->retries = SD_RETRIES;
xs->timeout = 10000; /* 10000 millisecs for a disk ! */
xs->cmd = (struct scsi_generic *) &cmd;
@@ -1202,7 +1117,7 @@ sddump(dev_t dev)
/*
* Pass all this info to the scsi driver.
*/
- retval = (*(sd->sc_link->adapter->scsi_cmd)) (xs);
+ retval = (*(sc_link->adapter->scsi_cmd)) (xs);
switch (retval) {
case SUCCESSFULLY_QUEUED:
case HAD_ERROR:
OpenPOWER on IntegriCloud