void ata_dpc_DMA(ide_qrequest *qrequest) { ide_device_info *device = qrequest->device; bool dma_success, dev_err; dma_success = finish_dma(device); dev_err = check_rw_error(device, qrequest); if (dma_success && !dev_err) { // reset error count if DMA worked device->DMA_failures = 0; device->CQ_failures = 0; qrequest->request->data_resid = 0; finish_checksense(qrequest); } else { SHOW_ERROR0( 2, "Error in DMA transmission" ); set_sense(device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_LUN_COM_FAILURE); if (++device->DMA_failures >= MAX_DMA_FAILURES) { SHOW_ERROR0( 2, "Disabled DMA because of too many errors" ); device->DMA_enabled = false; } // reset queue in case queuing is active finish_reset_queue(qrequest); } }
static void finish_setsense( ide_device_info *device, ide_qrequest *qrequest, int sense_key, int sense_asc ) { set_sense( device, sense_key, sense_asc ); finish_checksense( qrequest ); }
void finish_reset_queue( ide_qrequest *qrequest ) { ide_bus_info *bus = qrequest->device->bus; xpt->block_bus( bus->xpt_cookie ); finish_checksense( qrequest ); send_abort_queue( qrequest->device ); xpt->unblock_bus( bus->xpt_cookie ); }
void ata_dpc_DMA( ide_qrequest *qrequest ) { ide_device_info *device = qrequest->device; //ide_bus_info *bus = device->bus; bool dma_err, dev_err; dma_err = finish_dma( device ); dev_err = check_rw_error( device, qrequest ); if( !dma_err && !dev_err ) { device->DMA_failures = 0; device->CQ_failures = 0; qrequest->request->cam_resid = 0; finish_checksense( qrequest ); } else { if( ++device->DMA_failures == MAX_DMA_FAILURES ) { device->DMA_enabled = false; finish_reset_queue( qrequest ); } else { finish_retry( qrequest ); } } }
void ata_dpc_PIO( ide_qrequest *qrequest ) { ide_device_info *device = qrequest->device; bigtime_t timeout = qrequest->request->cam_timeout > 0 ? qrequest->request->cam_timeout : IDE_STD_TIMEOUT; if( !check_rw_error( device, qrequest ) || !check_rw_status( device, qrequest, qrequest->is_write ? device->left_blocks > 1 : true )) { /*if( (device->sense.sense_key == SCSIS_KEY_ABORTED_COMMAND || device->sense.ascq == SCSIS_ASC_UNREC_READ_ERR) && ++qrequest->retries < MAX_PIO_RETRIES ) { finish_rw_request( qrequest, ide_finish_rw_retry ); } else*/ finish_checksense( qrequest ); return; } if( qrequest->is_write ) { if( device->left_blocks == 0 ) goto finish; if( !wait_for_drq( device )) goto finish; start_waiting_nolock( device->bus, timeout, ide_state_async_waiting ); // having a too short data buffer shouldn't happen here // anyway - we are prepared if( write_PIO_block( qrequest, 512 ) == ERR_GENERAL ) goto finish_cancel_timeout; --device->left_blocks; } else { if( device->left_blocks > 0 ) start_waiting_nolock( device->bus, timeout, ide_state_async_waiting ); // see write if( read_PIO_block( qrequest, 512 ) == ERR_GENERAL ) goto finish_cancel_timeout; --device->left_blocks; if( device->left_blocks == 0 ) { wait_for_drqdown( device ); goto finish_cancel_timeout; } } //start_waiting( device->bus ); return; finish_cancel_timeout: cancel_irq_timeout( device->bus ); finish: finish_checksense( qrequest ); return; }
/*! Execute SCSI command */ void ata_exec_io(ide_device_info *device, ide_qrequest *qrequest) { scsi_ccb *request = qrequest->request; SHOW_FLOW(3, "command=%x", request->cdb[0]); // ATA devices have one LUN only if (request->target_lun != 0) { request->subsys_status = SCSI_SEL_TIMEOUT; finish_request(qrequest, false); return; } // starting a request means deleting sense, so don't do it if // the command wants to read it if (request->cdb[0] != SCSI_OP_REQUEST_SENSE) start_request(device, qrequest); switch (request->cdb[0]) { case SCSI_OP_TEST_UNIT_READY: ata_test_unit_ready(device, qrequest); break; case SCSI_OP_REQUEST_SENSE: ide_request_sense(device, qrequest); return; case SCSI_OP_FORMAT: /* FORMAT UNIT */ // we could forward request to disk, but modern disks cannot // be formatted anyway, so we just refuse request // (exceptions are removable media devices, but to my knowledge // they don't have to be formatted as well) set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); break; case SCSI_OP_INQUIRY: ata_inquiry(device, qrequest); break; case SCSI_OP_MODE_SELECT_10: ata_mode_select_10(device, qrequest); break; case SCSI_OP_MODE_SENSE_10: ata_mode_sense_10(device, qrequest); break; case SCSI_OP_MODE_SELECT_6: case SCSI_OP_MODE_SENSE_6: // we've told SCSI bus manager to emulates these commands set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); break; case SCSI_OP_RESERVE: case SCSI_OP_RELEASE: // though mandatory, this doesn't make much sense in a // single initiator environment; so what set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); break; case SCSI_OP_START_STOP: { scsi_cmd_ssu *cmd = (scsi_cmd_ssu *)request->cdb; // with no LoEj bit set, we should only allow/deny further access // we ignore that (unsupported for ATA) // with LoEj bit set, we should additionally either load or eject the medium // (start = 0 - eject; start = 1 - load) if (!cmd->start) // we must always flush cache if start = 0 ata_flush_cache(device, qrequest); if (cmd->load_eject) ata_load_eject(device, qrequest, cmd->start); break; } case SCSI_OP_PREVENT_ALLOW: { scsi_cmd_prevent_allow *cmd = (scsi_cmd_prevent_allow *)request->cdb; ata_prevent_allow(device, cmd->prevent); break; } case SCSI_OP_READ_CAPACITY: read_capacity(device, qrequest); break; case SCSI_OP_VERIFY: // does anyone uses this function? // effectly, it does a read-and-compare, which IDE doesn't support set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); break; case SCSI_OP_SYNCHRONIZE_CACHE: // we ignore range and immediate bit, we always immediately flush everything ata_flush_cache(device, qrequest); break; // sadly, there are two possible read/write operation codes; // at least, the third one, read/write(12), is not valid for DAS case SCSI_OP_READ_6: case SCSI_OP_WRITE_6: { scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb; uint32 pos; size_t length; pos = ((uint32)cmd->high_lba << 16) | ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba; length = cmd->length != 0 ? cmd->length : 256; SHOW_FLOW(3, "READ6/WRITE6 pos=%lx, length=%lx", pos, length); ata_send_rw(device, qrequest, pos, length, cmd->opcode == SCSI_OP_WRITE_6); return; } case SCSI_OP_READ_10: case SCSI_OP_WRITE_10: { scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb; uint32 pos; size_t length; pos = B_BENDIAN_TO_HOST_INT32(cmd->lba); length = B_BENDIAN_TO_HOST_INT16(cmd->length); if (length != 0) { ata_send_rw(device, qrequest, pos, length, cmd->opcode == SCSI_OP_WRITE_10); } else { // we cannot transfer zero blocks (apart from LBA48) finish_request(qrequest, false); } return; } default: set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); } finish_checksense(qrequest); }
void ata_dpc_PIO(ide_qrequest *qrequest) { ide_device_info *device = qrequest->device; uint32 timeout = qrequest->request->timeout > 0 ? qrequest->request->timeout : IDE_STD_TIMEOUT; SHOW_FLOW0(3, ""); if (check_rw_error(device, qrequest) || !check_rw_status(device, qrequest->is_write ? device->left_blocks > 0 : true)) { // failure reported by device SHOW_FLOW0( 3, "command finished unsuccessfully" ); finish_checksense(qrequest); return; } if (qrequest->is_write) { if (device->left_blocks == 0) { // this was the end-of-transmission IRQ SHOW_FLOW0(3, "write access finished"); if (!wait_for_drqdown(device)) { SHOW_ERROR0(3, "device wants to transmit data though command is finished"); goto finish; } goto finish; } // wait until device requests data SHOW_FLOW0(3, "Waiting for device ready to transmit"); if (!wait_for_drq(device)) { SHOW_FLOW0(3, "device not ready for data transmission - abort"); goto finish; } // start async waiting for next block/end of command // we should start that when block is transmitted, but with bad // luck the IRQ fires exactly between transmission and start of waiting, // so we better start waiting too early; as we are in service thread, // a DPC initiated by IRQ cannot overtake us, so there is no need to block // IRQs during sent start_waiting_nolock(device->bus, timeout, ide_state_async_waiting); // having a too short data buffer shouldn't happen here // anyway - we are prepared SHOW_FLOW0(3, "Writing one block"); if (write_PIO_block(qrequest, 512) == B_ERROR) goto finish_cancel_timeout; --device->left_blocks; } else { if (device->left_blocks > 1) { // start async waiting for next command (see above) start_waiting_nolock(device->bus, timeout, ide_state_async_waiting); } // see write SHOW_FLOW0( 3, "Reading one block" ); if (read_PIO_block(qrequest, 512) == B_ERROR) goto finish_cancel_timeout; --device->left_blocks; if (device->left_blocks == 0) { // at end of transmission, wait for data request going low SHOW_FLOW0( 3, "Waiting for device to finish transmission" ); if (!wait_for_drqdown(device)) SHOW_FLOW0( 3, "Device continues data transmission - abort command" ); // we don't cancel timeout as no timeout is started during last block goto finish; } } return; finish_cancel_timeout: cancel_irq_timeout(device->bus); finish: finish_checksense(qrequest); }