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;
}
Exemplo n.º 3
0
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);
}