diff options
-rw-r--r-- | drivers/scsi/scsi_debug.c | 141 | ||||
-rw-r--r-- | include/scsi/scsi.h | 3 |
2 files changed, 130 insertions, 14 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 9c0f35820e3e..30ee3d72c021 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
@@ -52,7 +52,7 @@ | |||
52 | #include "scsi_debug.h" | 52 | #include "scsi_debug.h" |
53 | 53 | ||
54 | #define SCSI_DEBUG_VERSION "1.80" | 54 | #define SCSI_DEBUG_VERSION "1.80" |
55 | static const char * scsi_debug_version_date = "20060914"; | 55 | static const char * scsi_debug_version_date = "20061018"; |
56 | 56 | ||
57 | /* Additional Sense Code (ASC) used */ | 57 | /* Additional Sense Code (ASC) used */ |
58 | #define NO_ADDITIONAL_SENSE 0x0 | 58 | #define NO_ADDITIONAL_SENSE 0x0 |
@@ -254,6 +254,8 @@ static int resp_requests(struct scsi_cmnd * SCpnt, | |||
254 | struct sdebug_dev_info * devip); | 254 | struct sdebug_dev_info * devip); |
255 | static int resp_start_stop(struct scsi_cmnd * scp, | 255 | static int resp_start_stop(struct scsi_cmnd * scp, |
256 | struct sdebug_dev_info * devip); | 256 | struct sdebug_dev_info * devip); |
257 | static int resp_report_tgtpgs(struct scsi_cmnd * scp, | ||
258 | struct sdebug_dev_info * devip); | ||
257 | static int resp_readcap(struct scsi_cmnd * SCpnt, | 259 | static int resp_readcap(struct scsi_cmnd * SCpnt, |
258 | struct sdebug_dev_info * devip); | 260 | struct sdebug_dev_info * devip); |
259 | static int resp_readcap16(struct scsi_cmnd * SCpnt, | 261 | static int resp_readcap16(struct scsi_cmnd * SCpnt, |
@@ -287,9 +289,9 @@ static void __init sdebug_build_parts(unsigned char * ramp); | |||
287 | static void __init init_all_queued(void); | 289 | static void __init init_all_queued(void); |
288 | static void stop_all_queued(void); | 290 | static void stop_all_queued(void); |
289 | static int stop_queued_cmnd(struct scsi_cmnd * cmnd); | 291 | static int stop_queued_cmnd(struct scsi_cmnd * cmnd); |
290 | static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, | 292 | static int inquiry_evpd_83(unsigned char * arr, int port_group_id, |
291 | int dev_id_num, const char * dev_id_str, | 293 | int target_dev_id, int dev_id_num, |
292 | int dev_id_str_len); | 294 | const char * dev_id_str, int dev_id_str_len); |
293 | static int inquiry_evpd_88(unsigned char * arr, int target_dev_id); | 295 | static int inquiry_evpd_88(unsigned char * arr, int target_dev_id); |
294 | static int do_create_driverfs_files(void); | 296 | static int do_create_driverfs_files(void); |
295 | static void do_remove_driverfs_files(void); | 297 | static void do_remove_driverfs_files(void); |
@@ -422,6 +424,15 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) | |||
422 | } | 424 | } |
423 | errsts = resp_readcap16(SCpnt, devip); | 425 | errsts = resp_readcap16(SCpnt, devip); |
424 | break; | 426 | break; |
427 | case MAINTENANCE_IN: | ||
428 | if (MI_REPORT_TARGET_PGS != cmd[1]) { | ||
429 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | ||
430 | INVALID_OPCODE, 0); | ||
431 | errsts = check_condition_result; | ||
432 | break; | ||
433 | } | ||
434 | errsts = resp_report_tgtpgs(SCpnt, devip); | ||
435 | break; | ||
425 | case READ_16: | 436 | case READ_16: |
426 | case READ_12: | 437 | case READ_12: |
427 | case READ_10: | 438 | case READ_10: |
@@ -665,8 +676,9 @@ static const char * inq_vendor_id = "Linux "; | |||
665 | static const char * inq_product_id = "scsi_debug "; | 676 | static const char * inq_product_id = "scsi_debug "; |
666 | static const char * inq_product_rev = "0004"; | 677 | static const char * inq_product_rev = "0004"; |
667 | 678 | ||
668 | static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, | 679 | static int inquiry_evpd_83(unsigned char * arr, int port_group_id, |
669 | int dev_id_num, const char * dev_id_str, | 680 | int target_dev_id, int dev_id_num, |
681 | const char * dev_id_str, | ||
670 | int dev_id_str_len) | 682 | int dev_id_str_len) |
671 | { | 683 | { |
672 | int num, port_a; | 684 | int num, port_a; |
@@ -720,6 +732,15 @@ static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, | |||
720 | arr[num++] = (port_a >> 16) & 0xff; | 732 | arr[num++] = (port_a >> 16) & 0xff; |
721 | arr[num++] = (port_a >> 8) & 0xff; | 733 | arr[num++] = (port_a >> 8) & 0xff; |
722 | arr[num++] = port_a & 0xff; | 734 | arr[num++] = port_a & 0xff; |
735 | /* NAA-5, Target port group identifier */ | ||
736 | arr[num++] = 0x61; /* proto=sas, binary */ | ||
737 | arr[num++] = 0x95; /* piv=1, target port group id */ | ||
738 | arr[num++] = 0x0; | ||
739 | arr[num++] = 0x4; | ||
740 | arr[num++] = 0; | ||
741 | arr[num++] = 0; | ||
742 | arr[num++] = (port_group_id >> 8) & 0xff; | ||
743 | arr[num++] = port_group_id & 0xff; | ||
723 | /* NAA-5, Target device identifier */ | 744 | /* NAA-5, Target device identifier */ |
724 | arr[num++] = 0x61; /* proto=sas, binary */ | 745 | arr[num++] = 0x61; /* proto=sas, binary */ |
725 | arr[num++] = 0xa3; /* piv=1, target device, naa */ | 746 | arr[num++] = 0xa3; /* piv=1, target device, naa */ |
@@ -928,12 +949,12 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
928 | struct sdebug_dev_info * devip) | 949 | struct sdebug_dev_info * devip) |
929 | { | 950 | { |
930 | unsigned char pq_pdt; | 951 | unsigned char pq_pdt; |
931 | unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ]; | 952 | unsigned char * arr; |
932 | unsigned char *cmd = (unsigned char *)scp->cmnd; | 953 | unsigned char *cmd = (unsigned char *)scp->cmnd; |
933 | int alloc_len, n; | 954 | int alloc_len, n, ret; |
934 | 955 | ||
935 | alloc_len = (cmd[3] << 8) + cmd[4]; | 956 | alloc_len = (cmd[3] << 8) + cmd[4]; |
936 | memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ); | 957 | arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_KERNEL); |
937 | if (devip->wlun) | 958 | if (devip->wlun) |
938 | pq_pdt = 0x1e; /* present, wlun */ | 959 | pq_pdt = 0x1e; /* present, wlun */ |
939 | else if (scsi_debug_no_lun_0 && (0 == devip->lun)) | 960 | else if (scsi_debug_no_lun_0 && (0 == devip->lun)) |
@@ -944,12 +965,15 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
944 | if (0x2 & cmd[1]) { /* CMDDT bit set */ | 965 | if (0x2 & cmd[1]) { /* CMDDT bit set */ |
945 | mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, | 966 | mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, |
946 | 0); | 967 | 0); |
968 | kfree(arr); | ||
947 | return check_condition_result; | 969 | return check_condition_result; |
948 | } else if (0x1 & cmd[1]) { /* EVPD bit set */ | 970 | } else if (0x1 & cmd[1]) { /* EVPD bit set */ |
949 | int lu_id_num, target_dev_id, len; | 971 | int lu_id_num, port_group_id, target_dev_id, len; |
950 | char lu_id_str[6]; | 972 | char lu_id_str[6]; |
951 | int host_no = devip->sdbg_host->shost->host_no; | 973 | int host_no = devip->sdbg_host->shost->host_no; |
952 | 974 | ||
975 | port_group_id = (((host_no + 1) & 0x7f) << 8) + | ||
976 | (devip->channel & 0x7f); | ||
953 | if (0 == scsi_debug_vpd_use_hostno) | 977 | if (0 == scsi_debug_vpd_use_hostno) |
954 | host_no = 0; | 978 | host_no = 0; |
955 | lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + | 979 | lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + |
@@ -977,8 +1001,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
977 | memcpy(&arr[4], lu_id_str, len); | 1001 | memcpy(&arr[4], lu_id_str, len); |
978 | } else if (0x83 == cmd[2]) { /* device identification */ | 1002 | } else if (0x83 == cmd[2]) { /* device identification */ |
979 | arr[1] = cmd[2]; /*sanity */ | 1003 | arr[1] = cmd[2]; /*sanity */ |
980 | arr[3] = inquiry_evpd_83(&arr[4], target_dev_id, | 1004 | arr[3] = inquiry_evpd_83(&arr[4], port_group_id, |
981 | lu_id_num, lu_id_str, len); | 1005 | target_dev_id, lu_id_num, |
1006 | lu_id_str, len); | ||
982 | } else if (0x84 == cmd[2]) { /* Software interface ident. */ | 1007 | } else if (0x84 == cmd[2]) { /* Software interface ident. */ |
983 | arr[1] = cmd[2]; /*sanity */ | 1008 | arr[1] = cmd[2]; /*sanity */ |
984 | arr[3] = inquiry_evpd_84(&arr[4]); | 1009 | arr[3] = inquiry_evpd_84(&arr[4]); |
@@ -1012,17 +1037,22 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
1012 | /* Illegal request, invalid field in cdb */ | 1037 | /* Illegal request, invalid field in cdb */ |
1013 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | 1038 | mk_sense_buffer(devip, ILLEGAL_REQUEST, |
1014 | INVALID_FIELD_IN_CDB, 0); | 1039 | INVALID_FIELD_IN_CDB, 0); |
1040 | kfree(arr); | ||
1015 | return check_condition_result; | 1041 | return check_condition_result; |
1016 | } | 1042 | } |
1017 | len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); | 1043 | len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); |
1018 | return fill_from_dev_buffer(scp, arr, | 1044 | ret = fill_from_dev_buffer(scp, arr, |
1019 | min(len, SDEBUG_MAX_INQ_ARR_SZ)); | 1045 | min(len, SDEBUG_MAX_INQ_ARR_SZ)); |
1046 | kfree(arr); | ||
1047 | return ret; | ||
1020 | } | 1048 | } |
1021 | /* drops through here for a standard inquiry */ | 1049 | /* drops through here for a standard inquiry */ |
1022 | arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ | 1050 | arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ |
1023 | arr[2] = scsi_debug_scsi_level; | 1051 | arr[2] = scsi_debug_scsi_level; |
1024 | arr[3] = 2; /* response_data_format==2 */ | 1052 | arr[3] = 2; /* response_data_format==2 */ |
1025 | arr[4] = SDEBUG_LONG_INQ_SZ - 5; | 1053 | arr[4] = SDEBUG_LONG_INQ_SZ - 5; |
1054 | if (0 == scsi_debug_vpd_use_hostno) | ||
1055 | arr[5] = 0x10; /* claim: implicit TGPS */ | ||
1026 | arr[6] = 0x10; /* claim: MultiP */ | 1056 | arr[6] = 0x10; /* claim: MultiP */ |
1027 | /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ | 1057 | /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ |
1028 | arr[7] = 0xa; /* claim: LINKED + CMDQUE */ | 1058 | arr[7] = 0xa; /* claim: LINKED + CMDQUE */ |
@@ -1039,8 +1069,10 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
1039 | arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ | 1069 | arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ |
1040 | } | 1070 | } |
1041 | arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ | 1071 | arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ |
1042 | return fill_from_dev_buffer(scp, arr, | 1072 | ret = fill_from_dev_buffer(scp, arr, |
1043 | min(alloc_len, SDEBUG_LONG_INQ_SZ)); | 1073 | min(alloc_len, SDEBUG_LONG_INQ_SZ)); |
1074 | kfree(arr); | ||
1075 | return ret; | ||
1044 | } | 1076 | } |
1045 | 1077 | ||
1046 | static int resp_requests(struct scsi_cmnd * scp, | 1078 | static int resp_requests(struct scsi_cmnd * scp, |
@@ -1171,6 +1203,87 @@ static int resp_readcap16(struct scsi_cmnd * scp, | |||
1171 | min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); | 1203 | min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); |
1172 | } | 1204 | } |
1173 | 1205 | ||
1206 | #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 | ||
1207 | |||
1208 | static int resp_report_tgtpgs(struct scsi_cmnd * scp, | ||
1209 | struct sdebug_dev_info * devip) | ||
1210 | { | ||
1211 | unsigned char *cmd = (unsigned char *)scp->cmnd; | ||
1212 | unsigned char * arr; | ||
1213 | int host_no = devip->sdbg_host->shost->host_no; | ||
1214 | int n, ret, alen, rlen; | ||
1215 | int port_group_a, port_group_b, port_a, port_b; | ||
1216 | |||
1217 | alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) | ||
1218 | + cmd[9]); | ||
1219 | |||
1220 | arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_KERNEL); | ||
1221 | /* | ||
1222 | * EVPD page 0x88 states we have two ports, one | ||
1223 | * real and a fake port with no device connected. | ||
1224 | * So we create two port groups with one port each | ||
1225 | * and set the group with port B to unavailable. | ||
1226 | */ | ||
1227 | port_a = 0x1; /* relative port A */ | ||
1228 | port_b = 0x2; /* relative port B */ | ||
1229 | port_group_a = (((host_no + 1) & 0x7f) << 8) + | ||
1230 | (devip->channel & 0x7f); | ||
1231 | port_group_b = (((host_no + 1) & 0x7f) << 8) + | ||
1232 | (devip->channel & 0x7f) + 0x80; | ||
1233 | |||
1234 | /* | ||
1235 | * The asymmetric access state is cycled according to the host_id. | ||
1236 | */ | ||
1237 | n = 4; | ||
1238 | if (0 == scsi_debug_vpd_use_hostno) { | ||
1239 | arr[n++] = host_no % 3; /* Asymm access state */ | ||
1240 | arr[n++] = 0x0F; /* claim: all states are supported */ | ||
1241 | } else { | ||
1242 | arr[n++] = 0x0; /* Active/Optimized path */ | ||
1243 | arr[n++] = 0x01; /* claim: only support active/optimized paths */ | ||
1244 | } | ||
1245 | arr[n++] = (port_group_a >> 8) & 0xff; | ||
1246 | arr[n++] = port_group_a & 0xff; | ||
1247 | arr[n++] = 0; /* Reserved */ | ||
1248 | arr[n++] = 0; /* Status code */ | ||
1249 | arr[n++] = 0; /* Vendor unique */ | ||
1250 | arr[n++] = 0x1; /* One port per group */ | ||
1251 | arr[n++] = 0; /* Reserved */ | ||
1252 | arr[n++] = 0; /* Reserved */ | ||
1253 | arr[n++] = (port_a >> 8) & 0xff; | ||
1254 | arr[n++] = port_a & 0xff; | ||
1255 | arr[n++] = 3; /* Port unavailable */ | ||
1256 | arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ | ||
1257 | arr[n++] = (port_group_b >> 8) & 0xff; | ||
1258 | arr[n++] = port_group_b & 0xff; | ||
1259 | arr[n++] = 0; /* Reserved */ | ||
1260 | arr[n++] = 0; /* Status code */ | ||
1261 | arr[n++] = 0; /* Vendor unique */ | ||
1262 | arr[n++] = 0x1; /* One port per group */ | ||
1263 | arr[n++] = 0; /* Reserved */ | ||
1264 | arr[n++] = 0; /* Reserved */ | ||
1265 | arr[n++] = (port_b >> 8) & 0xff; | ||
1266 | arr[n++] = port_b & 0xff; | ||
1267 | |||
1268 | rlen = n - 4; | ||
1269 | arr[0] = (rlen >> 24) & 0xff; | ||
1270 | arr[1] = (rlen >> 16) & 0xff; | ||
1271 | arr[2] = (rlen >> 8) & 0xff; | ||
1272 | arr[3] = rlen & 0xff; | ||
1273 | |||
1274 | /* | ||
1275 | * Return the smallest value of either | ||
1276 | * - The allocated length | ||
1277 | * - The constructed command length | ||
1278 | * - The maximum array size | ||
1279 | */ | ||
1280 | rlen = min(alen,n); | ||
1281 | ret = fill_from_dev_buffer(scp, arr, | ||
1282 | min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); | ||
1283 | kfree(arr); | ||
1284 | return ret; | ||
1285 | } | ||
1286 | |||
1174 | /* <<Following mode page info copied from ST318451LW>> */ | 1287 | /* <<Following mode page info copied from ST318451LW>> */ |
1175 | 1288 | ||
1176 | static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) | 1289 | static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) |
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 84a6d5fe0920..8a3f0bd0d45a 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h | |||
@@ -97,6 +97,7 @@ extern const unsigned char scsi_command_size[8]; | |||
97 | #define PERSISTENT_RESERVE_IN 0x5e | 97 | #define PERSISTENT_RESERVE_IN 0x5e |
98 | #define PERSISTENT_RESERVE_OUT 0x5f | 98 | #define PERSISTENT_RESERVE_OUT 0x5f |
99 | #define REPORT_LUNS 0xa0 | 99 | #define REPORT_LUNS 0xa0 |
100 | #define MAINTENANCE_IN 0xa3 | ||
100 | #define MOVE_MEDIUM 0xa5 | 101 | #define MOVE_MEDIUM 0xa5 |
101 | #define EXCHANGE_MEDIUM 0xa6 | 102 | #define EXCHANGE_MEDIUM 0xa6 |
102 | #define READ_12 0xa8 | 103 | #define READ_12 0xa8 |
@@ -114,6 +115,8 @@ extern const unsigned char scsi_command_size[8]; | |||
114 | #define SERVICE_ACTION_IN 0x9e | 115 | #define SERVICE_ACTION_IN 0x9e |
115 | /* values for service action in */ | 116 | /* values for service action in */ |
116 | #define SAI_READ_CAPACITY_16 0x10 | 117 | #define SAI_READ_CAPACITY_16 0x10 |
118 | /* values for maintenance in */ | ||
119 | #define MI_REPORT_TARGET_PGS 0x0a | ||
117 | 120 | ||
118 | /* Values for T10/04-262r7 */ | 121 | /* Values for T10/04-262r7 */ |
119 | #define ATA_16 0x85 /* 16-byte pass-thru */ | 122 | #define ATA_16 0x85 /* 16-byte pass-thru */ |