From e11295022950826c9f2fb00d8ad29734fca921af Mon Sep 17 00:00:00 2001 From: thorpej Date: Fri, 3 Dec 2004 20:20:32 +0000 Subject: [PATCH] And thus spake SBC-3: If the number of logical blocks exceeds the maximum value that is able to be specified in the RETURNED LOGICAL BLOCK ADDRESS field, the device server shall set the RETURNED LOGICAL BLOCK ADDRESS field to FFFFFFFFh. The application client should then issue a READ CAPACITY (16) command (see 5.11) to retrieve the READ CAPACITY (16) parameter data. Implement this in scsipi_size(). First issue in kern/28514. --- sys/dev/scsipi/scsipi_base.c | 41 +++++++++++++++++++++++++++++------- sys/dev/scsipi/scsipi_disk.h | 24 ++++++++++++++++++++- sys/dev/scsipi/scsipiconf.h | 18 +++++++++++++++- 3 files changed, 73 insertions(+), 10 deletions(-) diff --git a/sys/dev/scsipi/scsipi_base.c b/sys/dev/scsipi/scsipi_base.c index 87cb274d24c3..f96e1a3fbfd1 100644 --- a/sys/dev/scsipi/scsipi_base.c +++ b/sys/dev/scsipi/scsipi_base.c @@ -1,4 +1,4 @@ -/* $NetBSD: scsipi_base.c,v 1.121 2004/10/01 03:39:11 enami Exp $ */ +/* $NetBSD: scsipi_base.c,v 1.122 2004/12/03 20:20:32 thorpej Exp $ */ /*- * Copyright (c) 1998, 1999, 2000, 2002, 2003, 2004 The NetBSD Foundation, Inc. @@ -38,7 +38,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.121 2004/10/01 03:39:11 enami Exp $"); +__KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.122 2004/12/03 20:20:32 thorpej Exp $"); #include "opt_scsi.h" @@ -1026,22 +1026,47 @@ scsipi_interpret_sense(struct scsipi_xfer *xs) u_int64_t scsipi_size(struct scsipi_periph *periph, int flags) { - struct scsipi_read_capacity cmd; - struct scsipi_read_cap_data data; + union { + struct scsipi_read_capacity cmd; + struct scsipi_read_capacity_16 cmd16; + } cmd; + union { + struct scsipi_read_cap_data data; + struct scsipi_read_capacity_16_data data16; + } data; memset(&cmd, 0, sizeof(cmd)); - cmd.opcode = READ_CAPACITY; + cmd.cmd.opcode = READ_CAPACITY; /* * If the command works, interpret the result as a 4 byte * number of blocks */ - if (scsipi_command(periph, (void *)&cmd, sizeof(cmd), - (void *)&data, sizeof(data), SCSIPIRETRIES, 20000, NULL, + if (scsipi_command(periph, (void *)&cmd.cmd, sizeof(cmd.cmd), + (void *)&data.data, sizeof(data.data), SCSIPIRETRIES, 20000, NULL, flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK | XS_CTL_SILENT) != 0) return (0); - return (_4btol(data.addr) + 1); + if (_4btol(data.data.addr) != 0xffffffff) + return (_4btol(data.data.addr) + 1); + + /* + * Device is larger than can be reflected by READ CAPACITY (10). + * Try READ CAPACITY (16). + */ + + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd16.opcode = READ_CAPACITY_16; + cmd.cmd16.byte2 = SRC16_SERVICE_ACTION; + _lto4b(sizeof(data.data16), cmd.cmd16.len); + + if (scsipi_command(periph, (void *)&cmd.cmd16, sizeof(cmd.cmd16), + (void *)&data.data16, sizeof(data.data16), SCSIPIRETRIES, 20000, + NULL, + flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK | XS_CTL_SILENT) != 0) + return (0); + + return (_8btol(data.data16.addr) + 1); } /* diff --git a/sys/dev/scsipi/scsipi_disk.h b/sys/dev/scsipi/scsipi_disk.h index cf16b9ac36cb..499d758927ca 100644 --- a/sys/dev/scsipi/scsipi_disk.h +++ b/sys/dev/scsipi/scsipi_disk.h @@ -1,4 +1,4 @@ -/* $NetBSD: scsipi_disk.h,v 1.9 2003/09/17 23:33:43 mycroft Exp $ */ +/* $NetBSD: scsipi_disk.h,v 1.10 2004/12/03 20:20:32 thorpej Exp $ */ /* * SCSI and SCSI-like interfaces description @@ -86,6 +86,28 @@ struct scsipi_read_cap_data { u_int8_t length[4]; } __attribute__((packed)); +#define READ_CAPACITY_16 0x9e /* really SERVICE ACTION IN */ +struct scsipi_read_capacity_16 { + u_int8_t opcode; + u_int8_t byte2; +#define SRC16_SERVICE_ACTION 0x10 + u_int8_t addr[8]; + u_int8_t len[4]; + u_int8_t byte15; +#define SRC16_PMI 0x01 + u_int8_t control; +}; + +struct scsipi_read_capacity_16_data { + u_int8_t addr[8]; + u_int8_t length[4]; + u_int8_t byte13; +#define SRC16D_PROT_EN 0x01 +#define SRC16D_RTO_EN 0x02 + u_int8_t reserved[19]; +}; + +/* XXX SBC-2 says this is vendor-specific */ #define READ_FORMAT_CAPACITIES 0x23 struct scsipi_read_format_capacities { u_int8_t opcode; diff --git a/sys/dev/scsipi/scsipiconf.h b/sys/dev/scsipi/scsipiconf.h index db012281b250..86f3febc73fc 100644 --- a/sys/dev/scsipi/scsipiconf.h +++ b/sys/dev/scsipi/scsipiconf.h @@ -1,4 +1,4 @@ -/* $NetBSD: scsipiconf.h,v 1.90 2004/09/17 23:43:17 mycroft Exp $ */ +/* $NetBSD: scsipiconf.h,v 1.91 2004/12/03 20:20:32 thorpej Exp $ */ /*- * Copyright (c) 1998, 1999, 2000, 2004 The NetBSD Foundation, Inc. @@ -773,6 +773,22 @@ _5btol(const u_int8_t *bytes) return (rv); } +static __inline u_int64_t __unused +_8btol(const u_int8_t *bytes) +{ + u_int64_t rv; + + rv = ((u_int64_t)bytes[0] << 56) | + ((u_int64_t)bytes[1] << 48) | + ((u_int64_t)bytes[2] << 40) | + ((u_int64_t)bytes[3] << 32) | + ((u_int64_t)bytes[4] << 24) | + ((u_int64_t)bytes[5] << 16) | + ((u_int64_t)bytes[6] << 8) | + (u_int64_t)bytes[7]; + return (rv); +} + static __inline void __unused _lto2l(u_int32_t val, u_int8_t *bytes) {