Beispiel #1
0
void
AHCIPort::ScsiExecuteRequest(scsi_ccb *request)
{
//	TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length);

    if (fIsATAPI) {
        bool isWrite = false;
        switch (request->flags & SCSI_DIR_MASK) {
        case SCSI_DIR_NONE:
            ASSERT(request->data_length == 0);
            break;
        case SCSI_DIR_IN:
            ASSERT(request->data_length > 0);
            break;
        case SCSI_DIR_OUT:
            isWrite = true;
            ASSERT(request->data_length > 0);
            break;
        default:
            panic("CDB has invalid direction mask");
        }

//		TRACE("AHCIPort::ScsiExecuteRequest ATAPI: port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length);

        sata_request *sreq = new(std::nothrow) sata_request(request);
        if (sreq == NULL) {
            TRACE("out of memory when allocating atapi request\n");
            request->subsys_status = SCSI_REQ_ABORTED;
            gSCSI->finished(request, 1);
            return;
        }

        sreq->set_atapi_cmd(request->data_length);
//		uint8 *data = (uint8*) sreq->ccb()->cdb;
//		for (int i = 0; i < 16; i += 8) {
//			TRACE("  %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1], data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]);
//		}
        ExecuteSataRequest(sreq, isWrite);
        return;
    }

    if (request->cdb[0] == SCSI_OP_REQUEST_SENSE) {
        panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n");
        return;
    }

    if (!fDevicePresent) {
        TRACE("no device present on port %d\n", fIndex);
        request->subsys_status = SCSI_DEV_NOT_THERE;
        gSCSI->finished(request, 1);
        return;
    }

    request->subsys_status = SCSI_REQ_CMP;

    switch (request->cdb[0]) {
    case SCSI_OP_TEST_UNIT_READY:
        ScsiTestUnitReady(request);
        break;
    case SCSI_OP_INQUIRY:
        ScsiInquiry(request);
        break;
    case SCSI_OP_READ_CAPACITY:
        ScsiReadCapacity(request);
        break;
    case SCSI_OP_SERVICE_ACTION_IN:
        if ((request->cdb[1] & 0x1f) == SCSI_SAI_READ_CAPACITY_16)
            ScsiReadCapacity16(request);
        else {
            request->subsys_status = SCSI_REQ_INVALID;
            gSCSI->finished(request, 1);
        }
        break;
    case SCSI_OP_SYNCHRONIZE_CACHE:
        ScsiSynchronizeCache(request);
        break;
    case SCSI_OP_READ_6:
    case SCSI_OP_WRITE_6:
    {
        const scsi_cmd_rw_6 *cmd = (const scsi_cmd_rw_6 *)request->cdb;
        uint32 position = ((uint32)cmd->high_lba << 16)
                          | ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba;
        size_t length = cmd->length != 0 ? cmd->length : 256;
        bool isWrite = request->cdb[0] == SCSI_OP_WRITE_6;
        ScsiReadWrite(request, position, length, isWrite);
        break;
    }
    case SCSI_OP_READ_10:
    case SCSI_OP_WRITE_10:
    {
        const scsi_cmd_rw_10 *cmd = (const scsi_cmd_rw_10 *)request->cdb;
        uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba);
        size_t length = B_BENDIAN_TO_HOST_INT16(cmd->length);
        bool isWrite = request->cdb[0] == SCSI_OP_WRITE_10;
        if (length) {
            ScsiReadWrite(request, position, length, isWrite);
        } else {
            TRACE("AHCIPort::ScsiExecuteRequest error: transfer without "
                  "data!\n");
            request->subsys_status = SCSI_REQ_INVALID;
            gSCSI->finished(request, 1);
        }
        break;
    }
    case SCSI_OP_READ_12:
    case SCSI_OP_WRITE_12:
    {
        const scsi_cmd_rw_12 *cmd = (const scsi_cmd_rw_12 *)request->cdb;
        uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba);
        size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length);
        bool isWrite = request->cdb[0] == SCSI_OP_WRITE_12;
        if (length) {
            ScsiReadWrite(request, position, length, isWrite);
        } else {
            TRACE("AHCIPort::ScsiExecuteRequest error: transfer without "
                  "data!\n");
            request->subsys_status = SCSI_REQ_INVALID;
            gSCSI->finished(request, 1);
        }
        break;
    }
    case SCSI_OP_READ_16:
    case SCSI_OP_WRITE_16:
    {
        const scsi_cmd_rw_16 *cmd = (const scsi_cmd_rw_16 *)request->cdb;
        uint64 position = B_BENDIAN_TO_HOST_INT64(cmd->lba);
        size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length);
        bool isWrite = request->cdb[0] == SCSI_OP_WRITE_16;
        if (length) {
            ScsiReadWrite(request, position, length, isWrite);
        } else {
            TRACE("AHCIPort::ScsiExecuteRequest error: transfer without "
                  "data!\n");
            request->subsys_status = SCSI_REQ_INVALID;
            gSCSI->finished(request, 1);
        }
        break;
    }
    case SCSI_OP_WRITE_SAME_16:
    {
        const scsi_cmd_wsame_16 *cmd = (const scsi_cmd_wsame_16 *)request->cdb;

        // SCSI unmap is used for trim, otherwise we don't support it
        if (!cmd->unmap) {
            TRACE("%s port %d: unsupported request opcode 0x%02x\n",
                  __func__, fIndex, request->cdb[0]);
            request->subsys_status = SCSI_REQ_ABORTED;
            gSCSI->finished(request, 1);
            break;
        }

        if (!fTrim) {
            // Drive doesn't support trim (or atapi)
            // Just say it was successful and quit
            request->subsys_status = SCSI_REQ_CMP;
        } else {
            TRACE("%s unimplemented: TRIM call\n", __func__);
            // TODO: Make Serial ATA (sata_request?) trim call here.
            request->subsys_status = SCSI_REQ_ABORTED;
        }
        gSCSI->finished(request, 1);
        break;
    }
    default:
        TRACE("AHCIPort::ScsiExecuteRequest port %d unsupported request "
              "opcode 0x%02x\n", fIndex, request->cdb[0]);
        request->subsys_status = SCSI_REQ_ABORTED;
        gSCSI->finished(request, 1);
    }
}
Beispiel #2
0
void
AHCIPort::ScsiExecuteRequest(scsi_ccb* request)
{
//	TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length);

	if (fIsATAPI) {
		bool isWrite = false;
		switch (request->flags & SCSI_DIR_MASK) {
			case SCSI_DIR_NONE:
				ASSERT(request->data_length == 0);
				break;
			case SCSI_DIR_IN:
				ASSERT(request->data_length > 0);
				break;
			case SCSI_DIR_OUT:
				isWrite = true;
				ASSERT(request->data_length > 0);
				break;
			default:
				panic("CDB has invalid direction mask");
		}

//		TRACE("AHCIPort::ScsiExecuteRequest ATAPI: port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length);

		sata_request* sreq = new(std::nothrow) sata_request(request);
		if (sreq == NULL) {
			TRACE("out of memory when allocating atapi request\n");
			request->subsys_status = SCSI_REQ_ABORTED;
			gSCSI->finished(request, 1);
			return;
		}

		sreq->SetATAPICommand(request->data_length);
//		uint8* data = (uint8*) sreq->ccb()->cdb;
//		for (int i = 0; i < 16; i += 8) {
//			TRACE("  %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1], data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]);
//		}
		ExecuteSataRequest(sreq, isWrite);
		return;
	}

	if (request->cdb[0] == SCSI_OP_REQUEST_SENSE) {
		panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n");
		return;
	}

	if (!fDevicePresent) {
		TRACE("no device present on port %d\n", fIndex);
		request->subsys_status = SCSI_DEV_NOT_THERE;
		gSCSI->finished(request, 1);
		return;
	}

	request->subsys_status = SCSI_REQ_CMP;

	switch (request->cdb[0]) {
		case SCSI_OP_TEST_UNIT_READY:
			ScsiTestUnitReady(request);
			break;
		case SCSI_OP_INQUIRY:
			ScsiInquiry(request);
			break;
		case SCSI_OP_READ_CAPACITY:
			ScsiReadCapacity(request);
			break;
		case SCSI_OP_SERVICE_ACTION_IN:
			if ((request->cdb[1] & 0x1f) == SCSI_SAI_READ_CAPACITY_16)
				ScsiReadCapacity16(request);
			else {
				request->subsys_status = SCSI_REQ_INVALID;
				gSCSI->finished(request, 1);
			}
			break;
		case SCSI_OP_SYNCHRONIZE_CACHE:
			ScsiSynchronizeCache(request);
			break;
		case SCSI_OP_READ_6:
		case SCSI_OP_WRITE_6:
		{
			const scsi_cmd_rw_6* cmd = (const scsi_cmd_rw_6*)request->cdb;
			uint32 position = ((uint32)cmd->high_lba << 16)
				| ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba;
			size_t length = cmd->length != 0 ? cmd->length : 256;
			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_6;
			ScsiReadWrite(request, position, length, isWrite);
			break;
		}
		case SCSI_OP_READ_10:
		case SCSI_OP_WRITE_10:
		{
			const scsi_cmd_rw_10* cmd = (const scsi_cmd_rw_10*)request->cdb;
			uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba);
			size_t length = B_BENDIAN_TO_HOST_INT16(cmd->length);
			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_10;
			if (length) {
				ScsiReadWrite(request, position, length, isWrite);
			} else {
				TRACE("AHCIPort::ScsiExecuteRequest error: transfer without "
					"data!\n");
				request->subsys_status = SCSI_REQ_INVALID;
				gSCSI->finished(request, 1);
			}
			break;
		}
		case SCSI_OP_READ_12:
		case SCSI_OP_WRITE_12:
		{
			const scsi_cmd_rw_12* cmd = (const scsi_cmd_rw_12*)request->cdb;
			uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba);
			size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length);
			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_12;
			if (length) {
				ScsiReadWrite(request, position, length, isWrite);
			} else {
				TRACE("AHCIPort::ScsiExecuteRequest error: transfer without "
					"data!\n");
				request->subsys_status = SCSI_REQ_INVALID;
				gSCSI->finished(request, 1);
			}
			break;
		}
		case SCSI_OP_READ_16:
		case SCSI_OP_WRITE_16:
		{
			const scsi_cmd_rw_16* cmd = (const scsi_cmd_rw_16*)request->cdb;
			uint64 position = B_BENDIAN_TO_HOST_INT64(cmd->lba);
			size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length);
			bool isWrite = request->cdb[0] == SCSI_OP_WRITE_16;
			if (length) {
				ScsiReadWrite(request, position, length, isWrite);
			} else {
				TRACE("AHCIPort::ScsiExecuteRequest error: transfer without "
					"data!\n");
				request->subsys_status = SCSI_REQ_INVALID;
				gSCSI->finished(request, 1);
			}
			break;
		}
		case SCSI_OP_UNMAP:
		{
			const scsi_cmd_unmap* cmd = (const scsi_cmd_unmap*)request->cdb;

			if (!fTrimSupported) {
				TRACE("%s port %d: unsupported request opcode 0x%02x\n",
					__func__, fIndex, request->cdb[0]);
				request->subsys_status = SCSI_REQ_ABORTED;
				gSCSI->finished(request, 1);
				break;
			}

			scsi_unmap_parameter_list* unmapBlocks
				= (scsi_unmap_parameter_list*)request->data;
			if (unmapBlocks == NULL
				|| B_BENDIAN_TO_HOST_INT16(cmd->length) != request->data_length
				|| B_BENDIAN_TO_HOST_INT16(unmapBlocks->data_length)
					!= request->data_length - 1) {
				TRACE("%s port %d: invalid unmap parameter data length\n",
					__func__, fIndex);
				request->subsys_status = SCSI_REQ_ABORTED;
				gSCSI->finished(request, 1);
			} else {
				ScsiUnmap(request, unmapBlocks);
			}
			break;
		}
		default:
			TRACE("AHCIPort::ScsiExecuteRequest port %d unsupported request "
				"opcode 0x%02x\n", fIndex, request->cdb[0]);
			request->subsys_status = SCSI_REQ_ABORTED;
			gSCSI->finished(request, 1);
	}
}