diff options
author | Martin K. Petersen <martin.petersen@oracle.com> | 2008-07-17 04:28:34 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-07-26 15:14:55 -0400 |
commit | e0597d70012c82e16ee152270a55d89d8bf66693 (patch) | |
tree | 1752132ba07975a8db2bf93ddad88e1a6c06f4d2 /drivers | |
parent | 511e44f42e3239a4df77b8e0e46d294d98a768ad (diff) |
[SCSI] sd: Identify DIF protection type and application tag ownership
If a disk is formatted with protection information (Inquiry bit
PROTECT=1) it is required to support Read Capacity(16). Force use of
the 16-bit command in this case and extract the P_TYPE field which
indicates whether the disk is formatted using DIF Type 1, 2 or 3.
The ATO (App Tag Own) bit in the Control Mode Page indicates whether
the storage device or the initiator own the contents of the
DIF application tag.
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/sd.c | 122 | ||||
-rw-r--r-- | drivers/scsi/sd.h | 23 |
2 files changed, 141 insertions, 4 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 99dddcae7851..56b9501d12f3 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -233,6 +233,24 @@ sd_show_allow_restart(struct device *dev, struct device_attribute *attr, | |||
233 | return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart); | 233 | return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart); |
234 | } | 234 | } |
235 | 235 | ||
236 | static ssize_t | ||
237 | sd_show_protection_type(struct device *dev, struct device_attribute *attr, | ||
238 | char *buf) | ||
239 | { | ||
240 | struct scsi_disk *sdkp = to_scsi_disk(dev); | ||
241 | |||
242 | return snprintf(buf, 20, "%u\n", sdkp->protection_type); | ||
243 | } | ||
244 | |||
245 | static ssize_t | ||
246 | sd_show_app_tag_own(struct device *dev, struct device_attribute *attr, | ||
247 | char *buf) | ||
248 | { | ||
249 | struct scsi_disk *sdkp = to_scsi_disk(dev); | ||
250 | |||
251 | return snprintf(buf, 20, "%u\n", sdkp->ATO); | ||
252 | } | ||
253 | |||
236 | static struct device_attribute sd_disk_attrs[] = { | 254 | static struct device_attribute sd_disk_attrs[] = { |
237 | __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, | 255 | __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, |
238 | sd_store_cache_type), | 256 | sd_store_cache_type), |
@@ -241,6 +259,8 @@ static struct device_attribute sd_disk_attrs[] = { | |||
241 | sd_store_allow_restart), | 259 | sd_store_allow_restart), |
242 | __ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop, | 260 | __ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop, |
243 | sd_store_manage_start_stop), | 261 | sd_store_manage_start_stop), |
262 | __ATTR(protection_type, S_IRUGO, sd_show_protection_type, NULL), | ||
263 | __ATTR(app_tag_own, S_IRUGO, sd_show_app_tag_own, NULL), | ||
244 | __ATTR_NULL, | 264 | __ATTR_NULL, |
245 | }; | 265 | }; |
246 | 266 | ||
@@ -1164,6 +1184,49 @@ sd_spinup_disk(struct scsi_disk *sdkp) | |||
1164 | } | 1184 | } |
1165 | } | 1185 | } |
1166 | 1186 | ||
1187 | |||
1188 | /* | ||
1189 | * Determine whether disk supports Data Integrity Field. | ||
1190 | */ | ||
1191 | void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer) | ||
1192 | { | ||
1193 | struct scsi_device *sdp = sdkp->device; | ||
1194 | u8 type; | ||
1195 | |||
1196 | if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) | ||
1197 | type = 0; | ||
1198 | else | ||
1199 | type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ | ||
1200 | |||
1201 | switch (type) { | ||
1202 | case SD_DIF_TYPE0_PROTECTION: | ||
1203 | sdkp->protection_type = 0; | ||
1204 | break; | ||
1205 | |||
1206 | case SD_DIF_TYPE1_PROTECTION: | ||
1207 | case SD_DIF_TYPE3_PROTECTION: | ||
1208 | sdkp->protection_type = type; | ||
1209 | break; | ||
1210 | |||
1211 | case SD_DIF_TYPE2_PROTECTION: | ||
1212 | sd_printk(KERN_ERR, sdkp, "formatted with DIF Type 2 " \ | ||
1213 | "protection which is currently unsupported. " \ | ||
1214 | "Disabling disk!\n"); | ||
1215 | goto disable; | ||
1216 | |||
1217 | default: | ||
1218 | sd_printk(KERN_ERR, sdkp, "formatted with unknown " \ | ||
1219 | "protection type %d. Disabling disk!\n", type); | ||
1220 | goto disable; | ||
1221 | } | ||
1222 | |||
1223 | return; | ||
1224 | |||
1225 | disable: | ||
1226 | sdkp->protection_type = 0; | ||
1227 | sdkp->capacity = 0; | ||
1228 | } | ||
1229 | |||
1167 | /* | 1230 | /* |
1168 | * read disk capacity | 1231 | * read disk capacity |
1169 | */ | 1232 | */ |
@@ -1173,7 +1236,8 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) | |||
1173 | unsigned char cmd[16]; | 1236 | unsigned char cmd[16]; |
1174 | int the_result, retries; | 1237 | int the_result, retries; |
1175 | int sector_size = 0; | 1238 | int sector_size = 0; |
1176 | int longrc = 0; | 1239 | /* Force READ CAPACITY(16) when PROTECT=1 */ |
1240 | int longrc = scsi_device_protection(sdkp->device) ? 1 : 0; | ||
1177 | struct scsi_sense_hdr sshdr; | 1241 | struct scsi_sense_hdr sshdr; |
1178 | int sense_valid = 0; | 1242 | int sense_valid = 0; |
1179 | struct scsi_device *sdp = sdkp->device; | 1243 | struct scsi_device *sdp = sdkp->device; |
@@ -1185,8 +1249,8 @@ repeat: | |||
1185 | memset((void *) cmd, 0, 16); | 1249 | memset((void *) cmd, 0, 16); |
1186 | cmd[0] = SERVICE_ACTION_IN; | 1250 | cmd[0] = SERVICE_ACTION_IN; |
1187 | cmd[1] = SAI_READ_CAPACITY_16; | 1251 | cmd[1] = SAI_READ_CAPACITY_16; |
1188 | cmd[13] = 12; | 1252 | cmd[13] = 13; |
1189 | memset((void *) buffer, 0, 12); | 1253 | memset((void *) buffer, 0, 13); |
1190 | } else { | 1254 | } else { |
1191 | cmd[0] = READ_CAPACITY; | 1255 | cmd[0] = READ_CAPACITY; |
1192 | memset((void *) &cmd[1], 0, 9); | 1256 | memset((void *) &cmd[1], 0, 9); |
@@ -1194,7 +1258,7 @@ repeat: | |||
1194 | } | 1258 | } |
1195 | 1259 | ||
1196 | the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, | 1260 | the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, |
1197 | buffer, longrc ? 12 : 8, &sshdr, | 1261 | buffer, longrc ? 13 : 8, &sshdr, |
1198 | SD_TIMEOUT, SD_MAX_RETRIES); | 1262 | SD_TIMEOUT, SD_MAX_RETRIES); |
1199 | 1263 | ||
1200 | if (media_not_present(sdkp, &sshdr)) | 1264 | if (media_not_present(sdkp, &sshdr)) |
@@ -1269,6 +1333,8 @@ repeat: | |||
1269 | 1333 | ||
1270 | sector_size = (buffer[8] << 24) | | 1334 | sector_size = (buffer[8] << 24) | |
1271 | (buffer[9] << 16) | (buffer[10] << 8) | buffer[11]; | 1335 | (buffer[9] << 16) | (buffer[10] << 8) | buffer[11]; |
1336 | |||
1337 | sd_read_protection_type(sdkp, buffer); | ||
1272 | } | 1338 | } |
1273 | 1339 | ||
1274 | /* Some devices return the total number of sectors, not the | 1340 | /* Some devices return the total number of sectors, not the |
@@ -1530,6 +1596,52 @@ defaults: | |||
1530 | sdkp->DPOFUA = 0; | 1596 | sdkp->DPOFUA = 0; |
1531 | } | 1597 | } |
1532 | 1598 | ||
1599 | /* | ||
1600 | * The ATO bit indicates whether the DIF application tag is available | ||
1601 | * for use by the operating system. | ||
1602 | */ | ||
1603 | void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer) | ||
1604 | { | ||
1605 | int res, offset; | ||
1606 | struct scsi_device *sdp = sdkp->device; | ||
1607 | struct scsi_mode_data data; | ||
1608 | struct scsi_sense_hdr sshdr; | ||
1609 | |||
1610 | if (sdp->type != TYPE_DISK) | ||
1611 | return; | ||
1612 | |||
1613 | if (sdkp->protection_type == 0) | ||
1614 | return; | ||
1615 | |||
1616 | res = scsi_mode_sense(sdp, 1, 0x0a, buffer, 36, SD_TIMEOUT, | ||
1617 | SD_MAX_RETRIES, &data, &sshdr); | ||
1618 | |||
1619 | if (!scsi_status_is_good(res) || !data.header_length || | ||
1620 | data.length < 6) { | ||
1621 | sd_printk(KERN_WARNING, sdkp, | ||
1622 | "getting Control mode page failed, assume no ATO\n"); | ||
1623 | |||
1624 | if (scsi_sense_valid(&sshdr)) | ||
1625 | sd_print_sense_hdr(sdkp, &sshdr); | ||
1626 | |||
1627 | return; | ||
1628 | } | ||
1629 | |||
1630 | offset = data.header_length + data.block_descriptor_length; | ||
1631 | |||
1632 | if ((buffer[offset] & 0x3f) != 0x0a) { | ||
1633 | sd_printk(KERN_ERR, sdkp, "ATO Got wrong page\n"); | ||
1634 | return; | ||
1635 | } | ||
1636 | |||
1637 | if ((buffer[offset + 5] & 0x80) == 0) | ||
1638 | return; | ||
1639 | |||
1640 | sdkp->ATO = 1; | ||
1641 | |||
1642 | return; | ||
1643 | } | ||
1644 | |||
1533 | /** | 1645 | /** |
1534 | * sd_revalidate_disk - called the first time a new disk is seen, | 1646 | * sd_revalidate_disk - called the first time a new disk is seen, |
1535 | * performs disk spin up, read_capacity, etc. | 1647 | * performs disk spin up, read_capacity, etc. |
@@ -1566,6 +1678,7 @@ static int sd_revalidate_disk(struct gendisk *disk) | |||
1566 | sdkp->write_prot = 0; | 1678 | sdkp->write_prot = 0; |
1567 | sdkp->WCE = 0; | 1679 | sdkp->WCE = 0; |
1568 | sdkp->RCD = 0; | 1680 | sdkp->RCD = 0; |
1681 | sdkp->ATO = 0; | ||
1569 | 1682 | ||
1570 | sd_spinup_disk(sdkp); | 1683 | sd_spinup_disk(sdkp); |
1571 | 1684 | ||
@@ -1577,6 +1690,7 @@ static int sd_revalidate_disk(struct gendisk *disk) | |||
1577 | sd_read_capacity(sdkp, buffer); | 1690 | sd_read_capacity(sdkp, buffer); |
1578 | sd_read_write_protect_flag(sdkp, buffer); | 1691 | sd_read_write_protect_flag(sdkp, buffer); |
1579 | sd_read_cache_type(sdkp, buffer); | 1692 | sd_read_cache_type(sdkp, buffer); |
1693 | sd_read_app_tag_own(sdkp, buffer); | ||
1580 | } | 1694 | } |
1581 | 1695 | ||
1582 | /* | 1696 | /* |
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 03a3d45cfa42..86b18d4170fe 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h | |||
@@ -41,7 +41,9 @@ struct scsi_disk { | |||
41 | u32 index; | 41 | u32 index; |
42 | u8 media_present; | 42 | u8 media_present; |
43 | u8 write_prot; | 43 | u8 write_prot; |
44 | u8 protection_type;/* Data Integrity Field */ | ||
44 | unsigned previous_state : 1; | 45 | unsigned previous_state : 1; |
46 | unsigned ATO : 1; /* state of disk ATO bit */ | ||
45 | unsigned WCE : 1; /* state of disk WCE bit */ | 47 | unsigned WCE : 1; /* state of disk WCE bit */ |
46 | unsigned RCD : 1; /* state of disk RCD bit, unused */ | 48 | unsigned RCD : 1; /* state of disk RCD bit, unused */ |
47 | unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ | 49 | unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ |
@@ -59,4 +61,25 @@ static inline struct scsi_disk *scsi_disk(struct gendisk *disk) | |||
59 | (sdsk)->disk->disk_name, ##a) : \ | 61 | (sdsk)->disk->disk_name, ##a) : \ |
60 | sdev_printk(prefix, (sdsk)->device, fmt, ##a) | 62 | sdev_printk(prefix, (sdsk)->device, fmt, ##a) |
61 | 63 | ||
64 | /* | ||
65 | * A DIF-capable target device can be formatted with different | ||
66 | * protection schemes. Currently 0 through 3 are defined: | ||
67 | * | ||
68 | * Type 0 is regular (unprotected) I/O | ||
69 | * | ||
70 | * Type 1 defines the contents of the guard and reference tags | ||
71 | * | ||
72 | * Type 2 defines the contents of the guard and reference tags and | ||
73 | * uses 32-byte commands to seed the latter | ||
74 | * | ||
75 | * Type 3 defines the contents of the guard tag only | ||
76 | */ | ||
77 | |||
78 | enum sd_dif_target_protection_types { | ||
79 | SD_DIF_TYPE0_PROTECTION = 0x0, | ||
80 | SD_DIF_TYPE1_PROTECTION = 0x1, | ||
81 | SD_DIF_TYPE2_PROTECTION = 0x2, | ||
82 | SD_DIF_TYPE3_PROTECTION = 0x3, | ||
83 | }; | ||
84 | |||
62 | #endif /* _SCSI_DISK_H */ | 85 | #endif /* _SCSI_DISK_H */ |