summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authorken <ken@FreeBSD.org>2015-01-08 16:58:40 +0000
committerken <ken@FreeBSD.org>2015-01-08 16:58:40 +0000
commitb09a0cbe0ab3cc829ef468fc46df597c25b7fed3 (patch)
tree1c02a63965468a888671461d9bb72c8ff67fb435 /sys/cam
parent8d4db71d65990fa9bdb3f2dcfa4e6fe820dbbdc0 (diff)
downloadFreeBSD-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.c59
-rw-r--r--sys/cam/scsi/scsi_da.h39
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,
OpenPOWER on IntegriCloud