diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2007-06-23 19:19:50 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2007-06-23 19:19:50 +0000 |
commit | 741fb47166c6a7ffa0aea3684329acedb201ef7c (patch) | |
tree | df291a449f6b43d6f8b78223da879573128524d4 /sys | |
parent | 7c2aff00e72485ff4505521e9f198b4583a51cab (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.c | 55 | ||||
-rw-r--r-- | sys/scsi/scsi_disk.h | 3 | ||||
-rw-r--r-- | sys/scsi/scsiconf.h | 4 | ||||
-rw-r--r-- | sys/scsi/sd.c | 26 | ||||
-rw-r--r-- | sys/scsi/sdvar.h | 4 |
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 */ |