diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2005-07-02 03:49:48 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2005-07-02 03:49:48 +0000 |
commit | 6d094a535ab6bae839f381222773c7e82b38b42c (patch) | |
tree | 5dc1c4ca8d45be2c66d796fad82ebd8301ed6c55 | |
parent | ac927458513e4538345afbe43f0635d62a8172f7 (diff) |
Don't use READ FORMAT CAPACITIES to determine the size of ATAPI sd
devices. Use READ CAPACITY like NetBSD, FreeBSD, Linux and OpenSolaris
do. Well, NetBSD keeps READ FORMAT CAPACITIES as a backup. Fixes
problems with devices (such as my IBM USB Memory Key) which return
block counts that are off by one for READ FORMAT CAPACITIES.
This eliminates the significant difference between sd_atapi.c and
sd_scsi.c so merge sd_scsi.c into sd.c and just be careful to mark
ATAPI removable devices as both SDEV_NOSYNCCACHE and unable to return
MODE SENSE page 4 info.
All geometry faking is now in one place. Where it can be 'improved'.
sd_scsi.c, sd_atapi.c and atapi_disk.h will be removed as a result.
-rw-r--r-- | sys/scsi/files.scsi | 4 | ||||
-rw-r--r-- | sys/scsi/sd.c | 168 | ||||
-rw-r--r-- | sys/scsi/sdvar.h | 10 |
3 files changed, 151 insertions, 31 deletions
diff --git a/sys/scsi/files.scsi b/sys/scsi/files.scsi index 7ef33423207..e0a1d4dbb17 100644 --- a/sys/scsi/files.scsi +++ b/sys/scsi/files.scsi @@ -1,4 +1,4 @@ -# $OpenBSD: files.scsi,v 1.15 2005/05/27 16:07:51 krw Exp $ +# $OpenBSD: files.scsi,v 1.16 2005/07/02 03:49:47 krw Exp $ # $NetBSD: files.scsi,v 1.4 1996/05/16 04:01:08 mycroft Exp $ # # Config.new file and device description for machine-independent SCSI code. @@ -23,8 +23,6 @@ file scsi/ch.c ch needs-flag device sd: disk attach sd at scsibus file scsi/sd.c sd needs-flag -file scsi/sd_atapi.c sd needs-flag -file scsi/sd_scsi.c sd needs-flag device ses: disk attach ses at scsibus diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index ddd0e38f43d..a6da5a1325c 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sd.c,v 1.77 2005/05/03 00:29:16 krw Exp $ */ +/* $OpenBSD: sd.c,v 1.78 2005/07/02 03:49:47 krw Exp $ */ /* $NetBSD: sd.c,v 1.111 1997/04/02 02:29:41 mycroft Exp $ */ /*- @@ -103,6 +103,8 @@ void sddone(struct scsi_xfer *); void sd_shutdown(void *); int sd_reassign_blocks(struct sd_softc *, u_long); int sd_interpret_sense(struct scsi_xfer *); +int sd_get_parms(struct sd_softc *, struct disk_parms *, int); +void sd_flush(struct sd_softc *, int); void viscpy(u_char *, u_char *, int); @@ -194,12 +196,8 @@ sdattach(parent, self, aux) dk_establish(&sd->sc_dk, &sd->sc_dev); - if (sc_link->flags & SDEV_ATAPI && - (sc_link->flags & SDEV_REMOVABLE)) { - sd->sc_ops = &sd_atapibus_ops; - } else { - sd->sc_ops = &sd_scsibus_ops; - } + if ((sc_link->flags & SDEV_ATAPI) && (sc_link->flags & SDEV_REMOVABLE)) + sc_link->quirks |= SDEV_NOSYNCCACHE; if (!(sc_link->inquiry_flags & SID_RelAdr)) sc_link->quirks |= SDEV_ONLYBIG; @@ -235,7 +233,7 @@ sdattach(parent, self, aux) if (error) result = SDGP_RESULT_OFFLINE; else - result = (*sd->sc_ops->sdo_get_parms)(sd, &sd->params, + result = sd_get_parms(sd, &sd->params, scsi_autoconf | SCSI_SILENT | SCSI_IGNORE_MEDIA_CHANGE); printf("%s: ", sd->sc_dev.dv_xname); @@ -250,10 +248,6 @@ sdattach(parent, self, aux) printf("drive offline"); break; - case SDGP_RESULT_UNFORMATTED: - printf("unformatted media"); - break; - #ifdef DIAGNOSTIC default: panic("sdattach: unknown result from get_parms"); @@ -425,8 +419,7 @@ sdopen(dev, flag, fmt, p) } /* Load the physical device parameters. */ sc_link->flags |= SDEV_MEDIA_LOADED; - if ((*sd->sc_ops->sdo_get_parms)(sd, &sd->params, 0) == - SDGP_RESULT_OFFLINE) { + if (sd_get_parms(sd, &sd->params, 0) == SDGP_RESULT_OFFLINE) { sc_link->flags &= ~SDEV_MEDIA_LOADED; error = ENXIO; goto bad; @@ -506,9 +499,8 @@ sdclose(dev, flag, fmt, p) sd->sc_dk.dk_openmask = sd->sc_dk.dk_copenmask | sd->sc_dk.dk_bopenmask; if (sd->sc_dk.dk_openmask == 0) { - if ((sd->flags & SDF_DIRTY) != 0 && - sd->sc_ops->sdo_flush != NULL) - (*sd->sc_ops->sdo_flush)(sd, 0); + if ((sd->flags & SDF_DIRTY) != 0) + sd_flush(sd, 0); if ((sd->sc_link->flags & SDEV_REMOVABLE) != 0) scsi_prevent(sd->sc_link, PR_ALLOW, @@ -1068,8 +1060,8 @@ sd_shutdown(arg) * it, flush it. We're cold at this point, so we poll for * completion. */ - if ((sd->flags & SDF_DIRTY) != 0 && sd->sc_ops->sdo_flush != NULL) - (*sd->sc_ops->sdo_flush)(sd, SCSI_AUTOCONF); + if ((sd->flags & SDF_DIRTY) != 0) + sd_flush(sd, SCSI_AUTOCONF); } /* @@ -1332,3 +1324,141 @@ viscpy(dst, src, len) } *dst = '\0'; } + +/* + * Fill out the disk parameter structure. Return SDGP_RESULT_OK if the + * structure is correctly filled in, SDGP_RESULT_OFFLINE otherwise. The caller + * is responsible for clearing the SDEV_MEDIA_LOADED flag if the structure + * cannot be completed. + */ +int +sd_get_parms(sd, dp, flags) + struct sd_softc *sd; + struct disk_parms *dp; + int flags; +{ + struct scsi_mode_sense_buf buf; + union scsi_disk_pages *sense_pages; + u_int32_t heads = 0, sectors = 0, cyls = 0, blksize; + u_int16_t rpm = 0; + + dp->disksize = scsi_size(sd->sc_link, flags, &blksize); + + switch (sd->type) { + case T_OPTICAL: + /* No more information needed or available. */ + break; + + case T_RDIRECT: + /* T_RDIRECT only supports RBC Device Parameter Page (6). */ + scsi_do_mode_sense(sd->sc_link, 6, &buf, (void **)&sense_pages, + NULL, NULL, &blksize, sizeof(sense_pages->reduced_geometry), + flags | SCSI_SILENT, NULL); + if (sense_pages) { + if (dp->disksize == 0) + dp->disksize = _5btol(sense_pages-> + reduced_geometry.sectors); + if (blksize == 0) + blksize = _2btol(sense_pages-> + reduced_geometry.bytes_s); + } + break; + + default: + sense_pages = NULL; + if (((sd->sc_link->flags & SDEV_ATAPI) == 0) || + ((sd->sc_link->flags & SDEV_REMOVABLE) == 0)) + /* Try mode sense page 4 (RIGID GEOMETRY). */ + scsi_do_mode_sense(sd->sc_link, 4, &buf, + (void **)&sense_pages, NULL, NULL, &blksize, + sizeof(sense_pages->rigid_geometry), + flags | SCSI_SILENT, NULL); + if (sense_pages) { + heads = sense_pages->rigid_geometry.nheads; + cyls = _3btol(sense_pages->rigid_geometry.ncyl); + rpm = _2btol(sense_pages->rigid_geometry.rpm); + if (heads * cyls > 0) + sectors = dp->disksize / (heads * cyls); + } else { + /* * Try page 5 (FLEX GEOMETRY). */ + scsi_do_mode_sense(sd->sc_link, 5, &buf, + (void **)&sense_pages, NULL, NULL, &blksize, + sizeof(sense_pages->flex_geometry), + flags | SCSI_SILENT, NULL); + if (sense_pages) { + sectors = sense_pages->flex_geometry.ph_sec_tr; + heads = sense_pages->flex_geometry.nheads; + cyls = _2btol(sense_pages->flex_geometry.ncyl); + rpm = _2btol(sense_pages->flex_geometry.rpm); + if (blksize == 0) + blksize = _2btol(sense_pages-> + flex_geometry.bytes_s); + if (dp->disksize == 0) + dp->disksize = heads * cyls * sectors; + } + } + break; + } + + if (dp->disksize == 0) + return (SDGP_RESULT_OFFLINE); + + /* + * Use Adaptec standard geometry values for anything we still don't + * know. + */ + + dp->heads = (heads == 0) ? 64 : heads; + dp->blksize = (blksize == 0) ? 512 : blksize; + dp->sectors = (sectors == 0) ? 32 : sectors; + dp->rot_rate = (rpm == 0) ? 3600 : rpm; + + /* + * XXX THINK ABOUT THIS!! Using values such that sectors * heads * + * cyls is <= disk_size can lead to wasted space. We need a more + * careful calculation/validation to make everything work out + * optimally. + */ + dp->cyls = (cyls == 0) ? dp->disksize / (dp->heads * dp->sectors) : + cyls; + + return (SDGP_RESULT_OK); +} + +void +sd_flush(sd, flags) + struct sd_softc *sd; + int flags; +{ + struct scsi_link *sc_link = sd->sc_link; + struct scsi_synchronize_cache sync_cmd; + + /* + * If the device is SCSI-2, issue a SYNCHRONIZE CACHE. + * We issue with address 0 length 0, which should be + * interpreted by the device as "all remaining blocks + * starting at address 0". We ignore ILLEGAL REQUEST + * in the event that the command is not supported by + * the device, and poll for completion so that we know + * that the cache has actually been flushed. + * + * Unless, that is, the device can't handle the SYNCHRONIZE CACHE + * command, as indicated by our quirks flags. + * + * XXX What about older devices? + */ + if ((sc_link->scsi_version & SID_ANSII) >= 2 && + (sc_link->quirks & SDEV_NOSYNCCACHE) == 0) { + bzero(&sync_cmd, sizeof(sync_cmd)); + sync_cmd.opcode = SYNCHRONIZE_CACHE; + + if (scsi_scsi_cmd(sc_link, + (struct scsi_generic *)&sync_cmd, sizeof(sync_cmd), + NULL, 0, SDRETRIES, 100000, NULL, + flags|SCSI_IGNORE_ILLEGAL_REQUEST)) + printf("%s: WARNING: cache synchronization failed\n", + sd->sc_dev.dv_xname); + else + sd->flags |= SDF_FLUSHING; + } +} diff --git a/sys/scsi/sdvar.h b/sys/scsi/sdvar.h index d6270f72303..81f9cca4acc 100644 --- a/sys/scsi/sdvar.h +++ b/sys/scsi/sdvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdvar.h,v 1.4 2003/05/17 16:28:05 krw Exp $ */ +/* $OpenBSD: sdvar.h,v 1.5 2005/07/02 03:49:47 krw Exp $ */ /* $NetBSD: sdvar.h,v 1.7 1998/08/17 00:49:03 mycroft Exp $ */ /*- @@ -86,8 +86,6 @@ struct sd_softc { char product[17]; /* disk product model */ char revision[5]; /* drive/firmware revision */ } name; - const struct sd_ops *sc_ops; /* our bus-dependent ops vector */ - void *sc_sdhook; /* our shutdown hook */ #if NRND > 0 @@ -95,12 +93,6 @@ struct sd_softc { #endif }; -struct sd_ops { - int (*sdo_get_parms)(struct sd_softc *, struct disk_parms *, - int); - void (*sdo_flush)(struct sd_softc *, int); -}; #define SDGP_RESULT_OK 0 /* parameters obtained */ #define SDGP_RESULT_OFFLINE 1 /* no media, or otherwise losing */ -#define SDGP_RESULT_UNFORMATTED 2 /* unformatted media (max params) */ |