diff options
author | ken <ken@FreeBSD.org> | 2015-01-08 16:58:40 +0000 |
---|---|---|
committer | ken <ken@FreeBSD.org> | 2015-01-08 16:58:40 +0000 |
commit | b09a0cbe0ab3cc829ef468fc46df597c25b7fed3 (patch) | |
tree | 1c02a63965468a888671461d9bb72c8ff67fb435 /sys/cam | |
parent | 8d4db71d65990fa9bdb3f2dcfa4e6fe820dbbdc0 (diff) | |
download | FreeBSD-src-b09a0cbe0ab3cc829ef468fc46df597c25b7fed3.zip FreeBSD-src-b09a0cbe0ab3cc829ef468fc46df597c25b7fed3.tar.gz |
Improve camcontrol(8) handling of drive defect data.
This includes a new summary mode (-s) for camcontrol defects that
quickly tells the user the most important thing: how many defects
are in the requested list. The actual location of the defects is
less important.
Modern drives frequently have more than the 8191 defects that can
be reported by the READ DEFECT DATA (10) command. If they don't
have that many grown defects, they certainly have more than 8191
defects in the primary (i.e. factory) defect list.
The READ DEFECT DATA (12) command allows for longer parameter
lists, as well as indexing into the list of defects, and so allows
reporting many more defects.
This has been tested with HGST drives and Seagate drives, but
does not fully work with Seagate drives. Once I have a Seagate
spec I may be able to determine whether it is possible to make it
work with Seagate drives.
scsi_da.h: Add a definition for the new long block defect
format.
Add bit and mask definitions for the new extended
physical sector and bytes from index defect
formats.
Add a prototype for the new scsi_read_defects() CDB
building function.
scsi_da.c: Add a new scsi_read_defects() CDB building function.
camcontrol(8) was previously composing CDBs manually.
This is long overdue.
camcontrol.c: Revamp the camcontrol defects subcommand. We now
go through multiple stages in trying to get defect
data off the drive while avoiding various drive
firmware quirks.
We start off by requesting the defect header with
the 10 byte command. If we're in summary mode (-s)
and the drive reports fewer defects than can be
represented in the 10 byte header, we're done.
Otherwise, we know that we need to issue the
12 byte command if the drive reports the maximum
number of defects.
If we're in summary mode, we're done if we get a
good response back when asking for the 12 byte header.
If the user has asked for the full list, then we
use the address descriptor index field in the 12
byte CDB to step through the list in 64K chunks.
64K is small enough to work with most any ancient
or modern SCSI controller.
Add support for printing the new long block defect
format, as well as the extended physical sector and
bytes from index formats. I don't have any drives
that support the new formats.
Add a hexadecimal output format that can be turned
on with -X.
Add a quiet mode (-q) that can be turned on with
the summary mode (-s) to just print out a number.
Revamp the error detection and recovery code for
the defects command to work with HGST drives.
Call the new scsi_read_defects() CDB building
function instead of rolling the CDB ourselves.
Pay attention to the residual from the defect list
request when printing it out, so we don't run off
the end of the list.
Use the new scsi_nv library routines to convert
from strings to numbers and back.
camcontrol.8: Document the new defect formats (longblock, extbfi,
extphys) and command line options (-q, -s, -S and
-X) for the defects subcommand.
Explain a little more about what drives generally
do and don't support.
Sponsored by: Spectra Logic
MFC after: 1 week
Diffstat (limited to 'sys/cam')
-rw-r--r-- | sys/cam/scsi/scsi_da.c | 59 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_da.h | 39 |
2 files changed, 89 insertions, 9 deletions
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index d5e4937..4492579 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -3872,9 +3872,9 @@ dashutdown(void * arg, int howto) #else /* !_KERNEL */ /* - * XXX This is only left out of the kernel build to silence warnings. If, - * for some reason this function is used in the kernel, the ifdefs should - * be moved so it is included both in the kernel and userland. + * XXX These are only left out of the kernel build to silence warnings. If, + * for some reason these functions are used in the kernel, the ifdefs should + * be moved so they are included both in the kernel and userland. */ void scsi_format_unit(struct ccb_scsiio *csio, u_int32_t retries, @@ -3903,6 +3903,59 @@ scsi_format_unit(struct ccb_scsiio *csio, u_int32_t retries, } void +scsi_read_defects(struct ccb_scsiio *csio, uint32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + uint8_t tag_action, uint8_t list_format, + uint32_t addr_desc_index, uint8_t *data_ptr, + uint32_t dxfer_len, int minimum_cmd_size, + uint8_t sense_len, uint32_t timeout) +{ + uint8_t cdb_len; + + /* + * These conditions allow using the 10 byte command. Otherwise we + * need to use the 12 byte command. + */ + if ((minimum_cmd_size <= 10) + && (addr_desc_index == 0) + && (dxfer_len <= SRDD10_MAX_LENGTH)) { + struct scsi_read_defect_data_10 *cdb10; + + cdb10 = (struct scsi_read_defect_data_10 *) + &csio->cdb_io.cdb_bytes; + + cdb_len = sizeof(*cdb10); + bzero(cdb10, cdb_len); + cdb10->opcode = READ_DEFECT_DATA_10; + cdb10->format = list_format; + scsi_ulto2b(dxfer_len, cdb10->alloc_length); + } else { + struct scsi_read_defect_data_12 *cdb12; + + cdb12 = (struct scsi_read_defect_data_12 *) + &csio->cdb_io.cdb_bytes; + + cdb_len = sizeof(*cdb12); + bzero(cdb12, cdb_len); + cdb12->opcode = READ_DEFECT_DATA_12; + cdb12->format = list_format; + scsi_ulto4b(dxfer_len, cdb12->alloc_length); + scsi_ulto4b(addr_desc_index, cdb12->address_descriptor_index); + } + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/ CAM_DIR_IN, + tag_action, + data_ptr, + dxfer_len, + sense_len, + cdb_len, + timeout); +} + +void scsi_sanitize(struct ccb_scsiio *csio, u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *), u_int8_t tag_action, u_int8_t byte2, u_int16_t control, diff --git a/sys/cam/scsi/scsi_da.h b/sys/cam/scsi/scsi_da.h index 9e5563d..ad4d0db 100644 --- a/sys/cam/scsi/scsi_da.h +++ b/sys/cam/scsi/scsi_da.h @@ -98,8 +98,12 @@ struct scsi_read_defect_data_10 #define SRDD10_PLIST 0x10 #define SRDD10_DLIST_FORMAT_MASK 0x07 #define SRDD10_BLOCK_FORMAT 0x00 +#define SRDD10_EXT_BFI_FORMAT 0x01 +#define SRDD10_EXT_PHYS_FORMAT 0x02 +#define SRDD10_LONG_BLOCK_FORMAT 0x03 #define SRDD10_BYTES_FROM_INDEX_FORMAT 0x04 #define SRDD10_PHYSICAL_SECTOR_FORMAT 0x05 +#define SRDD10_VENDOR_FORMAT 0x06 uint8_t format; uint8_t reserved[4]; uint8_t alloc_length[2]; @@ -138,12 +142,13 @@ struct scsi_read_defect_data_12 #define SRDD12_GLIST 0x08 #define SRDD12_PLIST 0x10 #define SRDD12_DLIST_FORMAT_MASK 0x07 -#define SRDD12_BLOCK_FORMAT 0x00 -#define SRDD12_BYTES_FROM_INDEX_FORMAT 0x04 -#define SRDD12_PHYSICAL_SECTOR_FORMAT 0x05 +#define SRDD12_BLOCK_FORMAT SRDD10_BLOCK_FORMAT +#define SRDD12_BYTES_FROM_INDEX_FORMAT SRDD10_BYTES_FROM_INDEX_FORMAT +#define SRDD12_PHYSICAL_SECTOR_FORMAT SRDD10_PHYSICAL_SECTOR_FORMAT uint8_t format; uint8_t address_descriptor_index[4]; uint8_t alloc_length[4]; +#define SRDD12_MAX_LENGTH 0xffffffff uint8_t reserved; uint8_t control; }; @@ -325,6 +330,8 @@ struct scsi_read_defect_data_hdr_10 #define SRDDH10_PHYSICAL_SECTOR_FORMAT 0x05 u_int8_t format; u_int8_t length[2]; +#define SRDDH10_MAX_LENGTH SRDD10_MAX_LENGTH - \ + sizeof(struct scsi_read_defect_data_hdr_10) }; struct scsi_defect_desc_block @@ -332,10 +339,18 @@ struct scsi_defect_desc_block u_int8_t address[4]; }; +struct scsi_defect_desc_long_block +{ + u_int8_t address[8]; +}; + struct scsi_defect_desc_bytes_from_index { u_int8_t cylinder[3]; u_int8_t head; +#define SDD_EXT_BFI_MADS 0x80000000 +#define SDD_EXT_BFI_FLAG_MASK 0xf0000000 +#define SDD_EXT_BFI_ENTIRE_TRACK 0x0fffffff u_int8_t bytes_from_index[4]; }; @@ -343,6 +358,9 @@ struct scsi_defect_desc_phys_sector { u_int8_t cylinder[3]; u_int8_t head; +#define SDD_EXT_PHYS_MADS 0x80000000 +#define SDD_EXT_PHYS_FLAG_MASK 0xf0000000 +#define SDD_EXT_PHYS_ENTIRE_TRACK 0x0fffffff u_int8_t sector[4]; }; @@ -358,6 +376,8 @@ struct scsi_read_defect_data_hdr_12 u_int8_t format; u_int8_t generation[2]; u_int8_t length[4]; +#define SRDDH12_MAX_LENGTH SRDD12_MAX_LENGTH - \ + sizeof(struct scsi_read_defect_data_hdr_12) }; union disk_pages /* this is the structure copied from osf */ @@ -536,9 +556,9 @@ struct scsi_da_rw_recovery_page { __BEGIN_DECLS /* - * XXX This is only left out of the kernel build to silence warnings. If, - * for some reason this function is used in the kernel, the ifdefs should - * be moved so it is included both in the kernel and userland. + * XXX These are only left out of the kernel build to silence warnings. If, + * for some reason these functions are used in the kernel, the ifdefs should + * be moved so they are included both in the kernel and userland. */ #ifndef _KERNEL void scsi_format_unit(struct ccb_scsiio *csio, u_int32_t retries, @@ -547,6 +567,13 @@ void scsi_format_unit(struct ccb_scsiio *csio, u_int32_t retries, u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, u_int32_t timeout); +void scsi_read_defects(struct ccb_scsiio *csio, uint32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + uint8_t tag_action, uint8_t list_format, + uint32_t addr_desc_index, uint8_t *data_ptr, + uint32_t dxfer_len, int minimum_cmd_size, + uint8_t sense_len, uint32_t timeout); + void scsi_sanitize(struct ccb_scsiio *csio, u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *), u_int8_t tag_action, u_int8_t byte2, u_int16_t control, |