int T0260_get_lba_status_simple(const char *initiator, const char *url, int data_loss _U_, int show_info) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, lun; uint64_t num_blocks; printf("0260_get_lba_status_simple:\n"); printf("===================\n"); if (show_info) { printf("Test basic GET_LBA_STATUS functionality.\n"); printf("1, Verify we can read a descriptor at the start of the lun.\n"); printf("2, Verify we can read a descriptor at the end of the lun.\n"); printf("\n"); return 0; } iscsi = iscsi_context_login(initiator, url, &lun); if (iscsi == NULL) { printf("Failed to login to target\n"); return -1; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send readcapacity16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall readcapacity16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (rc16->lbpme == 0) { printf("Logical unit is fully provisioned. Skipping test\n"); ret = -2; scsi_free_scsi_task(task); goto finished; } num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); ret = 0; /* try reading one descriptor at offset 0 */ printf("Read one descriptor at LBA 0 ... "); task = iscsi_get_lba_status_sync(iscsi, lun, 0, 8 + 16); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send GET_LBA_STATUS command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("GET_LBA_STATUS command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } scsi_free_scsi_task(task); printf("[OK]\n"); /* try reading one descriptor at end-of-device */ printf("Read one descriptor at end-of-device ... "); task = iscsi_get_lba_status_sync(iscsi, lun, num_blocks, 8 + 16); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send GET_LBA_STATUS command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("GET_LBA_STATUS command: failed with sense. %s\n", iscsi_get_error(iscsi)); 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; }
int T0264_get_lba_status_beyondeol(const char *initiator, const char *url, int data_loss _U_, int show_info) { struct iscsi_context *iscsi; struct scsi_task *task; struct scsi_readcapacity16 *rc16; int ret, lun; uint32_t block_size; uint64_t num_blocks; printf("0264_get_lba_status_beyondeol:\n"); printf("==============================\n"); if (show_info) { printf("Test GET_LBA_STATUS functionality for beyond end-of-lun requests\n"); printf("1, Reading a descriptor beyond the end of the lun 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; } /* find the size of the LUN */ task = iscsi_readcapacity16_sync(iscsi, lun); if (task == NULL) { printf("Failed to send readcapacity16 command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status != SCSI_STATUS_GOOD) { printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall readcapacity16 data. %s\n", iscsi_get_error(iscsi)); ret = -1; scsi_free_scsi_task(task); goto finished; } if (rc16->lbpme == 0){ printf("Logical unit is fully provisioned. Skipping test\n"); ret = -1; scsi_free_scsi_task(task); goto finished; } block_size = rc16->block_length; num_blocks = rc16->returned_lba; scsi_free_scsi_task(task); ret = 0; /* try reading one descriptor beyond end-of-device */ printf("Read one descriptor beyond end-of-device ... "); task = iscsi_get_lba_status_sync(iscsi, lun, num_blocks + 1, 8 + 16); if (task == NULL) { printf("[FAILED]\n"); printf("Failed to send GET_LBA_STATUS command: %s\n", iscsi_get_error(iscsi)); ret = -1; goto finished; } if (task->status == SCSI_STATUS_GOOD) { printf("[FAILED]\n"); printf("GET_LBA_STATUS beyond eol should fail with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE\n"); 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_LBA_OUT_OF_RANGE) { printf("[FAILED]\n"); printf("GET_LBA_STATUS failed but with the wrong sense code. It should have failed with ILLEGAL_REQUEST/LBA_OUT_OF_RANGE.\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; }
ssize_t read(int fd, 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; struct scsi_get_lba_status *lbas; if (iscsi_fd_list[fd].dup2fd >= 0) { return read(iscsi_fd_list[fd].dup2fd, buf, count); } offset = iscsi_fd_list[fd].offset / iscsi_fd_list[fd].block_size * iscsi_fd_list[fd].block_size; num_blocks = (iscsi_fd_list[fd].offset - offset + count + iscsi_fd_list[fd].block_size - 1) / 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; if (iscsi_fd_list[fd].get_lba_status != 0) { uint32_t i; uint32_t _num_allocated=0; uint32_t _num_blocks=0; if (iscsi_fd_list[fd].lbasd_cache_valid==1) { LD_ISCSI_DPRINTF(5,"cached get_lba_status_descriptor is lba %"PRIu64", num_blocks %d, provisioning %d",iscsi_fd_list[fd].lbasd_cached.lba,iscsi_fd_list[fd].lbasd_cached.num_blocks,iscsi_fd_list[fd].lbasd_cached.provisioning); if (iscsi_fd_list[fd].lbasd_cached.provisioning != 0x00 && lba >= iscsi_fd_list[fd].lbasd_cached.lba && lba+num_blocks < iscsi_fd_list[fd].lbasd_cached.lba+iscsi_fd_list[fd].lbasd_cached.num_blocks) { LD_ISCSI_DPRINTF(4,"skipped read16_sync for non-allocated blocks: 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); memset(buf, 0x00, count); iscsi_fd_list[fd].offset += count; iscsi_fd_list[fd].in_flight = 0; return count; } } LD_ISCSI_DPRINTF(4,"get_lba_status_sync: lun %d, lba %"PRIu64", num_blocks: %"PRIu64,iscsi_fd_list[fd].lun,lba,num_blocks); task = iscsi_get_lba_status_sync(iscsi_fd_list[fd].iscsi, iscsi_fd_list[fd].lun, lba, 8+16); if (task == NULL || task->status != SCSI_STATUS_GOOD) { LD_ISCSI_DPRINTF(0,"failed to send get_lba_status command"); iscsi_fd_list[fd].in_flight = 0; errno = EIO; return -1; } lbas = scsi_datain_unmarshall(task); if (lbas == NULL) { LD_ISCSI_DPRINTF(0,"failed to unmarshall get_lba_status data"); scsi_free_scsi_task(task); iscsi_fd_list[fd].in_flight = 0; errno = EIO; return -1; } LD_ISCSI_DPRINTF(5,"get_lba_status: num_descriptors: %d",lbas->num_descriptors); for (i=0;i<lbas->num_descriptors;i++) { struct scsi_lba_status_descriptor *lbasd = &lbas->descriptors[i]; LD_ISCSI_DPRINTF(5,"get_lba_status_descriptor %d, lba %"PRIu64", num_blocks %d, provisioning %d",i,lbasd->lba,lbasd->num_blocks,lbasd->provisioning); if (lbasd->lba != _num_blocks+lba) { LD_ISCSI_DPRINTF(0,"get_lba_status response is non-continuous"); scsi_free_scsi_task(task); iscsi_fd_list[fd].in_flight = 0; errno = EIO; return -1; } _num_allocated+=(lbasd->provisioning==0x00)?lbasd->num_blocks:0; _num_blocks+=lbasd->num_blocks; iscsi_fd_list[fd].lbasd_cached=lbas->descriptors[i]; iscsi_fd_list[fd].lbasd_cache_valid=1; } scsi_free_scsi_task(task); if (_num_allocated == 0 && _num_blocks >= num_blocks) { LD_ISCSI_DPRINTF(4,"skipped read16_sync for non-allocated blocks: 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); memset(buf, 0x00, count); iscsi_fd_list[fd].offset += count; iscsi_fd_list[fd].in_flight = 0; return count; } } LD_ISCSI_DPRINTF(4,"read16_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_read16_sync(iscsi_fd_list[fd].iscsi, iscsi_fd_list[fd].lun, lba, num_blocks * iscsi_fd_list[fd].block_size, 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 read16 command"); errno = EIO; return -1; } memcpy(buf, &task->datain.data[iscsi_fd_list[fd].offset - offset], count); iscsi_fd_list[fd].offset += count; scsi_free_scsi_task(task); return count; } return real_read(fd, buf, count); }