ssize_t write(int fd, const void *buf, size_t count) { if ((iscsi_fd_list[fd].is_iscsi == 1) && (iscsi_fd_list[fd].in_flight == 0)) { uint64_t offset; uint64_t num_blocks, lba; struct scsi_task *task; if (iscsi_fd_list[fd].dup2fd >= 0) { return write(iscsi_fd_list[fd].dup2fd, buf, count); } if (iscsi_fd_list[fd].offset%iscsi_fd_list[fd].block_size) { errno = EINVAL; return -1; } if (count%iscsi_fd_list[fd].block_size) { errno = EINVAL; return -1; } iscsi_fd_list[fd].lbasd_cache_valid = 0; offset = iscsi_fd_list[fd].offset; num_blocks = count/iscsi_fd_list[fd].block_size; lba = offset / iscsi_fd_list[fd].block_size; /* Don't try to read beyond the last LBA */ if (lba >= iscsi_fd_list[fd].num_blocks) { return 0; } /* Trim num_blocks requested to last lba */ if ((lba + num_blocks) > iscsi_fd_list[fd].num_blocks) { num_blocks = iscsi_fd_list[fd].num_blocks - lba; count = num_blocks * iscsi_fd_list[fd].block_size; } iscsi_fd_list[fd].in_flight = 1; LD_ISCSI_DPRINTF(4,"write16_sync: lun %d, lba %"PRIu64", num_blocks: %"PRIu64", block_size: %d, offset: %"PRIu64" count: %lu",iscsi_fd_list[fd].lun,lba,num_blocks,iscsi_fd_list[fd].block_size,offset,(unsigned long)count); task = iscsi_write16_sync(iscsi_fd_list[fd].iscsi, iscsi_fd_list[fd].lun, lba, (unsigned char *) buf, count, iscsi_fd_list[fd].block_size, 0, 0, 0, 0, 0); iscsi_fd_list[fd].in_flight = 0; if (task == NULL || task->status != SCSI_STATUS_GOOD) { LD_ISCSI_DPRINTF(0,"failed to send write16 command"); errno = EIO; return -1; } iscsi_fd_list[fd].offset += count; scsi_free_scsi_task(task); return count; } return real_write(fd, buf, count); }
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; }