diff options
Diffstat (limited to 'sys/scsi')
-rw-r--r-- | sys/scsi/sd.c | 127 | ||||
-rw-r--r-- | sys/scsi/sdvar.h | 3 |
2 files changed, 122 insertions, 8 deletions
diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index 59379bd9da8..430c4d84c9d 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sd.c,v 1.233 2011/07/06 04:49:36 matthew Exp $ */ +/* $OpenBSD: sd.c,v 1.234 2011/07/11 00:22:15 dlg Exp $ */ /* $NetBSD: sd.c,v 1.111 1997/04/02 02:29:41 mycroft Exp $ */ /*- @@ -88,6 +88,9 @@ int sdgetdisklabel(dev_t, struct sd_softc *, struct disklabel *, int); void sdstart(struct scsi_xfer *); void sd_shutdown(void *); int sd_interpret_sense(struct scsi_xfer *); +int sd_read_cap_10(struct sd_softc *, int); +int sd_read_cap_16(struct sd_softc *, int); +int sd_size(struct sd_softc *, int); int sd_get_parms(struct sd_softc *, struct disk_parms *, int); void sd_flush(struct sd_softc *, int); @@ -222,10 +225,13 @@ sdattach(struct device *parent, struct device *self, void *aux) switch (result) { case SDGP_RESULT_OK: - printf("%s: %lldMB, %lu bytes/sec, %lld sec total\n", + printf("%s: %lldMB, %lu bytes/sector, %lld sectors", sc->sc_dev.dv_xname, dp->disksize / (1048576 / dp->secsize), dp->secsize, dp->disksize); + if (ISSET(sc->flags, SDF_THIN)) + printf(", thin"); + printf("\n"); break; case SDGP_RESULT_OFFLINE: @@ -1327,6 +1333,113 @@ viscpy(u_char *dst, u_char *src, int len) *dst = '\0'; } +int +sd_read_cap_10(struct sd_softc *sc, int flags) +{ + struct scsi_read_capacity cdb; + struct scsi_read_cap_data *rdcap; + struct scsi_xfer *xs; + int rv = ENOMEM; + + CLR(flags, SCSI_IGNORE_ILLEGAL_REQUEST); + + rdcap = dma_alloc(sizeof(*rdcap), (ISSET(flags, SCSI_NOSLEEP) ? + PR_NOWAIT : PR_WAITOK) | PR_ZERO); + if (rdcap == NULL) + return (ENOMEM); + + xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT); + if (xs == NULL) + goto done; + + bzero(&cdb, sizeof(cdb)); + cdb.opcode = READ_CAPACITY; + + memcpy(xs->cmd, &cdb, sizeof(cdb)); + xs->cmdlen = sizeof(cdb); + xs->data = (void *)rdcap; + xs->datalen = sizeof(*rdcap); + xs->timeout = 20000; + + rv = scsi_xs_sync(xs); + scsi_xs_put(xs); + + if (rv == 0) { + sc->params.disksize = _4btol(rdcap->addr) + 1; + sc->params.secsize = _4btol(rdcap->length); + CLR(sc->flags, SDF_THIN); + } + + done: + dma_free(rdcap, sizeof(*rdcap)); + return (rv); +} + +int +sd_read_cap_16(struct sd_softc *sc, int flags) +{ + struct scsi_read_capacity_16 cdb; + struct scsi_read_cap_data_16 *rdcap; + struct scsi_xfer *xs; + int rv = ENOMEM; + + CLR(flags, SCSI_IGNORE_ILLEGAL_REQUEST); + + rdcap = dma_alloc(sizeof(*rdcap), (ISSET(flags, SCSI_NOSLEEP) ? + PR_NOWAIT : PR_WAITOK) | PR_ZERO); + if (rdcap == NULL) + return (ENOMEM); + + xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT); + if (xs == NULL) + goto done; + + bzero(&cdb, sizeof(cdb)); + cdb.opcode = READ_CAPACITY_16; + cdb.byte2 = SRC16_SERVICE_ACTION; + _lto4b(sizeof(*rdcap), cdb.length); + + memcpy(xs->cmd, &cdb, sizeof(cdb)); + xs->cmdlen = sizeof(cdb); + xs->data = (void *)rdcap; + xs->datalen = sizeof(*rdcap); + xs->timeout = 20000; + + rv = scsi_xs_sync(xs); + scsi_xs_put(xs); + + if (rv == 0) { + sc->params.disksize = _8btol(rdcap->addr) + 1; + sc->params.secsize = _4btol(rdcap->length); + if (ISSET(_2btol(rdcap->lowest_aligned), READ_CAP_16_TPE)) + SET(sc->flags, SDF_THIN); + else + CLR(sc->flags, SDF_THIN); + } + + done: + dma_free(rdcap, sizeof(*rdcap)); + return (rv); +} + +int +sd_size(struct sd_softc *sc, int flags) +{ + int rv; + + if (SCSISPC(sc->sc_link->inqdata.version) >= 3) { + rv = sd_read_cap_16(sc, flags); + if (rv != 0) + rv = sd_read_cap_10(sc, flags); + } else { + rv = sd_read_cap_10(sc, flags); + if (rv == 0 && sc->params.disksize == 0xffffffff) + rv = sd_read_cap_16(sc, flags); + } + + return (rv); +} + /* * Fill out the disk parameter structure. Return SDGP_RESULT_OK if the * structure is correctly filled in, SDGP_RESULT_OFFLINE otherwise. The caller @@ -1341,10 +1454,12 @@ sd_get_parms(struct sd_softc *sc, struct disk_parms *dp, int flags) struct page_flex_geometry *flex = NULL; struct page_reduced_geometry *reduced = NULL; u_char *page0 = NULL; - u_int32_t heads = 0, sectors = 0, cyls = 0, secsize = 0, sssecsize; + u_int32_t heads = 0, sectors = 0, cyls = 0, secsize = 0; int err = 0, big; - dp->disksize = scsi_size(sc->sc_link, flags, &sssecsize); + err = sd_size(sc, flags); + if (err != 0) + return (SDGP_RESULT_OFFLINE); buf = dma_alloc(sizeof(*buf), PR_NOWAIT); if (buf == NULL) @@ -1437,9 +1552,7 @@ validate: if (dp->disksize == 0) return (SDGP_RESULT_OFFLINE); - if (sssecsize > 0) - dp->secsize = sssecsize; - else + if (dp->secsize == 0) dp->secsize = (secsize == 0) ? 512 : secsize; /* diff --git a/sys/scsi/sdvar.h b/sys/scsi/sdvar.h index 344c9b344ac..13b7c47ee3c 100644 --- a/sys/scsi/sdvar.h +++ b/sys/scsi/sdvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdvar.h,v 1.36 2011/06/06 01:59:49 matthew Exp $ */ +/* $OpenBSD: sdvar.h,v 1.37 2011/07/11 00:22:15 dlg Exp $ */ /* $NetBSD: sdvar.h,v 1.7 1998/08/17 00:49:03 mycroft Exp $ */ /*- @@ -58,6 +58,7 @@ struct sd_softc { #define SDF_DIRTY 0x20 /* disk is dirty; needs cache flush */ #define SDF_DYING 0x40 /* dying, when deactivated */ #define SDF_WAITING 0x80 +#define SDF_THIN 0x01 /* disk is thin provisioned */ struct scsi_link *sc_link; /* contains our targ, lun, etc. */ struct disk_parms { u_long heads; /* number of heads */ |