int T0430_report_all_supported_ops(const char *initiator, const char *url, int data_loss, int show_info) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_report_supported_op_codes *rsoc; struct scsi_command_descriptor *desc; int ret, lun, i; int full_size, desc_size; printf("0430_report_all_supported_ops:\n"); printf("===================\n"); if (show_info) { printf("Test MaintenanceIn: Report Supported Operations.\n"); printf("1, Report Supported Ops (no timeout information).\n"); printf("2, Report Supported Ops (with timeout information).\n"); printf("\n"); return 0; } iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } ret = 0; printf("See if Report Supported Opcodes is supported... "); /* See how big data is */ task = iscsi_report_supported_opcodes_sync(iscsi, lun, 0, 4); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send Report Supported Opcodes command : %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_CHECK_CONDITION && task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST && task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) { printf("[SKIPPED]\n"); printf("REPORT SUPPORTED OPCODES command failed : %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); ret = -2; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("REPORT SUPPORTED OPCODES command failed : %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); ret = -1; goto finished; } full_size = scsi_datain_getfullsize(task); if (full_size > task->datain.size) { scsi_free_scsi_task(task); /* we need more data for the full list */ if ((task = iscsi_report_supported_opcodes_sync(iscsi, lun, 0, full_size)) == NULL) { printf("[FAILED]\n"); printf("REPORT SUPPORTED OPCODES failed : %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } } rsoc = scsi_datain_unmarshall(task); if (rsoc == NULL) { printf("[FAILED]\n"); printf("failed to unmarshall REPORT SUPPORTED OPCODES datain blob\n"); scsi_free_scsi_task(task); ret = -1; goto finished; } printf("Supported Commands: %d\n", rsoc->num_descriptors); printf("=======================\n"); for (i=0; i < rsoc->num_descriptors; i++) { printf("op:%x\tsa:%x\tcdb length:%d\n", rsoc->descriptors[i].op_code, rsoc->descriptors[i].service_action, rsoc->descriptors[i].cdb_length); } printf("\n[OK]\n"); scsi_free_scsi_task(task); test2: /*Report All Supported Operations including timeout info.*/ printf("See if Report Supported Opcodes with Timeouts is supported... "); /* See how big data is */ task = iscsi_report_supported_opcodes_sync(iscsi, lun, 1, 4); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send Report Supported Opcodes command : %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_CHECK_CONDITION && task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST && (task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE || task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB)) { printf("[SKIPPED]\n"); printf("REPORT SUPPORTED OPCODES command failed : %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); ret = -2; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("REPORT SUPPORTED OPCODES command failed : %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); ret = -1; goto finished; } full_size = scsi_datain_getfullsize(task); if (full_size > task->datain.size) { scsi_free_scsi_task(task); /* we need more data for the full list */ if ((task = iscsi_report_supported_opcodes_sync(iscsi, lun, 1, full_size)) == NULL) { printf("[FAILED]\n"); printf("REPORT SUPPORTED OPCODES failed : %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } } rsoc = scsi_datain_unmarshall(task); if (rsoc == NULL) { printf("[FAILED]\n"); printf("failed to unmarshall REPORT SUPPORTED OPCODES datain blob\n"); scsi_free_scsi_task(task); ret = -1; goto finished; } printf("Supported Commands (with timeout information): %d\n", rsoc->num_descriptors); printf("=======================\n"); desc_size = sizeof (struct scsi_command_descriptor) + sizeof (struct scsi_op_timeout_descriptor); desc = &rsoc->descriptors[0]; for (i=0; i < rsoc->num_descriptors; i++) { printf("op:%x\tsa:%x\tcdb_length:%d\ttimeout info: length:%d\tcommand specific:%x\tnominal processing%d\trecommended%d\n", desc->op_code, desc->service_action, desc->cdb_length, desc->to[0].descriptor_length, desc->to[0].command_specific, desc->to[0].nominal_processing_timeout, desc->to[0].recommended_timeout); desc = (struct scsi_command_descriptor *)((char *)desc + desc_size); } printf("\n[OK]\n"); scsi_free_scsi_task(task); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; }
int main(int argc, char *argv[]) { char *testname_re = NULL; int lun; CU_BasicRunMode mode = CU_BRM_VERBOSE; CU_ErrorAction error_action = CUEA_IGNORE; int res; struct scsi_readcapacity10 *rc10; struct scsi_task *inq_task = NULL; struct scsi_task *inq_lbp_task = NULL; struct scsi_task *inq_bdc_task = NULL; struct scsi_task *inq_bl_task = NULL; struct scsi_task *rc16_task = NULL; struct scsi_task *rsop_task = NULL; int full_size; int is_usb = 0; int xml_mode = 0; static struct option long_opts[] = { { "help", no_argument, 0, '?' }, { "list", no_argument, 0, 'l' }, { "initiator-name", required_argument, 0, 'i' }, { "initiator-name-2", required_argument, 0, 'I' }, { "test", required_argument, 0, 't' }, { "dataloss", no_argument, 0, 'd' }, { "allow-sanitize", no_argument, 0, 'S' }, { "ignore", no_argument, 0, 'g' }, { "fail", no_argument, 0, 'f' }, { "abort", no_argument, 0, 'A' }, { "silent", no_argument, 0, 's' }, { "normal", no_argument, 0, 'n' }, { "usb", no_argument, 0, 'u' }, { "verbose", no_argument, 0, 'v' }, { "xml", no_argument, 0, 'x' }, { "Verbose-scsi", no_argument, 0, 'V' }, { NULL, 0, 0, 0 } }; int i, c; int opt_idx = 0; while ((c = getopt_long(argc, argv, "?hli:I:t:sdgfAsSnuvxV", long_opts, &opt_idx)) > 0) { switch (c) { case 'h': case '?': print_usage(); return 0; case 'l': list_all_tests(); return 0; case 'i': initiatorname1 = strdup(optarg); break; case 'I': initiatorname2 = strdup(optarg); break; case 't': testname_re = strdup(optarg); break; case 'd': data_loss++; break; case 'g': error_action = CUEA_IGNORE; /* default */ break; case 'f': error_action = CUEA_FAIL; break; case 'A': error_action = CUEA_ABORT; break; case 's': mode = CU_BRM_SILENT; break; case 'S': allow_sanitize = 1; break; case 'n': mode = CU_BRM_NORMAL; break; case 'u': is_usb = 1; break; case 'v': mode = CU_BRM_VERBOSE; /* default */ break; case 'x': xml_mode = 1; break; case 'V': loglevel = LOG_VERBOSE; break; default: fprintf(stderr, "error: unknown option return: %c (option %s)\n", c, argv[optind]); return 1; } } if (optind < argc) { tgt_url = strdup(argv[optind++]); } if (optind < argc) { fprintf(stderr, "error: too many arguments\n"); print_usage(); return 1; } /* XXX why is this done? */ real_iscsi_queue_pdu = dlsym(RTLD_NEXT, "iscsi_queue_pdu"); if (tgt_url == NULL) { fprintf(stderr, "You must specify the URL\n"); print_usage(); if (testname_re) free(testname_re); return 10; } iscsic = iscsi_context_login(initiatorname1, tgt_url, &lun); if (iscsic == NULL) { printf("Failed to login to target\n"); return -1; } /* * find the size of the LUN * All devices support readcapacity10 but only some support * readcapacity16 */ task = iscsi_readcapacity10_sync(iscsic, lun, 0, 0); if (task == NULL) { printf("Failed to send READCAPACITY10 command: %s\n", iscsi_get_error(iscsic)); iscsi_destroy_context(iscsic); return -1; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY10 command: failed with sense. %s\n", iscsi_get_error(iscsic)); scsi_free_scsi_task(task); iscsi_destroy_context(iscsic); return -1; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall READCAPACITY10 data. %s\n", iscsi_get_error(iscsic)); scsi_free_scsi_task(task); iscsi_destroy_context(iscsic); return -1; } block_size = rc10->block_size; num_blocks = rc10->lba + 1; scsi_free_scsi_task(task); rc16_task = iscsi_readcapacity16_sync(iscsic, lun); if (rc16_task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsic)); iscsi_destroy_context(iscsic); return -1; } if (rc16_task->status == SCSI_STATUS_GOOD) { rc16 = scsi_datain_unmarshall(rc16_task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsic)); scsi_free_scsi_task(rc16_task); iscsi_destroy_context(iscsic); return -1; } block_size = rc16->block_length; num_blocks = rc16->returned_lba + 1; lbppb = 1 << rc16->lbppbe; } inq_task = iscsi_inquiry_sync(iscsic, lun, 0, 0, 64); if (inq_task == NULL || inq_task->status != SCSI_STATUS_GOOD) { printf("Inquiry command failed : %s\n", iscsi_get_error(iscsic)); return -1; } full_size = scsi_datain_getfullsize(inq_task); if (full_size > inq_task->datain.size) { scsi_free_scsi_task(inq_task); /* we need more data for the full list */ inq_task = iscsi_inquiry_sync(iscsic, lun, 0, 0, full_size); if (inq_task == NULL) { printf("Inquiry command failed : %s\n", iscsi_get_error(iscsic)); return -1; } } inq = scsi_datain_unmarshall(inq_task); if (inq == NULL) { printf("failed to unmarshall inquiry datain blob\n"); scsi_free_scsi_task(inq_task); return -1; } sbc3_support = 0; for (i = 0; i < 8; i++) { if (inq->version_descriptor[i] == 0x04C0) { sbc3_support = 1; } } /* try reading block limits vpd */ inq_bl_task = iscsi_inquiry_sync(iscsic, lun, 1, SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS, 64); if (inq_bl_task && inq_bl_task->status != SCSI_STATUS_GOOD) { scsi_free_scsi_task(inq_bl_task); inq_bl_task = NULL; } if (inq_bl_task) { full_size = scsi_datain_getfullsize(inq_bl_task); if (full_size > inq_bl_task->datain.size) { scsi_free_scsi_task(inq_bl_task); if ((inq_bl_task = iscsi_inquiry_sync(iscsic, lun, 1, SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS, full_size)) == NULL) { printf("Inquiry command failed : %s\n", iscsi_get_error(iscsic)); return -1; } } inq_bl = scsi_datain_unmarshall(inq_bl_task); if (inq_bl == NULL) { printf("failed to unmarshall inquiry datain blob\n"); return -1; } } /* try reading block device characteristics vpd */ inq_bdc_task = iscsi_inquiry_sync(iscsic, lun, 1, SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS, 255); if (inq_bdc_task == NULL) { printf("Failed to read Block Device Characteristics page\n"); } if (inq_bdc_task) { inq_bdc = scsi_datain_unmarshall(inq_bdc_task); if (inq_bdc == NULL) { printf("failed to unmarshall inquiry datain blob\n"); return -1; } } /* if thin provisioned we also need to read the VPD page for it */ if (rc16 && rc16->lbpme != 0){ inq_lbp_task = iscsi_inquiry_sync(iscsic, lun, 1, SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING, 64); if (inq_lbp_task == NULL || inq_lbp_task->status != SCSI_STATUS_GOOD) { printf("Inquiry command failed : %s\n", iscsi_get_error(iscsic)); return -1; } full_size = scsi_datain_getfullsize(inq_lbp_task); if (full_size > inq_lbp_task->datain.size) { scsi_free_scsi_task(inq_lbp_task); /* we need more data for the full list */ if ((inq_lbp_task = iscsi_inquiry_sync(iscsic, lun, 1, SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING, full_size)) == NULL) { printf("Inquiry command failed : %s\n", iscsi_get_error(iscsic)); return -1; } } inq_lbp = scsi_datain_unmarshall(inq_lbp_task); if (inq_lbp == NULL) { printf("failed to unmarshall inquiry datain blob\n"); return -1; } } rsop_task = iscsi_report_supported_opcodes_sync(iscsic, lun, 1, SCSI_REPORT_SUPPORTING_OPS_ALL, 0, 0, 65535); if (rsop_task == NULL) { printf("Failed to send REPORT_SUPPORTED_OPCODES command: %s\n", iscsi_get_error(iscsic)); iscsi_destroy_context(iscsic); return -1; } if (rsop_task->status == SCSI_STATUS_GOOD) { rsop = scsi_datain_unmarshall(rsop_task); if (rsop == NULL) { printf("failed to unmarshall REPORT_SUPPORTED_OPCODES " "data. %s\n", iscsi_get_error(iscsic)); scsi_free_scsi_task(rsop_task); } } /* check if the device is write protected or not */ task = iscsi_modesense6_sync(iscsic, lun, 0, SCSI_MODESENSE_PC_CURRENT, SCSI_MODEPAGE_RETURN_ALL_PAGES, 0, 255); if (task == NULL) { printf("Failed to send MODE_SENSE6 command: %s\n", iscsi_get_error(iscsic)); iscsi_destroy_context(iscsic); return -1; } if (task->status == SCSI_STATUS_GOOD) { struct scsi_mode_sense *ms; ms = scsi_datain_unmarshall(task); if (ms == NULL) { printf("failed to unmarshall mode sense datain blob\n"); scsi_free_scsi_task(task); return -1; } readonly = !!(ms->device_specific_parameter & 0x80); } scsi_free_scsi_task(task); iscsi_logout_sync(iscsic); iscsi_destroy_context(iscsic); if (is_usb) { printf("USB device. Clamping maximum transfer length to 120k\n"); maximum_transfer_length = 120 *1024 / block_size; } if (CU_initialize_registry() != 0) { fprintf(stderr, "error: unable to initialize test registry\n"); return 1; } if (CU_is_test_running()) { fprintf(stderr, "error: test suite(s) already running!?\n"); exit(1); } parse_and_add_tests(testname_re); if (testname_re) free(testname_re); CU_basic_set_mode(mode); CU_set_error_action(error_action); printf("\n"); /* * this actually runs the tests ... */ if (xml_mode) { CU_list_tests_to_file(); CU_automated_run_tests(); } else { res = CU_basic_run_tests(); printf("Tests completed with return value: %d\n", res); } CU_cleanup_registry(); free(discard_const(tgt_url)); if (inq_task != NULL) { scsi_free_scsi_task(inq_task); } if (inq_bl_task != NULL) { scsi_free_scsi_task(inq_bl_task); } if (inq_lbp_task != NULL) { scsi_free_scsi_task(inq_lbp_task); } if (inq_bdc_task != NULL) { scsi_free_scsi_task(inq_bdc_task); } if (rc16_task != NULL) { scsi_free_scsi_task(rc16_task); } if (rsop_task != NULL) { scsi_free_scsi_task(rsop_task); } return 0; }