summaryrefslogtreecommitdiff
path: root/sys/scsi/sd.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2011-07-11 00:22:16 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2011-07-11 00:22:16 +0000
commit2e4cd0ad9e5d255b639b7348340085a8fdccb17f (patch)
tree9172cbe454b562e3e9d49745f3ef92b29733ab9a /sys/scsi/sd.c
parent9ed4c7013223096daecbcc2b6f8aa6924c7ccbfe (diff)
disks report trim^Wunmap^Wif theyre thin provisioned via a bit in
the read cap 16 data. move the read cap code into sd.c so i can get at this bit without much contorting, and to make it trivial to get at the other interesting things in there later. thin disks report themselves as "thin" in dmesg along with their size now. ok matthew@
Diffstat (limited to 'sys/scsi/sd.c')
-rw-r--r--sys/scsi/sd.c127
1 files changed, 120 insertions, 7 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;
/*