summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2010-04-03 07:09:30 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2010-04-03 07:09:30 +0000
commitd996f4362efd28d814bac947f37c403ab2462c7e (patch)
tree052c26f3190708c873fe2a67c6510be855d72199
parentbb944976dc31039a7843473e42b5fe344e6b6402 (diff)
add support for emulating the disk characteristics and disk limits vpd
pages. this if the first step in figuring out if disks use a different physical block size compared to the logical block size they present to the operating system.
-rw-r--r--sys/dev/ata/atascsi.c64
-rw-r--r--sys/dev/ata/atascsi.h17
-rw-r--r--sys/scsi/scsi_disk.h48
3 files changed, 122 insertions, 7 deletions
diff --git a/sys/dev/ata/atascsi.c b/sys/dev/ata/atascsi.c
index 9f27e878a0e..8bee37f61a5 100644
--- a/sys/dev/ata/atascsi.c
+++ b/sys/dev/ata/atascsi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atascsi.c,v 1.72 2010/03/23 01:57:19 krw Exp $ */
+/* $OpenBSD: atascsi.c,v 1.73 2010/04/03 07:09:29 dlg Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
@@ -75,6 +75,8 @@ void atascsi_disk_inquiry(struct scsi_xfer *);
void atascsi_disk_vpd_supported(struct scsi_xfer *);
void atascsi_disk_vpd_serial(struct scsi_xfer *);
void atascsi_disk_vpd_ident(struct scsi_xfer *);
+void atascsi_disk_vpd_limits(struct scsi_xfer *);
+void atascsi_disk_vpd_info(struct scsi_xfer *);
void atascsi_disk_capacity(struct scsi_xfer *);
void atascsi_disk_sync(struct scsi_xfer *);
void atascsi_disk_sync_done(struct ata_xfer *);
@@ -220,6 +222,8 @@ atascsi_probe(struct scsi_link *link)
if (type != ATA_PORT_T_DISK)
return (0);
+ printf("106: 0x%04x\n", ap->ap_identify.p2l_sect);
+
/* Enable write cache if supported */
if (ap->ap_identify.cmdset82 & ATA_IDENTIFY_WRITECACHE) {
xa = ata_get_xfer(ap);
@@ -484,6 +488,12 @@ atascsi_disk_inq(struct scsi_xfer *xs)
case SI_PG_DEVID:
atascsi_disk_vpd_ident(xs);
break;
+ case SI_PG_DISK_LIMITS:
+ atascsi_disk_vpd_limits(xs);
+ break;
+ case SI_PG_DISK_INFO:
+ atascsi_disk_vpd_info(xs);
+ break;
default:
atascsi_done(xs, XS_DRIVER_STUFFUP);
break;
@@ -559,7 +569,7 @@ atascsi_disk_vpd_supported(struct scsi_xfer *xs)
{
struct {
struct scsi_vpd_hdr hdr;
- u_int8_t list[3];
+ u_int8_t list[5];
} pg;
bzero(&pg, sizeof(pg));
@@ -570,6 +580,8 @@ atascsi_disk_vpd_supported(struct scsi_xfer *xs)
pg.list[0] = SI_PG_SUPPORTED;
pg.list[1] = SI_PG_SERIAL;
pg.list[2] = SI_PG_DEVID;
+ pg.list[3] = SI_PG_DISK_LIMITS;
+ pg.list[4] = SI_PG_DISK_INFO;
bcopy(&pg, xs->data, MIN(sizeof(pg), xs->datalen));
@@ -649,6 +661,54 @@ atascsi_disk_vpd_ident(struct scsi_xfer *xs)
}
void
+atascsi_disk_vpd_limits(struct scsi_xfer *xs)
+{
+ struct scsi_link *link = xs->sc_link;
+ struct atascsi *as = link->adapter_softc;
+ struct ata_port *ap = as->as_ports[link->target];
+ struct scsi_vpd_disk_limits pg;
+ u_int16_t p2l_sect;
+
+ bzero(&pg, sizeof(pg));
+ pg.hdr.device = T_DIRECT;
+ pg.hdr.page_code = SI_PG_DISK_LIMITS;
+ pg.hdr.page_length = SI_PG_DISK_LIMITS_LEN_THIN;
+
+ p2l_sect = letoh16(ap->ap_identify.p2l_sect);
+ if ((p2l_sect & ATA_ID_P2L_SECT_MASK) == ATA_ID_P2L_SECT_VALID &&
+ ISSET(p2l_sect, ATA_ID_P2L_SECT_SET)) {
+ _lto2b(2 << (p2l_sect & SI_PG_DISK_LIMITS_LEN_THIN),
+ pg.optimal_xfer_granularity);
+ } else
+ _lto2b(1, pg.optimal_xfer_granularity);
+
+ bcopy(&pg, xs->data, MIN(sizeof(pg), xs->datalen));
+
+ atascsi_done(xs, XS_NOERROR);
+}
+
+void
+atascsi_disk_vpd_info(struct scsi_xfer *xs)
+{
+ struct scsi_link *link = xs->sc_link;
+ struct atascsi *as = link->adapter_softc;
+ struct ata_port *ap = as->as_ports[link->target];
+ struct scsi_vpd_disk_info pg;
+
+ bzero(&pg, sizeof(pg));
+ pg.hdr.device = T_DIRECT;
+ pg.hdr.page_code = SI_PG_DISK_INFO;
+ pg.hdr.page_length = sizeof(pg) - sizeof(pg.hdr);
+
+ _lto2b(letoh16(ap->ap_identify.rpm), pg.rpm);
+ pg.form_factor = letoh16(ap->ap_identify.form) & ATA_ID_FORM_MASK;
+
+ bcopy(&pg, xs->data, MIN(sizeof(pg), xs->datalen));
+
+ atascsi_done(xs, XS_NOERROR);
+}
+
+void
atascsi_disk_sync(struct scsi_xfer *xs)
{
struct scsi_link *link = xs->sc_link;
diff --git a/sys/dev/ata/atascsi.h b/sys/dev/ata/atascsi.h
index c1b4e543f67..79625b28c29 100644
--- a/sys/dev/ata/atascsi.h
+++ b/sys/dev/ata/atascsi.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: atascsi.h,v 1.35 2009/12/08 08:07:51 dlg Exp $ */
+/* $OpenBSD: atascsi.h,v 1.36 2010/04/03 07:09:29 dlg Exp $ */
/*
* Copyright (c) 2007 David Gwynne <dlg@openbsd.org>
@@ -110,7 +110,12 @@ struct ata_identify {
u_int16_t addrsecxt[4]; /* 100 */
u_int16_t stream_xfer_p; /* 104 */
u_int16_t padding1; /* 105 */
- u_int16_t phys_sect_sz; /* 106 */
+ u_int16_t p2l_sect; /* 106 */
+#define ATA_ID_P2L_SECT_MASK 0xc000
+#define ATA_ID_P2L_SECT_VALID 0x4000
+#define ATA_ID_P2L_SECT_SET 0x2000
+#define ATA_ID_P2L_SECT_LARGE 0x1000
+#define ATA_ID_P2L_SECT_SIZE 0x000f
u_int16_t seek_delay; /* 107 */
u_int16_t naa_ieee_oui; /* 108 */
u_int16_t ieee_oui_uid; /* 109 */
@@ -125,10 +130,14 @@ struct ata_identify {
u_int16_t rmsn; /* 127 */
u_int16_t securestatus; /* 128 */
u_int16_t vendor[31]; /* 129 */
- u_int16_t padding3[16]; /* 160 */
+ u_int16_t padding3[8]; /* 160 */
+ u_int16_t form; /* 168 */
+#define ATA_ID_FORM_MASK 0x000f
+ u_int16_t padding4[7]; /* 169 */
u_int16_t curmedser[30]; /* 176 */
u_int16_t sctsupport; /* 206 */
- u_int16_t padding4[48]; /* 207 */
+ u_int16_t rpm; /* 207 */
+ u_int16_t padding5[47]; /* 208 */
u_int16_t integrity; /* 255 */
} __packed;
diff --git a/sys/scsi/scsi_disk.h b/sys/scsi/scsi_disk.h
index 1f4abf27a08..7cc5d2b39e4 100644
--- a/sys/scsi/scsi_disk.h
+++ b/sys/scsi/scsi_disk.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsi_disk.h,v 1.24 2010/01/03 11:09:41 dlg Exp $ */
+/* $OpenBSD: scsi_disk.h,v 1.25 2010/04/03 07:09:29 dlg Exp $ */
/* $NetBSD: scsi_disk.h,v 1.10 1996/07/05 16:19:05 christos Exp $ */
/*
@@ -395,4 +395,50 @@ struct page_caching_mode {
u_int8_t max_prefetch_ceil[2];
};
+#define SI_PG_DISK_LIMITS 0xb0 /* block limits */
+#define SI_PG_DISK_INFO 0xb1 /* device charateristics */
+
+struct scsi_vpd_disk_limits {
+ struct scsi_vpd_hdr hdr;
+#define SI_PG_DISK_LIMITS_LEN 0x10
+#define SI_PG_DISK_LIMITS_LEN_THIN 0x3c
+
+ u_int8_t _reserved1[1];
+ u_int8_t max_comp_wr_len;
+ u_int8_t optimal_xfer_granularity[2];
+
+ u_int8_t max_xfer_len[4];
+
+ u_int8_t optimal_xfer[4];
+
+ u_int8_t max_xd_prefetch_len[4];
+
+ u_int8_t max_unmap_lba_count[4];
+
+ u_int8_t max_unmap_desc_count[4];
+
+ u_int8_t optimal_unmap_granularity[4];
+
+ u_int8_t unmap_granularity_align[4];
+
+ u_int8_t _reserved2[28];
+};
+
+struct scsi_vpd_disk_info {
+ struct scsi_vpd_hdr hdr;
+ u_int8_t rpm[2];
+#define VPD_DISK_INFO_RPM_UNDEF 0x0000
+#define VPD_DISK_INFO_RPM_NONE 0x0001
+ u_int8_t _reserved1[1];
+ u_int8_t form_factor;
+#define VPD_DISK_INFO_FORM_MASK 0xf
+#define VPD_DISK_INFO_FORM_UNDEF 0x0
+#define VPD_DISK_INFO_FORM_5_25 0x1
+#define VPD_DISK_INFO_FORM_3_5 0x2
+#define VPD_DISK_INFO_FORM_2_5 0x3
+#define VPD_DISK_INFO_FORM_1_8 0x4
+#define VPD_DISK_INFO_FORM_LT_1_8 0x5
+ u_int8_t _reserved2[56];
+};
+
#endif /* _SCSI_SCSI_DISK_H */