summaryrefslogtreecommitdiff
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
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@
-rw-r--r--sys/scsi/sd.c127
-rw-r--r--sys/scsi/sdvar.h3
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 */