void AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount, bool isWrite) { RWTRACE("[%lld] %ld ScsiReadWrite: position %llu, size %lu, isWrite %d\n", system_time(), find_thread(NULL), lba * 512, sectorCount * 512, isWrite); #if 0 if (isWrite) { TRACE("write request ignored\n"); request->subsys_status = SCSI_REQ_CMP; request->data_resid = 0; gSCSI->finished(request, 1); return; } #endif ASSERT(request->data_length == sectorCount * 512); sata_request *sreq = new(std::nothrow) sata_request(request); if (fUse48BitCommands) { if (sectorCount > 65536) panic("ahci: ScsiReadWrite length too large, %lu sectors", sectorCount); if (lba > MAX_SECTOR_LBA_48) panic("achi: ScsiReadWrite position too large for 48-bit LBA\n"); sreq->set_ata48_cmd(isWrite ? 0x35 : 0x25, lba, sectorCount); } else { if (sectorCount > 256) panic("ahci: ScsiReadWrite length too large, %lu sectors", sectorCount); if (lba > MAX_SECTOR_LBA_28) panic("achi: ScsiReadWrite position too large for normal LBA\n"); sreq->set_ata28_cmd(isWrite ? 0xca : 0xc8, lba, sectorCount); } ExecuteSataRequest(sreq, isWrite); }
void AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) { // Determine how many ranges we'll need // We assume that the SCSI unmap ranges cannot be merged together uint32 scsiRangeCount = B_BENDIAN_TO_HOST_INT16( unmapBlocks->block_data_length) / sizeof(scsi_unmap_block_descriptor); uint32 lbaRangeCount = 0; for (uint32 i = 0; i < scsiRangeCount; i++) { lbaRangeCount += ((uint32)B_BENDIAN_TO_HOST_INT32( unmapBlocks->blocks[i].block_count) + 65534) / 65535; } uint32 lbaRangesSize = lbaRangeCount * sizeof(uint64); uint64* lbaRanges = (uint64*)malloc(lbaRangesSize); if (lbaRanges == NULL) { TRACE("out of memory when allocating %" B_PRIu32 " unmap ranges\n", lbaRangeCount); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); return; } MemoryDeleter deleter(lbaRanges); for (uint32 i = 0, scsiIndex = 0; scsiIndex < scsiRangeCount; scsiIndex++) { uint64 lba = (uint64)B_BENDIAN_TO_HOST_INT64( unmapBlocks->blocks[scsiIndex].lba); uint64 blocksLeft = (uint32)B_BENDIAN_TO_HOST_INT32( unmapBlocks->blocks[scsiIndex].block_count); while (blocksLeft > 0) { uint16 blocks = blocksLeft > 65535 ? 65535 : (uint16)blocksLeft; lbaRanges[i++] = B_HOST_TO_LENDIAN_INT64( ((uint64)blocks << 48) | lba); lba += blocks; blocksLeft -= blocks; } } sata_request sreq; sreq.SetATA48Command(ATA_COMMAND_DATA_SET_MANAGEMENT, 0, (lbaRangesSize + 511) / 512); sreq.SetFeature(1); sreq.SetData(lbaRanges, lbaRangesSize); ExecuteSataRequest(&sreq); sreq.WaitForCompletion(); if ((sreq.CompletionStatus() & ATA_ERR) != 0) { TRACE("trim failed (%" B_PRIu32 " ranges)!\n", lbaRangeCount); request->subsys_status = SCSI_REQ_CMP_ERR; } else request->subsys_status = SCSI_REQ_CMP; request->data_resid = 0; request->device_status = SCSI_STATUS_GOOD; gSCSI->finished(request, 1); }
void AHCIPort::ScsiSynchronizeCache(scsi_ccb *request) { //TRACE("AHCIPort::ScsiSynchronizeCache port %d\n", fIndex); sata_request *sreq = new(std::nothrow) sata_request(request); sreq->set_ata_cmd(fUse48BitCommands ? 0xea : 0xe7); // Flush Cache ExecuteSataRequest(sreq); }
void AHCIPort::ScsiReadWrite(scsi_ccb* request, uint64 lba, size_t sectorCount, bool isWrite) { RWTRACE("[%lld] %ld ScsiReadWrite: position %llu, size %lu, isWrite %d\n", system_time(), find_thread(NULL), lba * 512, sectorCount * 512, isWrite); #if 0 if (isWrite) { TRACE("write request ignored\n"); request->subsys_status = SCSI_REQ_CMP; request->data_resid = 0; gSCSI->finished(request, 1); return; } #endif ASSERT(request->data_length == sectorCount * 512); sata_request* sreq = new(std::nothrow) sata_request(request); if (sreq == NULL) { TRACE("out of memory when allocating read/write request\n"); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); return; } if (fUse48BitCommands) { if (sectorCount > 65536) { panic("ahci: ScsiReadWrite length too large, %lu sectors", sectorCount); } if (lba > MAX_SECTOR_LBA_48) panic("achi: ScsiReadWrite position too large for 48-bit LBA\n"); sreq->SetATA48Command( isWrite ? ATA_COMMAND_WRITE_DMA_EXT : ATA_COMMAND_READ_DMA_EXT, lba, sectorCount); } else { if (sectorCount > 256) { panic("ahci: ScsiReadWrite length too large, %lu sectors", sectorCount); } if (lba > MAX_SECTOR_LBA_28) panic("achi: ScsiReadWrite position too large for normal LBA\n"); sreq->SetATA28Command(isWrite ? ATA_COMMAND_WRITE_DMA : ATA_COMMAND_READ_DMA, lba, sectorCount); } ExecuteSataRequest(sreq, isWrite); }
void AHCIPort::ScsiSynchronizeCache(scsi_ccb *request) { //TRACE("AHCIPort::ScsiSynchronizeCache port %d\n", fIndex); sata_request *sreq = new(std::nothrow) sata_request(request); if (sreq == NULL) { TRACE("out of memory when allocating sync request\n"); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); return; } sreq->set_ata_cmd(fUse48BitCommands ? 0xea : 0xe7); // Flush Cache ExecuteSataRequest(sreq); }
void AHCIPort::ScsiSynchronizeCache(scsi_ccb* request) { //TRACE("AHCIPort::ScsiSynchronizeCache port %d\n", fIndex); sata_request* sreq = new(std::nothrow) sata_request(request); if (sreq == NULL) { TRACE("out of memory when allocating sync request\n"); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); return; } sreq->SetATACommand(fUse48BitCommands ? ATA_COMMAND_FLUSH_CACHE_EXT : ATA_COMMAND_FLUSH_CACHE); ExecuteSataRequest(sreq); }
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); } }
void AHCIPort::ScsiInquiry(scsi_ccb *request) { TRACE("AHCIPort::ScsiInquiry port %d\n", fIndex); const scsi_cmd_inquiry *cmd = (const scsi_cmd_inquiry *)request->cdb; scsi_res_inquiry scsiData; ata_device_infoblock ataData; ASSERT(sizeof(ataData) == 512); if (cmd->evpd || cmd->page_code || request->data_length < sizeof(scsiData)) { TRACE("invalid request\n"); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); return; } sata_request sreq; sreq.set_data(&ataData, sizeof(ataData)); sreq.set_ata_cmd(fIsATAPI ? 0xa1 : 0xec); // Identify (Packet) Device ExecuteSataRequest(&sreq); sreq.wait_for_completion(); if (sreq.completion_status() & ATA_ERR) { TRACE("identify device failed\n"); request->subsys_status = SCSI_REQ_CMP_ERR; gSCSI->finished(request, 1); return; } /* uint8 *data = (uint8*) &ataData; for (int i = 0; i < 512; 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]); } */ scsiData.device_type = fIsATAPI ? ataData.word_0.atapi.command_packet_set : scsi_dev_direct_access; scsiData.device_qualifier = scsi_periph_qual_connected; scsiData.device_type_modifier = 0; scsiData.removable_medium = ataData.word_0.ata.removable_media_device; scsiData.ansi_version = 2; scsiData.ecma_version = 0; scsiData.iso_version = 0; scsiData.response_data_format = 2; scsiData.term_iop = false; scsiData.additional_length = sizeof(scsi_res_inquiry) - 4; scsiData.soft_reset = false; scsiData.cmd_queue = false; scsiData.linked = false; scsiData.sync = false; scsiData.write_bus16 = true; scsiData.write_bus32 = false; scsiData.relative_address = false; if (!fIsATAPI) { fSectorCount = ataData.SectorCount(fUse48BitCommands, true); fSectorSize = ataData.SectorSize(); fTrim = ataData.data_set_management_support; TRACE("lba %d, lba48 %d, fUse48BitCommands %d, sectors %" B_PRIu32 ", sectors48 %" B_PRIu64 ", size %" B_PRIu64 "\n", ataData.dma_supported != 0, ataData.lba48_supported != 0, fUse48BitCommands, ataData.lba_sector_count, ataData.lba48_sector_count, fSectorCount * fSectorSize); } #if 0 if (fSectorCount < 0x0fffffff) { TRACE("disabling 48 bit commands\n"); fUse48BitCommands = 0; } #endif char modelNumber[sizeof(ataData.model_number) + 1]; char serialNumber[sizeof(ataData.serial_number) + 1]; char firmwareRev[sizeof(ataData.firmware_revision) + 1]; strlcpy(modelNumber, ataData.model_number, sizeof(modelNumber)); strlcpy(serialNumber, ataData.serial_number, sizeof(serialNumber)); strlcpy(firmwareRev, ataData.firmware_revision, sizeof(firmwareRev)); swap_words(modelNumber, sizeof(modelNumber) - 1); swap_words(serialNumber, sizeof(serialNumber) - 1); swap_words(firmwareRev, sizeof(firmwareRev) - 1); TRACE("model number: %s\n", modelNumber); TRACE("serial number: %s\n", serialNumber); TRACE("firmware rev.: %s\n", firmwareRev); TRACE("trim support: %s\n", fTrim ? "yes" : "no"); // There's not enough space to fit all of the data in. ATA has 40 bytes for // the model number, 20 for the serial number and another 8 for the // firmware revision. SCSI has room for 8 for vendor ident, 16 for product // ident and another 4 for product revision. We just try and fit in as much // as possible of the model number into the vendor and product ident fields // and put a little of the serial number into the product revision field. memcpy(scsiData.vendor_ident, modelNumber, sizeof(scsiData.vendor_ident)); memcpy(scsiData.product_ident, modelNumber + 8, sizeof(scsiData.product_ident)); memcpy(scsiData.product_rev, serialNumber, sizeof(scsiData.product_rev)); if (sg_memcpy(request->sg_list, request->sg_count, &scsiData, sizeof(scsiData)) < B_OK) { request->subsys_status = SCSI_DATA_RUN_ERR; } else { request->subsys_status = SCSI_REQ_CMP; request->data_resid = request->data_length - sizeof(scsiData); } gSCSI->finished(request, 1); }
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); 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_SYNCHRONIZE_CACHE: ScsiSynchronizeCache(request); break; case SCSI_OP_READ_6: case SCSI_OP_WRITE_6: { scsi_cmd_rw_6 *cmd = (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: { scsi_cmd_rw_10 *cmd = (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: { scsi_cmd_rw_12 *cmd = (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; } 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); } }
void AHCIPort::ScsiInquiry(scsi_ccb *request) { TRACE("AHCIPort::ScsiInquiry port %d\n", fIndex); scsi_cmd_inquiry *cmd = (scsi_cmd_inquiry *)request->cdb; scsi_res_inquiry scsiData; ata_res_identify_device ataData; ASSERT(sizeof(ataData) == 512); if (cmd->evpd || cmd->page_code || request->data_length < sizeof(scsiData)) { TRACE("invalid request\n"); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); return; } sata_request sreq; sreq.set_data(&ataData, sizeof(ataData)); sreq.set_ata_cmd(fIsATAPI ? 0xa1 : 0xec); // Identify (Packet) Device ExecuteSataRequest(&sreq); sreq.wait_for_completition(); if (sreq.completition_status() & ATA_ERR) { TRACE("identify device failed\n"); request->subsys_status = SCSI_REQ_CMP_ERR; gSCSI->finished(request, 1); return; } /* uint8 *data = (uint8*) &ataData; for (int i = 0; i < 512; 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]); } */ scsiData.device_type = fIsATAPI ? scsi_dev_CDROM : scsi_dev_direct_access; scsiData.device_qualifier = scsi_periph_qual_connected; scsiData.device_type_modifier = 0; scsiData.removable_medium = fIsATAPI; scsiData.ansi_version = 2; scsiData.ecma_version = 0; scsiData.iso_version = 0; scsiData.response_data_format = 2; scsiData.term_iop = false; scsiData.additional_length = sizeof(scsiData) - 4; scsiData.soft_reset = false; scsiData.cmd_queue = false; scsiData.linked = false; scsiData.sync = false; scsiData.write_bus16 = true; scsiData.write_bus32 = false; scsiData.relative_address = false; memcpy(scsiData.vendor_ident, ataData.model_number, sizeof(scsiData.vendor_ident)); memcpy(scsiData.product_ident, ataData.model_number + 8, sizeof(scsiData.product_ident)); memcpy(scsiData.product_rev, ataData.serial_number, sizeof(scsiData.product_rev)); if (!fIsATAPI) { bool lba = (ataData.words[49] & (1 << 9)) != 0; bool lba48 = (ataData.words[83] & (1 << 10)) != 0; uint32 sectors = *(uint32*)&ataData.words[60]; uint64 sectors48 = *(uint64*)&ataData.words[100]; fUse48BitCommands = lba && lba48; fSectorSize = 512; fSectorCount = !(lba || sectors) ? 0 : lba48 ? sectors48 : sectors; TRACE("lba %d, lba48 %d, fUse48BitCommands %d, sectors %lu, " "sectors48 %llu, size %llu\n", lba, lba48, fUse48BitCommands, sectors, sectors48, fSectorCount * fSectorSize); } #if 0 if (fSectorCount < 0x0fffffff) { TRACE("disabling 48 bit commands\n"); fUse48BitCommands = 0; } #endif char modelNumber[sizeof(ataData.model_number) + 1]; char serialNumber[sizeof(ataData.serial_number) + 1]; char firmwareRev[sizeof(ataData.firmware_revision) + 1]; strlcpy(modelNumber, ataData.model_number, sizeof(modelNumber)); strlcpy(serialNumber, ataData.serial_number, sizeof(serialNumber)); strlcpy(firmwareRev, ataData.firmware_revision, sizeof(firmwareRev)); swap_words(modelNumber, sizeof(modelNumber) - 1); swap_words(serialNumber, sizeof(serialNumber) - 1); swap_words(firmwareRev, sizeof(firmwareRev) - 1); TRACE("model number: %s\n", modelNumber); TRACE("serial number: %s\n", serialNumber); TRACE("firmware rev.: %s\n", firmwareRev); if (sg_memcpy(request->sg_list, request->sg_count, &scsiData, sizeof(scsiData)) < B_OK) { request->subsys_status = SCSI_DATA_RUN_ERR; } else { request->subsys_status = SCSI_REQ_CMP; request->data_resid = request->data_length - sizeof(scsiData); } gSCSI->finished(request, 1); }
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); } }