summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2007-06-23 19:19:50 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2007-06-23 19:19:50 +0000
commit741fb47166c6a7ffa0aea3684329acedb201ef7c (patch)
treedf291a449f6b43d6f8b78223da879573128524d4 /sys
parent7c2aff00e72485ff4505521e9f198b4583a51cab (diff)
Implement disk sizes > 2^32-1. Code modelled on NetBSD.
Tested, tweaked and ok otto@
Diffstat (limited to 'sys')
-rw-r--r--sys/scsi/scsi_base.c55
-rw-r--r--sys/scsi/scsi_disk.h3
-rw-r--r--sys/scsi/scsiconf.h4
-rw-r--r--sys/scsi/sd.c26
-rw-r--r--sys/scsi/sdvar.h4
5 files changed, 58 insertions, 34 deletions
diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c
index 2fb0a89d5c4..92b5db1f9e0 100644
--- a/sys/scsi/scsi_base.c
+++ b/sys/scsi/scsi_base.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsi_base.c,v 1.121 2007/05/31 18:21:44 dlg Exp $ */
+/* $OpenBSD: scsi_base.c,v 1.122 2007/06/23 19:19:49 krw Exp $ */
/* $NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $ */
/*
@@ -221,13 +221,15 @@ scsi_make_xs(struct scsi_link *sc_link, struct scsi_generic *scsi_cmd,
/*
* Find out from the device what its capacity is.
*/
-u_long
+daddr64_t
scsi_size(struct scsi_link *sc_link, int flags, u_int32_t *blksize)
{
- struct scsi_read_capacity scsi_cmd;
- struct scsi_read_cap_data rdcap;
- u_long max_addr;
- int error;
+ struct scsi_read_cap_data_16 rdcap16;
+ struct scsi_read_capacity_16 rc16;
+ struct scsi_read_cap_data rdcap;
+ struct scsi_read_capacity rc;
+ daddr64_t max_addr;
+ int error;
if (blksize != NULL)
*blksize = 0;
@@ -235,15 +237,16 @@ scsi_size(struct scsi_link *sc_link, int flags, u_int32_t *blksize)
/*
* make up a scsi command and ask the scsi driver to do it for you.
*/
- bzero(&scsi_cmd, sizeof(scsi_cmd));
- scsi_cmd.opcode = READ_CAPACITY;
+ bzero(&rc, sizeof(rc));
+ bzero(&rdcap, sizeof(rdcap));
+ rc.opcode = READ_CAPACITY;
/*
* If the command works, interpret the result as a 4 byte
* number of blocks
*/
- error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,
- sizeof(scsi_cmd), (u_char *)&rdcap, sizeof(rdcap), 2, 20000, NULL,
+ error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&rc, sizeof(rc),
+ (u_char *)&rdcap, sizeof(rdcap), 2, 20000, NULL,
flags | SCSI_DATA_IN);
if (error) {
SC_DEBUG(sc_link, SDEV_DB1, ("READ CAPACITY error (%#x)\n",
@@ -255,17 +258,31 @@ scsi_size(struct scsi_link *sc_link, int flags, u_int32_t *blksize)
if (blksize != NULL)
*blksize = _4btol(rdcap.length);
- if (max_addr == 0xffffffffUL) {
- /*
- * The device is reporting it has more than 2^32-1 sectors. The
- * 16-byte READ CAPACITY command must be issued to get full
- * capacity.
- */
- sc_print_addr(sc_link);
- printf("only the first 4,294,967,295 sectors will be used.\n");
- return (0xffffffffUL);
+ if (max_addr != 0xffffffff)
+ return (max_addr + 1);
+
+ /*
+ * The device has more than 2^32-1 sectors. Use 16-byte READ CAPACITY.
+ */
+ bzero(&rc16, sizeof(rc16));
+ bzero(&rdcap16, sizeof(rdcap16));
+ rc16.opcode = READ_CAPACITY_16;
+ rc16.byte2 = SRC16_SERVICE_ACTION;
+ _lto4b(sizeof(rdcap16), rc16.length);
+
+ error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&rc16,
+ sizeof(rc16), (u_char *)&rdcap16, sizeof(rdcap16), 2, 20000, NULL,
+ flags | SCSI_DATA_IN);
+ if (error) {
+ SC_DEBUG(sc_link, SDEV_DB1, ("READ CAPACITY 16 error (%#x)\n",
+ error));
+ return (0);
}
+ max_addr = _8btol(rdcap16.addr);
+ if (blksize != NULL)
+ *blksize = _4btol(rdcap16.length);
+
return (max_addr + 1);
}
diff --git a/sys/scsi/scsi_disk.h b/sys/scsi/scsi_disk.h
index eaa8bf31fde..508c3b5648c 100644
--- a/sys/scsi/scsi_disk.h
+++ b/sys/scsi/scsi_disk.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsi_disk.h,v 1.21 2007/04/12 16:33:27 weingart Exp $ */
+/* $OpenBSD: scsi_disk.h,v 1.22 2007/06/23 19:19:49 krw Exp $ */
/* $NetBSD: scsi_disk.h,v 1.10 1996/07/05 16:19:05 christos Exp $ */
/*
@@ -203,6 +203,7 @@ struct scsi_read_capacity {
struct scsi_read_capacity_16 {
u_int8_t opcode;
u_int8_t byte2;
+#define SRC16_SERVICE_ACTION 0x10
u_int8_t addr[8];
u_int8_t length[4];
u_int8_t reserved;
diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h
index 6e816f45729..09f16d14adf 100644
--- a/sys/scsi/scsiconf.h
+++ b/sys/scsi/scsiconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsiconf.h,v 1.86 2007/05/31 21:53:02 tedu Exp $ */
+/* $OpenBSD: scsiconf.h,v 1.87 2007/06/23 19:19:49 krw Exp $ */
/* $NetBSD: scsiconf.h,v 1.35 1997/04/02 02:29:38 mycroft Exp $ */
/*
@@ -312,7 +312,7 @@ struct scsi_xfer *
scsi_get_xs(struct scsi_link *, int);
void scsi_free_xs(struct scsi_xfer *, int);
int scsi_execute_xs(struct scsi_xfer *);
-u_long scsi_size(struct scsi_link *, int, u_int32_t *);
+daddr64_t scsi_size(struct scsi_link *, int, u_int32_t *);
int scsi_test_unit_ready(struct scsi_link *, int, int);
int scsi_inquire(struct scsi_link *, struct scsi_inquiry_data *, int);
int scsi_inquire_vpd(struct scsi_link *, void *, u_int, u_int8_t, int);
diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c
index f7ac4666ce4..37253fd686b 100644
--- a/sys/scsi/sd.c
+++ b/sys/scsi/sd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sd.c,v 1.135 2007/06/20 18:15:47 deraadt Exp $ */
+/* $OpenBSD: sd.c,v 1.136 2007/06/23 19:19:49 krw Exp $ */
/* $NetBSD: sd.c,v 1.111 1997/04/02 02:29:41 mycroft Exp $ */
/*-
@@ -223,7 +223,7 @@ sdattach(struct device *parent, struct device *self, void *aux)
printf("%s: ", sd->sc_dev.dv_xname);
switch (result) {
case SDGP_RESULT_OK:
- printf("%luMB, %lu cyl, %lu head, %lu sec, %lu bytes/sec, %lu sec total",
+ printf("%lldMB, %lu cyl, %lu head, %lu sec, %lu bytes/sec, %lld sec total",
dp->disksize / (1048576 / dp->blksize), dp->cyls,
dp->heads, dp->sectors, dp->blksize, dp->disksize);
break;
@@ -1418,19 +1418,25 @@ validate:
}
/*
- * Use standard geometry values for anything we still don't know.
- */
-
- dp->heads = (heads == 0) ? 255 : heads;
- dp->sectors = (sectors == 0) ? 63 : 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.
*/
+ if (dp->disksize > 0xffffffff && (dp->heads * dp->sectors) < 0xffff) {
+ dp->heads = 511;
+ dp->sectors = 255;
+ cyls = 0;
+ } else {
+ /*
+ * Use standard geometry values for anything we still don't
+ * know.
+ */
+ dp->heads = (heads == 0) ? 255 : heads;
+ dp->sectors = (sectors == 0) ? 63 : sectors;
+ dp->rot_rate = (rpm == 0) ? 3600 : rpm;
+ }
+
dp->cyls = (cyls == 0) ? dp->disksize / (dp->heads * dp->sectors) :
cyls;
diff --git a/sys/scsi/sdvar.h b/sys/scsi/sdvar.h
index e44cfb2a6aa..b82666ba5f2 100644
--- a/sys/scsi/sdvar.h
+++ b/sys/scsi/sdvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdvar.h,v 1.10 2006/12/12 02:44:36 krw Exp $ */
+/* $OpenBSD: sdvar.h,v 1.11 2007/06/23 19:19:49 krw Exp $ */
/* $NetBSD: sdvar.h,v 1.7 1998/08/17 00:49:03 mycroft Exp $ */
/*-
@@ -74,8 +74,8 @@ struct sd_softc {
u_long cyls; /* number of cylinders */
u_long sectors; /* number of sectors/track */
u_long blksize; /* number of bytes/sector */
- u_long disksize; /* total number sectors */
u_long rot_rate; /* rotational rate, in RPM */
+ daddr64_t disksize; /* total number sectors */
} params;
struct buf buf_queue;
void *sc_sdhook; /* our shutdown hook */