static bool scan_device_int(ide_device_info *device, bool atapi) { ide_bus_info *bus = device->bus; int status; TRACE("scan_device_int: device %p, atapi %d\n", device, atapi); device->tf_param_mask = 0; device->tf.write.command = atapi ? IDE_CMD_IDENTIFY_PACKET_DEVICE : IDE_CMD_IDENTIFY_DEVICE; // initialize device selection flags, // this is the only place where this bit gets initialized in the task file if (bus->controller->read_command_block_regs(bus->channel_cookie, &device->tf, ide_mask_device_head) != B_OK) { TRACE("scan_device_int: read_command_block_regs failed\n"); return false; } device->tf.lba.device = device->is_device1; if (!send_command(device, NULL, atapi ? false : true, 20, ide_state_sync_waiting)) { TRACE("scan_device_int: send_command failed\n"); return false; } // do a short wait first - if there's no device at all we could wait forever // ToDo: have a look at this; if it times out (when the time is too short), // the kernel seems to crash a little later)! TRACE("scan_device_int: waiting 100ms...\n"); if (acquire_sem_etc(bus->sync_wait_sem, 1, B_RELATIVE_TIMEOUT, 100000) == B_TIMED_OUT) { bool cont; TRACE("scan_device_int: no fast response to inquiry\n"); // check the busy flag - if it's still set, there's probably no device IDE_LOCK(bus); status = bus->controller->get_altstatus(bus->channel_cookie); cont = (status & ide_status_bsy) == ide_status_bsy; IDE_UNLOCK(bus); TRACE("scan_device_int: status %#04x\n", status); if (!cont) { TRACE("scan_device_int: busy bit not set after 100ms - probably noone there\n"); // no reaction -> abort waiting cancel_irq_timeout(bus); // timeout or irq may have been fired, reset semaphore just is case acquire_sem_etc(bus->sync_wait_sem, 1, B_RELATIVE_TIMEOUT, 0); TRACE("scan_device_int: aborting because busy bit not set\n"); return false; } TRACE("scan_device_int: busy bit set, give device more time\n"); // there is something, so wait for it acquire_sem(bus->sync_wait_sem); } TRACE("scan_device_int: got a fast response\n"); // cancel the timeout manually; usually this is done by wait_for_sync(), but // we've used the wait semaphore directly cancel_irq_timeout(bus); if (bus->sync_wait_timeout) { TRACE("scan_device_int: aborting on sync_wait_timeout\n"); return false; } ide_wait(device, ide_status_drq, ide_status_bsy, true, 1000); status = bus->controller->get_altstatus(bus->channel_cookie); if ((status & ide_status_err) != 0) { // if there's no device, all bits including the error bit are set TRACE("scan_device_int: error bit set - no device or wrong type (status: %#04x)\n", status); return false; } // get the infoblock bus->controller->read_pio(bus->channel_cookie, (uint16 *)&device->infoblock, sizeof(device->infoblock) / sizeof(uint16), false); if (!wait_for_drqdown(device)) { TRACE("scan_device_int: wait_for_drqdown failed\n"); return false; } TRACE("scan_device_int: device found\n"); prep_infoblock(device); return true; }
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; }
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); }