void readcapacity10_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; struct scsi_task *task = command_data; struct scsi_readcapacity10 *rc10; int full_size; if (status == ISCSI_STATUS_CHECK_CONDITION) { printf("Readcapacity10 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); exit(10); } full_size = scsi_datain_getfullsize(task); if (full_size < task->datain.size) { printf("not enough data for full size readcapacity10\n"); exit(10); } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall readcapacity10 data\n"); exit(10); } clnt->block_size = rc10->block_size; printf("READCAPACITY10 successful. Size:%d blocks blocksize:%d. Read first block\n", rc10->lba, rc10->block_size); free(rc10); if (iscsi_read10_async(iscsi, clnt->lun, read10_cb, 0, clnt->block_size, clnt->block_size, private_data) != 0) { printf("failed to send read10 command\n"); exit(10); } }
void list_luns(const char *target, const char *portal) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_reportluns_list *list; int full_report_size; int i; iscsi = iscsi_create_context(initiator); if (iscsi == NULL) { printf("Failed to create context\n"); exit(10); } if (iscsi_set_targetname(iscsi, target)) { fprintf(stderr, "Failed to set target name\n"); exit(10); } iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL); iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); if (iscsi_connect_sync(iscsi, portal) != 0) { printf("iscsi_connect failed. %s\n", iscsi_get_error(iscsi)); exit(10); } if (iscsi_login_sync(iscsi) != 0) { fprintf(stderr, "login failed :%s\n", iscsi_get_error(iscsi)); exit(10); } /* get initial reportluns data, all targets can report 16 bytes but some * fail if we ask for too much. */ if ((task = iscsi_reportluns_sync(iscsi, 0, 16)) == NULL) { fprintf(stderr, "reportluns failed : %s\n", iscsi_get_error(iscsi)); exit(10); } full_report_size = scsi_datain_getfullsize(task); if (full_report_size > task->datain.size) { scsi_free_scsi_task(task); /* we need more data for the full list */ if ((task = iscsi_reportluns_sync(iscsi, 0, full_report_size)) == NULL) { fprintf(stderr, "reportluns failed : %s\n", iscsi_get_error(iscsi)); exit(10); } } list = scsi_datain_unmarshall(task); if (list == NULL) { fprintf(stderr, "failed to unmarshall reportluns datain blob\n"); exit(10); } for (i=0; i < (int)list->num; i++) { show_lun(iscsi, list->luns[i]); } scsi_free_scsi_task(task); iscsi_destroy_context(iscsi); }
void modesense6_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; struct scsi_task *task = command_data; int full_size; if (status == ISCSI_STATUS_CHECK_CONDITION) { printf("Modesense6 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); exit(10); } full_size = scsi_datain_getfullsize(task); if (full_size > task->datain.size) { printf("did not get enough data for mode sense, sening modesense again asking for bigger buffer\n"); if (iscsi_modesense6_async(iscsi, clnt->lun, modesense6_cb, 0, SCSI_MODESENSE_PC_CURRENT, SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, 0, full_size, private_data) != 0) { printf("failed to send modesense6 command\n"); exit(10); } return; } printf("MODESENSE6 successful.\n"); printf("Send READCAPACITY10\n"); if (iscsi_readcapacity10_async(iscsi, clnt->lun, readcapacity10_cb, 0, 0, private_data) != 0) { printf("failed to send readcapacity command\n"); exit(10); } }
void do_inquiry(struct iscsi_context *iscsi, int lun, int evpd, int pc) { struct scsi_task *task; int full_size; void *inq; /* See how big this inquiry data is */ task = iscsi_inquiry_sync(iscsi, lun, evpd, pc, 64); if (task == NULL || task->status != SCSI_STATUS_GOOD) { fprintf(stderr, "Inquiry command failed : %s\n", iscsi_get_error(iscsi)); exit(10); } 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_inquiry_sync(iscsi, lun, evpd, pc, full_size)) == NULL) { fprintf(stderr, "Inquiry command failed : %s\n", iscsi_get_error(iscsi)); exit(10); } } inq = scsi_datain_unmarshall(task); if (inq == NULL) { fprintf(stderr, "failed to unmarshall inquiry datain blob\n"); exit(10); } if (evpd == 0) { inquiry_standard(inq); } else { switch (pc) { case SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES: inquiry_supported_pages(inq); break; case SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER: inquiry_unit_serial_number(inq); break; case SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION: inquiry_device_identification(inq); break; case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS: inquiry_block_limits(inq); break; case SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS: inquiry_block_device_characteristics(inq); break; case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING: inquiry_logical_block_provisioning(inq); break; default: fprintf(stderr, "Usupported pagecode:0x%02x\n", pc); } } scsi_free_scsi_task(task); }
void reportluns_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; struct scsi_task *task = command_data; struct scsi_reportluns_list *list; uint32_t full_report_size; int i; if (status != ISCSI_STATUS_GOOD) { printf("Reportluns failed with unknown status code :%d\n", status); return; } full_report_size = scsi_datain_getfullsize(task); printf("REPORTLUNS status:%d data size:%d, full reports luns data size:%d\n", status, task->datain.size, full_report_size); if (full_report_size > task->datain.size) { printf("We did not get all the data we need in reportluns, ask again\n"); if (iscsi_reportluns_async(iscsi, reportluns_cb, 0, full_report_size, private_data) != 0) { printf("failed to send reportluns command\n"); exit(10); } return; } list = scsi_datain_unmarshall(task); if (list == NULL) { printf("failed to unmarshall reportluns datain blob\n"); exit(10); } for (i=0; i < list->num; i++) { printf("LUN:%d found\n", list->luns[i]); clnt->lun = list->luns[i]; } printf("Will use LUN:%d\n", clnt->lun); printf("Send testunitready to lun %d\n", clnt->lun); if (iscsi_testunitready_async(iscsi, clnt->lun, testunitready_cb, private_data) != 0) { printf("failed to send testunitready command\n"); exit(10); } }
int T0300_readonly(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_mode_sense *ms; int ret, lun; unsigned char data[4096]; struct unmap_list list[1]; int full_size; ret = -1; printf("0300_readonly:\n"); printf("==============\n"); if (show_info) { printf("Test that all commands that modify the medium fail for readonly devices\n"); printf("1, WRITE10 at LUN 0 should fail.\n"); printf("2, WRITE12 at LUN 0 should fail.\n"); printf("3, WRITE16 at LUN 0 should fail.\n"); printf("4, WRITESAME10 at LUN 0 should fail.\n"); printf("5, WRITESAME16 at LUN 0 should fail.\n"); printf("6, WRITESAME10 with UNMAP at LUN 0 should fail (skipped if not thin-provisioned).\n"); printf("7, WRITESAME16 with UNMAP at LUN 0 should fail (skipped if not thin-provisioned).\n"); printf("8, UNMAP at LUN 0 should fail (skipped if not thin-provisioned).\n"); printf("9, WRITEVERIFY10 at LUN 0 should fail.\n"); printf("10, WRITEVERIFY12 at LUN 0 should fail.\n"); printf("11, WRITEVERIFY16 at LUN 0 should fail.\n"); printf("12, COMPAREANDWRITE at LUN 0 should fail.\n"); printf("13, ORWRITE at LUN 0 should fail.\n"); printf("\n"); return 0; } iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -2; goto finished; } /* This test is only valid for SBC devices */ if (device_type != SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { printf("LUN is not SBC device. Skipping test\n"); return -2; } /* verify the device is readonly */ task = iscsi_modesense6_sync(iscsi, lun, 0, SCSI_MODESENSE_PC_CURRENT, SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, 0, 4); if (task == NULL) { printf("Failed to send modesense6 command: %s\n", iscsi_get_error(iscsi)); goto finished; } full_size = scsi_datain_getfullsize(task); if (full_size > task->datain.size) { scsi_free_scsi_task(task); task = iscsi_modesense6_sync(iscsi, lun, 0, SCSI_MODESENSE_PC_CURRENT, SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, 0, full_size); if (task == NULL) { printf("Failed to send modesense6 command: %s\n", iscsi_get_error(iscsi)); goto finished; } } ms = scsi_datain_unmarshall(task); if (ms == NULL) { printf("failed to unmarshall mode sense datain blob\n"); scsi_free_scsi_task(task); goto finished; } if (!(ms->device_specific_parameter & 0x80)) { printf("Device is not read-only. Skipping test\n"); ret = -2; goto finished; } scsi_free_scsi_task(task); ret = 0; /* Write one block at lba 0 */ printf("WRITE10 to LUN 0 ... "); task = iscsi_write10_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITE10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITE10 command should fail when writing to readonly devices\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_DATA_PROTECTION || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { printf("[FAILED]\n"); printf("WRITE10 failed with the wrong sense code. Should fail with DATA_PROTECTION/WRITE_PROTECTED\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Write one block at lba 0 */ printf("WRITE12 to LUN 0 ... "); task = iscsi_write12_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITE12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITE12 command should fail when writing to readonly devices\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_DATA_PROTECTION || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { printf("[FAILED]\n"); printf("WRITE12 failed with the wrong sense code. Should fail with DATA_PROTECTION/WRITE_PROTECTED\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Write one block at lba 0 */ printf("WRITE16 to LUN 0 ... "); task = iscsi_write16_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITE16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITE16 command should fail when writing to readonly devices\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_DATA_PROTECTION || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { printf("[FAILED]\n"); printf("WRITE16 failed with the wrong sense code. Should fail with DATA_PROTECTION/WRITE_PROTECTED\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Write one block at lba 0 */ printf("WRITESAME10 to LUN 0 ... "); task = iscsi_writesame10_sync(iscsi, lun, data, block_size, 0, 1, 0, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITESAME10 command should fail when writing to readonly devices\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_DATA_PROTECTION || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { printf("[FAILED]\n"); printf("WRITESAME10 failed with the wrong sense code. Should fail with DATA_PROTECTION/WRITE_PROTECTED\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Write one block at lba 0 */ printf("WRITESAME16 to LUN 0 ... "); task = iscsi_writesame16_sync(iscsi, lun, data, block_size, 0, 1, 0, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITESAME16 command should fail when writing to readonly devices\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_DATA_PROTECTION || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { printf("[FAILED]\n"); printf("WRITESAME16 failed with the wrong sense code. Should fail with DATA_PROTECTION/WRITE_PROTECTED\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* UNMAP one block at lba 0 */ printf("WRITESAME10 to UNMAP LUN 0 ... "); if (lbpme == 0) { printf("LUN is not thin-provisioned. [SKIPPED]\n"); goto finished; } task = iscsi_writesame10_sync(iscsi, lun, data, block_size, 0, 1, 0, 1, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITESAME10 command should fail when writing to readonly devices\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_DATA_PROTECTION || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { printf("[FAILED]\n"); printf("WRITESAME10 failed with the wrong sense code. Should fail with DATA_PROTECTION/WRITE_PROTECTED\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* UNMAP one block at lba 0 */ printf("WRITESAME16 to UNMAP LUN 0 ... "); if (lbpme == 0) { printf("LUN is not thin-provisioned. [SKIPPED]\n"); goto finished; } task = iscsi_writesame16_sync(iscsi, lun, data, block_size, 0, 1, 0, 1, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITESAME16 command should fail when writing to readonly devices\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_DATA_PROTECTION || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { printf("[FAILED]\n"); printf("WRITESAME16 failed with the wrong sense code. Should fail with DATA_PROTECTION/WRITE_PROTECTED\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* UNMAP one block at lba 0 */ printf("UNMAP LUN 0 ... "); if (lbpme == 0) { printf("LUN is not thin-provisioned. [SKIPPED]\n"); goto finished; } list[0].lba = 0; list[0].num = 1; task = iscsi_unmap_sync(iscsi, lun, 0, 0, &list[0], 1); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send UNMAP command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("UNMAP command should fail when writing to readonly devices\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_DATA_PROTECTION || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { printf("[FAILED]\n"); printf("UNMAP failed with the wrong sense code. Should fail with DATA_PROTECTION/WRITE_PROTECTED\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Write one block at lba 0 */ printf("WRITEVERIFY10 to LUN 0 ... "); task = iscsi_writeverify10_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITEVERIFY10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITEVERIFY10 command should fail when writing to readonly devices\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_DATA_PROTECTION || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { printf("[FAILED]\n"); printf("WRITEVERIFY10 failed with the wrong sense code. Should fail with DATA_PROTECTION/WRITE_PROTECTED\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Write one block at lba 0 */ printf("WRITEVERIFY12 to LUN 0 ... "); task = iscsi_writeverify12_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITEVERIFY12 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITEVERIFY12 command should fail when writing to readonly devices\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_DATA_PROTECTION || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { printf("[FAILED]\n"); printf("WRITEVERIFY12 failed with the wrong sense code. Should fail with DATA_PROTECTION/WRITE_PROTECTED\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Write one block at lba 0 */ printf("WRITEVERIFY16 to LUN 0 ... "); task = iscsi_writeverify16_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITEVERIFY16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITEVERIFY16 command should fail when writing to readonly devices\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_DATA_PROTECTION || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { printf("[FAILED]\n"); printf("WRITEVERIFY16 failed with the wrong sense code. Should fail with DATA_PROTECTION/WRITE_PROTECTED\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Write one block at lba 0 */ printf("COMPAREWRITE to LUN 0 ... "); task = iscsi_compareandwrite_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send COMPAREANDWRITE command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("COMPAREANDWRITE command should fail when writing to readonly devices\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_DATA_PROTECTION || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { printf("[FAILED]\n"); printf("COMPAREANDWRITE failed with the wrong sense code. Should fail with DATA_PROTECTION/WRITE_PROTECTED\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Write one block at lba 0 */ printf("ORWRITE to LUN 0 ... "); task = iscsi_orwrite_sync(iscsi, lun, 0, data, block_size, block_size, 0, 0, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send ORWRITE command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("ORWRITE command should fail when writing to readonly devices\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_DATA_PROTECTION || task->sense.ascq != SCSI_SENSE_ASCQ_WRITE_PROTECTED) { printf("[FAILED]\n"); printf("ORWRITE failed with the wrong sense code. Should fail with DATA_PROTECTION/WRITE_PROTECTED\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; }
static int mpath_check_matching_ids_serial_vpd(int num_sds, struct scsi_device **sds) { int i; int num_sds_with_valid_id = 0; struct scsi_task *inq_task = NULL; char *usn_saved = NULL; for (i = 0; i < num_sds; i++) { int full_size; struct scsi_inquiry_unit_serial_number *inq_serial; /* * inquiry to confirm that all multipath devices carry an * identical unit serial number. */ inq_task = NULL; inquiry(sds[i], &inq_task, 1, SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER, 64, EXPECT_STATUS_GOOD); if (inq_task && inq_task->status != SCSI_STATUS_GOOD) { printf("Inquiry command failed : %s\n", sds[i]->error_str); goto err_cleanup; } full_size = scsi_datain_getfullsize(inq_task); if (full_size > inq_task->datain.size) { scsi_free_scsi_task(inq_task); /* we need more data */ inq_task = NULL; inquiry(sds[i], &inq_task, 1, SCSI_INQUIRY_PAGECODE_UNIT_SERIAL_NUMBER, full_size, EXPECT_STATUS_GOOD); if (inq_task == NULL) { printf("Inquiry command failed : %s\n", sds[i]->error_str); goto err_cleanup; } } inq_serial = scsi_datain_unmarshall(inq_task); if (inq_serial == NULL) { printf("failed to unmarshall inquiry datain blob\n"); goto err_cleanup; } if (inq_serial->qualifier != SCSI_INQUIRY_PERIPHERAL_QUALIFIER_CONNECTED) { printf("error: multipath device not connected\n"); goto err_cleanup; } if (inq_serial->device_type != SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { printf("error: multipath devices must be SBC\n"); goto err_cleanup; } if (inq_serial->usn == NULL) { printf("error: empty usn for multipath device\n"); goto err_cleanup; } if (usn_saved == NULL) { usn_saved = strdup(inq_serial->usn); if (usn_saved == NULL) { goto err_cleanup; } num_sds_with_valid_id++; } else if (strcmp(usn_saved, inq_serial->usn) == 0) { num_sds_with_valid_id++; } else { printf("multipath unit serial mismatch: %s != %s\n", usn_saved, inq_serial->usn); } scsi_free_scsi_task(inq_task); inq_task = NULL; } if (num_sds_with_valid_id != num_sds) { printf("failed to find matching serial number for all paths\n"); goto err_cleanup; } printf("found matching serial number for all (%d) paths: %s\n", num_sds, usn_saved); free(usn_saved); return 0; err_cleanup: free(usn_saved); scsi_free_scsi_task(inq_task); return -1; }
static int mpath_check_matching_ids_devid_vpd(int num_sds, struct scsi_device **sds) { int i; int num_sds_with_valid_id = 0; struct scsi_task *inq_task = NULL; struct scsi_inquiry_device_designator *des_saved = NULL; for (i = 0; i < num_sds; i++) { int ret; int full_size; struct scsi_inquiry_device_identification *inq_id_data; struct scsi_inquiry_device_designator *des; /* * dev ID inquiry to confirm that all multipath devices carry * an identical logical unit identifier. */ inquiry(sds[i], &inq_task, 1, SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION, 64, EXPECT_STATUS_GOOD); if (inq_task && inq_task->status != SCSI_STATUS_GOOD) { printf("Inquiry command failed : %s\n", sds[i]->error_str); goto err_cleanup; } full_size = scsi_datain_getfullsize(inq_task); if (full_size > inq_task->datain.size) { /* we need more data */ scsi_free_scsi_task(inq_task); inq_task = NULL; inquiry(sds[i], &inq_task, 1, SCSI_INQUIRY_PAGECODE_DEVICE_IDENTIFICATION, full_size, EXPECT_STATUS_GOOD); if (inq_task == NULL) { printf("Inquiry command failed : %s\n", sds[i]->error_str); goto err_cleanup; } } inq_id_data = scsi_datain_unmarshall(inq_task); if (inq_id_data == NULL) { printf("failed to unmarshall inquiry ID datain blob\n"); goto err_cleanup; } if (inq_id_data->qualifier != SCSI_INQUIRY_PERIPHERAL_QUALIFIER_CONNECTED) { printf("error: multipath device not connected\n"); goto err_cleanup; } if (inq_id_data->device_type != SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { printf("error: multipath devices must be SBC\n"); goto err_cleanup; } /* walk the list of IDs, and find a suitable LU candidate */ for (des = inq_id_data->designators; des != NULL; des = des->next) { if (des->association != SCSI_ASSOCIATION_LOGICAL_UNIT) { printf("skipping non-LU designator: %d\n", des->association); continue; } if ((des->designator_type != SCSI_DESIGNATOR_TYPE_EUI_64) && (des->designator_type != SCSI_DESIGNATOR_TYPE_NAA) && (des->designator_type != SCSI_DESIGNATOR_TYPE_MD5_LOGICAL_UNIT_IDENTIFIER) && (des->designator_type != SCSI_DESIGNATOR_TYPE_SCSI_NAME_STRING)) { printf("skipping unsupported des type: %d\n", des->designator_type); continue; } if (des->designator_length <= 0) { printf("skipping designator with bad len: %d\n", des->designator_length); continue; } if (des_saved == NULL) { ret = mpath_des_copy(des, &des_saved); if (ret < 0) { goto err_cleanup; } /* * we now have a reference to look for in all * subsequent paths. */ num_sds_with_valid_id++; break; } else if (mpath_des_cmp(des, des_saved) == 0) { /* found match for previous path designator */ num_sds_with_valid_id++; break; } /* no match yet, keep checking other designators */ } scsi_free_scsi_task(inq_task); inq_task = NULL; } mpath_des_free(des_saved); if (num_sds_with_valid_id != num_sds) { printf("failed to find matching LU device ID for all paths\n"); return -1; } printf("found matching LU device identifier for all (%d) paths\n", num_sds); return 0; err_cleanup: mpath_des_free(des_saved); scsi_free_scsi_task(inq_task); return -1; }
int T0400_inquiry_basic(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_inquiry_standard *inq; int ret, lun, i; int full_size; printf("0400_inquiry_basic:\n"); printf("===================\n"); if (show_info) { printf("Test the standard INQUIRY data format.\n"); printf("1, Check we can read the standard INQUIRY data.\n"); printf("2, Standard data must be at least 36 bytes in size.\n"); printf("3, Device-type must be either of DISK/TAPE/CDROM.\n"); printf("4, Check that peripheral-qualifier field is 0.\n"); printf("5, Check that the version field is valid.\n"); printf("6, Check that response-data-format is valid.\n"); printf("7, Check that additional-length is valid.\n"); printf("8, Verify HiSup flag is set.\n"); printf("9, Verify vendor-identification is in ASCII.\n"); printf("10, Verify product-identification is in ASCII.\n"); printf("11, Verify product-revision-level is in ASCII.\n"); printf("12, Verify AERC is clear in SPC-3 and later.\n"); printf("13, Verify TrmTsk is clear in SPC-2 and later.\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("Read standard INQUIRY data ... "); /* See how big this inquiry data is */ task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 255); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send INQUIRY command : %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("INQUIRY 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_inquiry_sync(iscsi, lun, 0, 0, full_size)) == NULL) { printf("[FAILED]\n"); printf("Inquiry command failed : %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } } inq = scsi_datain_unmarshall(task); if (inq == NULL) { printf("[FAILED]\n"); printf("failed to unmarshall inquiry datain blob\n"); scsi_free_scsi_task(task); ret = -1; goto finished; } printf("[OK]\n"); printf("Check that standard data is >= 36 bytes in size ... "); if (full_size < 36) { printf("[FAILED]\n"); printf("Standard INQUIRY data is less than 36 bytes.\n"); scsi_free_scsi_task(task); ret = -1; goto finished; } printf("[OK]\n"); printf("Check device-type is either of DISK, TAPE or CD/DVD ... "); switch (inq->device_type) { case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS: case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_SEQUENTIAL_ACCESS: case SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_MMC: break; default: printf("[FAILED]\n"); printf("Device-type is not DISK, TAPE or CD/DVD. Device reported:%s\n", scsi_devtype_to_str(inq->device_type)); ret = -1; goto test4; } printf("[OK]\n"); test4: printf("Check PREIPHERAL QUALIFIER FIELD is 0 ... "); if (inq->qualifier != 0) { printf("[FAILED]\n"); printf("QUALIFIER was not 0, it was %d\n", inq->qualifier); ret = -1; goto test5; } printf("[OK]\n"); test5: printf("Check VERSION field is either 0x4, 0x5 or 0x6 ... "); switch (inq->version) { case 0x4: /* SPC-2 */ case 0x5: /* SPC-3 */ case 0x6: /* SPC-4 */ break; default: printf("[FAILED]\n"); printf("Invalid VERSION:%d. Should be 0x4, 0x5 or 0x6\n", inq->version); ret = -1; goto test6; } printf("[OK]\n"); test6: printf("Check RESPONSE DATA FORMAT is 2 ... "); if (inq->response_data_format != 2) { printf("[FAILED]\n"); printf("Invalid RESPONSE_DATA_FORMAT:%d. Should be 2\n", inq->response_data_format); ret = -1; goto test7; } printf("[OK]\n"); test7: printf("Verify Additional-Length ... "); if (inq->additional_length + 5 != full_size) { printf("[FAILED]\n"); printf("Invalid additional-length. Was %d but should be %d\n", inq->additional_length, full_size-5); ret = -1; goto test8; } printf("[OK]\n"); test8: printf("Verify HiSup is set ... "); if (!inq->hisup) { printf("[FAILED]\n"); printf("HiSup flag is not set.\n"); ret = -1; goto test9; } printf("[OK]\n"); test9: printf("Verify VENDOR_IDENTIFICATION is in ASCII ... "); for (i = 8; i < 16; i++) { /* SPC-4 4.4.1 only characters 0x00 and 0x20-0x7E allowed */ if (task->datain.data[i] == 0) { continue; } if (task->datain.data[i] >= 0x20 && task->datain.data[i] <= 0x7e) { continue; } printf("[FAILED]\n"); printf("VENDOR_IDENTIFICATION contains non-ASCII characters\n"); ret = -1; goto test10; } printf("[OK]\n"); test10: printf("Verify PRODUCT_IDENTIFICATION is in ASCII ... "); for (i = 16; i < 32; i++) { /* SPC-4 4.4.1 only characters 0x00 and 0x20-0x7E allowed */ if (task->datain.data[i] == 0) { continue; } if (task->datain.data[i] >= 0x20 && task->datain.data[i] <= 0x7e) { continue; } printf("[FAILED]\n"); printf("PRODUCT_IDENTIFICATION contains non-ASCII characters\n"); ret = -1; goto test11; } printf("[OK]\n"); test11: printf("Verify PRODUCT_REVISION_LEVEL is in ASCII ... "); for (i = 32; i < 36; i++) { /* SPC-4 4.4.1 only characters 0x00 and 0x20-0x7E allowed */ if (task->datain.data[i] == 0) { continue; } if (task->datain.data[i] >= 0x20 && task->datain.data[i] <= 0x7e) { continue; } printf("[FAILED]\n"); printf("PRODUCT_REVISION_LEVEL contains non-ASCII characters\n"); ret = -1; goto test12; } printf("[OK]\n"); test12: printf("Verify AERC is clear in SPC-3 and later ... "); if (task->datain.data[3] & 0x80 && inq->version >= 5) { printf("[FAILED]\n"); printf("AERC is set but this device reports SPC-3 or later\n"); ret = -1; goto test13; } printf("[OK]\n"); test13: printf("Verify TrmTsk is clear in SPC-2 and later ... "); if (task->datain.data[3] & 0x40 && inq->version >= 4) { printf("[FAILED]\n"); printf("TrmTsk is set but this device reports SPC-2 or later\n"); ret = -1; goto test14; } printf("[OK]\n"); test14: scsi_free_scsi_task(task); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; }
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; }
int T0180_writesame10_unmap(const char *initiator, const char *url) { struct iscsi_context *iscsi; struct scsi_task *task; int full_size; struct scsi_inquiry_logical_block_provisioning *lbp; int ret, i, lun; printf("0180_writesame10_unmap:\n"); printf("=======================\n"); if (show_info) { printf("Test basic WRITESAME10-UNMAP functionality.\n"); printf("1, If LBPME==1 we should have VPD page 0xB2\n"); printf("2, UNMAP the first 1-256 blocks at the start of the LUN\n"); printf("3, UNMAP the last 1-256 blocks at the end of the LUN\n"); printf("4, Verify that UNMAP == 0 and ANCHOR == 1 is invalid\n"); printf("5, UNMAP == 1 and ANCHOR == 1\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; if (rc16 == NULL || rc16->lbpme == 0) { printf("Logical unit is fully provisioned. All commands should fail with check condition.\n"); } /* Check that id we have logical block provisioning we also have the VPD page for it */ printf("Logical Block Provisioning is available. Check that VPD page 0xB2 exists ... "); /* See how big this inquiry data is */ task = iscsi_inquiry_sync(iscsi, lun, 1, SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING, 64); if (task == NULL || task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("Inquiry command failed : %s\n", iscsi_get_error(iscsi)); 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_inquiry_sync(iscsi, lun, 1, SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING, full_size)) == NULL) { printf("[FAILED]\n"); printf("Inquiry command failed : %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } } lbp = scsi_datain_unmarshall(task); if (lbp == NULL) { printf("failed to unmarshall inquiry datain blob\n"); scsi_free_scsi_task(task); ret = -1; goto finished; } printf("[OK]\n"); if (lbp->lbpws10 == 0) { printf("Device does not support WRITE_SAME10 for UNMAP. All WRITE_SAME10 commands to unmap should fail.\n"); } if (!data_loss) { printf("--dataloss flag is not set. Skipping test\n"); ret = -2; goto finished; } ret = 0; /* unmap the first 1 - 256 blocks at the start of the LUN */ printf("Unmapping first 1-256 blocks ... "); if (lbp->lbpws10 == 0) { printf("(Should all fail since LBPWS10 is 0) "); } for (i=1; i<=256; i++) { /* only try unmapping whole physical blocks, of if unmap using ws10 is not supported we test for all and they should all fail */ if (lbp->lbpws10 == 1 && i % lbppb) { continue; } task = iscsi_writesame10_sync(iscsi, lun, 0, NULL, 0, i, 0, 1, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME10 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("Opcode is not implemented on target\n"); scsi_free_scsi_task(task); ret = -2; goto finished; } if (lbp->lbpws10) { if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITESAME10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); ret = -1; goto finished; } } else { if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST || task->sense.ascq != SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB) { printf("[FAILED]\n"); printf("WRITESAME10 command should fail since LBPWS10 is 0 but failed with wrong sense code %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); ret = -1; goto finished; } } scsi_free_scsi_task(task); } printf("[OK]\n"); /* unmap the last 1 - 256 blocks at the end of the LUN */ printf("Unmapping last 1-256 blocks ... "); if (lbp->lbpws10 == 0) { printf("(Should all fail since LBPWS10 is 0) "); } for (i=1; i<=256; i++) { /* only try unmapping whole physical blocks, of if unmap using ws10 is not supported we test for all and they should all fail */ if (lbp->lbpws10 == 1 && i % lbppb) { continue; } task = iscsi_writesame10_sync(iscsi, lun, num_blocks + 1 - i, NULL, 0, i, 0, 1, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (lbp->lbpws10) { if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITESAME10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); ret = -1; goto finished; } } else { if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST || task->sense.ascq != SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB) { printf("[FAILED]\n"); printf("WRITESAME10 command should fail since LBPWS10 is 0 but failed with wrong sense code %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); ret = -1; goto finished; } } scsi_free_scsi_task(task); } printf("[OK]\n"); /* Test that UNMAP=0 and ANCHOR==1 fails with check condition */ printf("Try UNMAP==0 and ANCHOR==1 ... "); task = iscsi_writesame10_sync(iscsi, lun, 0, NULL, 0, 64, 1, 0, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME10 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_FIELD_IN_CDB) { printf("[FAILED]\n"); printf("WRITESAME10 with UNMAP=0 ANCHOR=1 failed with wrong sense code %d %s(%d) %s(0x%04x) should be CHECK_CONDITION/ILLEGAL_REQUEST/INVALID_FIELD_IN_CDB\n", task->status, scsi_sense_key_str(task->sense.key), task->sense.key, scsi_sense_ascq_str(task->sense.ascq), task->sense.ascq); scsi_free_scsi_task(task); ret = -1; goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* Test UNMAP=1 and ANCHOR==1 */ printf("Try UNMAP==1 and ANCHOR==1 ... "); if (lbp->anc_sup == 0) { printf("(ANC_SUP==0 so check condition expected) "); } task = iscsi_writesame10_sync(iscsi, lun, 0, NULL, 0, 64, 1, 1, 0, 0); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send WRITESAME10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (lbp->anc_sup == 0) { if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST || task->sense.ascq != SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB) { printf("[FAILED]\n"); printf("WRITESAME10 with UNMAP=1 ANCHOR=1 failed with wrong sense code %d %s(%d) %s(0x%04x) should be CHECK_CONDITION/ILLEGAL_REQUEST/INVALID_FIELD_IN_CDB\n", task->status, scsi_sense_key_str(task->sense.key), task->sense.key, scsi_sense_ascq_str(task->sense.ascq), task->sense.ascq); scsi_free_scsi_task(task); ret = -1; goto finished; } } else { if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("WRITESAME10 command: failed with sense. %s\n", iscsi_get_error(iscsi)); scsi_free_scsi_task(task); ret = -1; goto finished; } } scsi_free_scsi_task(task); printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; }
int main(int argc, char *argv[]) { char *testname_re = NULL; 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 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' }, { "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:sdgfAsSnvxV", 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 '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; } } /* parse all trailing arguments as device paths */ mp_num_sds = 0; while (optind < argc) { if (mp_num_sds >= MPATH_MAX_DEVS) { fprintf(stderr, "Too many multipath device URLs\n"); print_usage(); free(testname_re); return 10; } mp_sds[mp_num_sds] = malloc(sizeof(struct scsi_device)); memset(mp_sds[mp_num_sds], '\0', sizeof(struct scsi_device)); mp_sds[mp_num_sds]->sgio_fd = -1; if (!strncmp(argv[optind], "iscsi://", 8)) { mp_sds[mp_num_sds]->iscsi_url = strdup(argv[optind++]); #ifdef HAVE_SG_IO } else { mp_sds[mp_num_sds]->sgio_dev = strdup(argv[optind++]); #endif } mp_num_sds++; } /* So that we can override iscsi_queue_pdu in tests * and replace or mutate the blob that we are about to write to the * wire. * This allows such tests to do their mutates and then call out * to the real queueing function once they have modified the data. */ real_iscsi_queue_pdu = dlsym(RTLD_NEXT, "iscsi_queue_pdu"); if ((mp_num_sds == 0) || (mp_sds[0]->iscsi_url == NULL && mp_sds[0]->sgio_dev == NULL)) { #ifdef HAVE_SG_IO fprintf(stderr, "You must specify either an iSCSI URL or a device file\n"); #else fprintf(stderr, "You must specify an iSCSI URL\n"); #endif print_usage(); if (testname_re) free(testname_re); return 10; } /* sd remains an alias for the first device */ sd = mp_sds[0]; for (i = 0; i < mp_num_sds; i++) { res = connect_scsi_device(mp_sds[i], initiatorname1); if (res < 0) { fprintf(stderr, "Failed to connect to SCSI device %d\n", i); goto err_sds_free; } } if (mp_num_sds > 1) { /* check that all multipath sds identify as the same LU */ res = mpath_check_matching_ids(mp_num_sds, mp_sds); if (res < 0) { fprintf(stderr, "multipath devices don't match\n"); goto err_sds_free; } } /* * find the size of the LUN * All devices support readcapacity10 but only some support * readcapacity16 */ task = NULL; readcapacity10(sd, &task, 0, 0, EXPECT_STATUS_GOOD); if (task == NULL) { printf("Failed to send READCAPACITY10 command: %s\n", sd->error_str); goto err_sds_free; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY10 command: failed with sense. %s\n", sd->error_str); scsi_free_scsi_task(task); goto err_sds_free; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall READCAPACITY10 data.\n"); scsi_free_scsi_task(task); goto err_sds_free; } block_size = rc10->block_size; num_blocks = rc10->lba + 1; scsi_free_scsi_task(task); rc16_task = NULL; readcapacity16(sd, &rc16_task, 96, EXPECT_STATUS_GOOD); if (rc16_task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", sd->error_str); goto err_sds_free; } if (rc16_task->status == SCSI_STATUS_GOOD) { rc16 = scsi_datain_unmarshall(rc16_task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", sd->error_str); scsi_free_scsi_task(rc16_task); goto err_sds_free; } block_size = rc16->block_length; num_blocks = rc16->returned_lba + 1; lbppb = 1 << rc16->lbppbe; } inq_task = NULL; inquiry(sd, &inq_task, 0, 0, 64, EXPECT_STATUS_GOOD); if (inq_task == NULL || inq_task->status != SCSI_STATUS_GOOD) { printf("Inquiry command failed : %s\n", sd->error_str); goto err_sds_free; } 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 = NULL; inquiry(sd, &inq_task, 0, 0, full_size, EXPECT_STATUS_GOOD); if (inq_task == NULL) { printf("Inquiry command failed : %s\n", sd->error_str); goto err_sds_free; } } inq = scsi_datain_unmarshall(inq_task); if (inq == NULL) { printf("failed to unmarshall inquiry datain blob\n"); scsi_free_scsi_task(inq_task); goto err_sds_free; } 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 = NULL; inquiry(sd, &inq_bl_task, 1, SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS, 64, EXPECT_STATUS_GOOD); 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); inq_bl_task = NULL; inquiry(sd, &inq_bl_task, 1, SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS, full_size, EXPECT_STATUS_GOOD); if (inq_bl_task == NULL) { printf("Inquiry command failed : %s\n", sd->error_str); goto err_sds_free; } } inq_bl = scsi_datain_unmarshall(inq_bl_task); if (inq_bl == NULL) { printf("failed to unmarshall inquiry datain blob\n"); goto err_sds_free; } } /* try reading block device characteristics vpd */ inquiry(sd, &inq_bdc_task, 1, SCSI_INQUIRY_PAGECODE_BLOCK_DEVICE_CHARACTERISTICS, 255, EXPECT_STATUS_GOOD); if (inq_bdc_task == NULL || inq_bdc_task->status != SCSI_STATUS_GOOD) { printf("Failed to read Block Device Characteristics page\n"); } else { inq_bdc = scsi_datain_unmarshall(inq_bdc_task); if (inq_bdc == NULL) { printf("failed to unmarshall inquiry datain blob\n"); goto err_sds_free; } } /* if thin provisioned we also need to read the VPD page for it */ if (rc16 && rc16->lbpme != 0){ inq_lbp_task = NULL; inquiry(sd, &inq_lbp_task, 1, SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING, 64, EXPECT_STATUS_GOOD); if (inq_lbp_task == NULL || inq_lbp_task->status != SCSI_STATUS_GOOD) { printf("Inquiry command failed : %s\n", sd->error_str); goto err_sds_free; } 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 */ inq_lbp_task = NULL; inquiry(sd, &inq_lbp_task, 1, SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING, full_size, EXPECT_STATUS_GOOD); if (inq_lbp_task == NULL) { printf("Inquiry command failed : %s\n", sd->error_str); goto err_sds_free; } } inq_lbp = scsi_datain_unmarshall(inq_lbp_task); if (inq_lbp == NULL) { printf("failed to unmarshall inquiry datain blob\n"); goto err_sds_free; } } rsop_task = NULL; report_supported_opcodes(sd, &rsop_task, 1, SCSI_REPORT_SUPPORTING_OPS_ALL, 0, 0, 65535, EXPECT_STATUS_GOOD); if (rsop_task == NULL) { printf("Failed to send REPORT_SUPPORTED_OPCODES command: %s\n", sd->error_str); goto err_sds_free; } if (rsop_task->status == SCSI_STATUS_GOOD) { rsop = scsi_datain_unmarshall(rsop_task); if (rsop == NULL) { printf("failed to unmarshall REPORT_SUPPORTED_OPCODES data.\n"); scsi_free_scsi_task(rsop_task); rsop_task = NULL; } } /* check if the device is write protected or not */ task = NULL; modesense6(sd, &task, 0, SCSI_MODESENSE_PC_CURRENT, SCSI_MODEPAGE_RETURN_ALL_PAGES, 0, 255, EXPECT_STATUS_GOOD); if (task == NULL) { printf("Failed to send MODE_SENSE6 command: %s\n", sd->error_str); goto err_sds_free; } 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); goto err_sds_free; } readonly = !!(ms->device_specific_parameter & 0x80); } scsi_free_scsi_task(task); if (maxsectbytes) { maximum_transfer_length = maxsectbytes / block_size; printf("Bus transfer size is limited to %d bytes. Clamping " "max transfers accordingly.\n", maxsectbytes); } if (CU_initialize_registry() != 0) { fprintf(stderr, "error: unable to initialize test registry\n"); goto err_sds_free; } 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(); 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); } for (i = 0; i < mp_num_sds; i++) { free_scsi_device(mp_sds[i]); } return 0; err_sds_free: for (i = 0; i < mp_num_sds; i++) { free_scsi_device(mp_sds[i]); } return -1; }
int T0103_read10_rdprotect(const char *initiator, const char *url, int data_loss _U_, int show_info) { struct iscsi_context *iscsi; struct scsi_task *task; int full_size; struct scsi_inquiry_standard *inq; int ret, i, lun; printf("0103_read10_rdprotect:\n"); printf("======================\n"); if (show_info) { printf("Test how READ10 handles the rdprotect bits\n"); printf("1, Any non-zero valued for rdprotect should fail.\n"); printf("\n"); return 0; } iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* See how big this inquiry data is */ task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 64); if (task == NULL || task->status != SCSI_STATUS_GOOD) { printf("Inquiry command failed : %s\n", iscsi_get_error(iscsi)); return -1; } 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_inquiry_sync(iscsi, lun, 0, 0, full_size)) == NULL) { printf("Inquiry command failed : %s\n", iscsi_get_error(iscsi)); return -1; } } inq = scsi_datain_unmarshall(task); if (inq == NULL) { printf("failed to unmarshall inquiry datain blob\n"); scsi_free_scsi_task(task); return -1; } if (inq->periperal_device_type != SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { printf("LUN is not SBC device. Skipping test\n"); scsi_free_scsi_task(task); return -1; } if (inq->protect) { printf("LUN is formatted with protection information. Skipping test\n"); scsi_free_scsi_task(task); return -1; } scsi_free_scsi_task(task); ret = 0; /* Try out Different non-zero values for RDPROTECT. They should all fail */ printf("Read10 with non-zero RDPROTECT ... "); for (i = 1; i < 8; i++) { task = malloc(sizeof(struct scsi_task)); if (task == NULL) { printf("Failed to allocate task structure\n"); ret = -1; goto finished; } memset(task, 0, sizeof(struct scsi_task)); task->cdb[0] = SCSI_OPCODE_READ10; task->cdb[1] = (i<<5)&0xe0; task->cdb[8] = 1; task->cdb_size = 10; task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 512; if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (task->status != SCSI_STATUS_CHECK_CONDITION || task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST || task->sense.ascq != SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB) { printf("[FAILED]\n"); printf("Read10 with rdprotect should fail with ILLEGAL REQUEST/INVALID OPCODE\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); } printf("[OK]\n"); finished: iscsi_logout_sync(iscsi); iscsi_destroy_context(iscsi); return ret; }