Exemple #1
0
int
scsi_probe_target(struct scsibus_softc *sc, int target)
{
	struct scsi_link *alink = sc->adapter_link;
	struct scsi_link *link;
	struct scsi_report_luns_data *report;
	int i, nluns, lun;

	if (scsi_probe_lun(sc, target, 0) == EINVAL)
		return (EINVAL);

	link = sc->sc_link[target][0];
	if (link == NULL)
		return (ENXIO);

	if ((link->flags & (SDEV_UMASS | SDEV_ATAPI)) == 0 &&
	    SCSISPC(link->inqdata.version) > 2) {
		report = malloc(sizeof(*report), M_TEMP, M_WAITOK);
		if (report == NULL)
			goto dumbscan;

		if (scsi_report_luns(link, REPORT_NORMAL, report,
		    sizeof(*report), scsi_autoconf | SCSI_SILENT |
		    SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY |
		    SCSI_IGNORE_MEDIA_CHANGE, 10000) != 0) {
			free(report, M_TEMP);
			goto dumbscan;
		}

		/*
		 * XXX In theory we should check if data is full, which
		 * would indicate it needs to be enlarged and REPORT
		 * LUNS tried again. Solaris tries up to 3 times with
		 * larger sizes for data.
		 */
		nluns = _4btol(report->length) / RPL_LUNDATA_SIZE;
		for (i = 0; i < nluns; i++) {
			if (report->luns[i].lundata[0] != 0)
				continue;
			lun = report->luns[i].lundata[RPL_LUNDATA_T0LUN];
			if (lun == 0)
				continue;

			/* Probe the provided LUN. Don't check LUN 0. */
			sc->sc_link[target][0] = NULL;
			scsi_probe_lun(sc, target, lun);
			sc->sc_link[target][0] = link;
		}

		free(report, M_TEMP);
		return (0);
	}

dumbscan:
	for (i = 1; i < alink->luns; i++) {
		if (scsi_probe_lun(sc, target, i) == EINVAL)
			break;
	}

	return (0);
}
Exemple #2
0
int scsi_parse(uint8_t *block, uint8_t in_len)
{
	/* set new operation */
	if (state == USB_MS_SCSI_STATE_IDLE) {
		state = USB_MS_SCSI_STATE_PARSE;

		op = block[0];
	}

	/* skip operation if sending reply */
	if (state != USB_MS_SCSI_STATE_REPLY) {
		switch (op) {
		case SCSI_INQUIRY:
			scsi_inquiry(block, in_len);
		break;
		case SCSI_MODE_SENSE6:
			scsi_mode_sense6(block, in_len);
		break;
		case SCSI_READ10:
			scsi_read10(block, in_len);
		break;
		case SCSI_READ_CAPACITY10:
			scsi_read_capacity10(block, in_len);
		break;
		case SCSI_READ_FORMAT_CAPACITIES:
			scsi_read_format_capacities(block, in_len);
		break;
		case SCSI_REPORT_LUNS:
			scsi_report_luns(block, in_len);
		break;
		case SCSI_REQUEST_SENSE:
			scsi_request_sense(block, in_len);
		break;
		case SCSI_START_STOP_UNIT:
			scsi_start_stop_unit(block, in_len);
		break;
		case SCSI_SYNCHRONIZE_CACHE10:
			scsi_synchronize_cache10(block, in_len);
		break;
		case SCSI_TEST_UNIT_READY:
			scsi_test_unit_ready(block, in_len);
		break;
		case SCSI_WRITE10:
			scsi_write10(block, in_len);
		break;
		default:
			state = USB_MS_SCSI_STATE_REPLY;
			scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
				SCSI_SENSE_CODE_INVALID_COMMAND_OPERATION_CODE);
		break;
		}
	}

	/* error during data rx/tx */
	if (((state == USB_MS_SCSI_STATE_DATA_OUT) ||
			(state == USB_MS_SCSI_STATE_DATA_IN)) &&
			scsi_sense_data.key) {
		btable_ep[USB_EP_MS_TX].tx_count = 0;
		state = USB_MS_SCSI_STATE_REPLY;
		return SCSI_STATUS_CONTINUE;
	}

	/* done sending data */
	if (state == USB_MS_SCSI_STATE_REPLY) {
		state = USB_MS_SCSI_STATE_IDLE;
		return scsi_sense_data.key;
	}

	/* still sending/receiving data and no error has occurred */
	return SCSI_STATUS_CONTINUE;
}