/*! Start waiting for DMA to be finished with bus lock not hold */ void start_dma_wait_no_lock(ide_device_info *device, ide_qrequest *qrequest) { ide_bus_info *bus = device->bus; IDE_LOCK(bus); start_dma_wait(device, qrequest); }
bool send_command(ide_device_info *device, ide_qrequest *qrequest, bool need_drdy, uint32 timeout, ide_bus_state new_state) { ide_bus_info *bus = device->bus; bigtime_t irq_disabled_at = 0; // make compiler happy uint8 num_retries = 0; bool irq_guard; retry: irq_guard = bus->num_running_reqs > 1; SHOW_FLOW(3, "qrequest=%p, request=%p", qrequest, qrequest ? qrequest->request : NULL); // if there are pending requests, IRQs must be disabled to // not mix up IRQ reasons // XXX can we avoid that with the IDE_LOCK trick? It would // save some work and the bug workaround! if (irq_guard) { if (bus->controller->write_device_control(bus->channel_cookie, ide_devctrl_nien | ide_devctrl_bit3) != B_OK) goto err; irq_disabled_at = system_time(); } // select device if (bus->controller->write_command_block_regs(bus->channel_cookie, &device->tf, ide_mask_device_head) != B_OK) goto err; bus->active_device = device; if (!ide_wait(device, 0, ide_status_bsy | ide_status_drq, false, 50000)) { uint8 status; SHOW_FLOW0(1, "device is not ready"); status = bus->controller->get_altstatus(bus->channel_cookie); if (status == 0xff) { // there is no device (should happen during detection only) SHOW_FLOW0(1, "there is no device"); // device detection recognizes this code as "all hope lost", so // neither replace it nor use it anywhere else device->subsys_status = SCSI_TID_INVALID; return false; } // reset device and retry if (reset_device(device, qrequest) && ++num_retries <= MAX_FAILED_SEND) { SHOW_FLOW0(1, "retrying"); goto retry; } SHOW_FLOW0(1, "giving up"); // reset to often - abort request device->subsys_status = SCSI_SEL_TIMEOUT; return false; } if (need_drdy && (bus->controller->get_altstatus(bus->channel_cookie) & ide_status_drdy) == 0) { SHOW_FLOW0(3, "drdy not set"); device->subsys_status = SCSI_SEQUENCE_FAIL; return false; } // write parameters if (bus->controller->write_command_block_regs(bus->channel_cookie, &device->tf, device->tf_param_mask) != B_OK) goto err; if (irq_guard) { // IRQ may be fired by service requests and by the process of disabling(!) // them (I heard this is caused by edge triggered PCI IRQs) // wait at least 50 µs to catch all pending irq's // (at my system, up to 30 µs elapsed) // additionally, old drives (at least my IBM-DTTA-351010) loose // sync if they are pushed too hard - on heavy overlapped write // stress this drive tends to forget outstanding requests, // waiting at least 50 µs seems(!) to solve this while (system_time() - irq_disabled_at < MAX_IRQ_DELAY) spin(1); } // if we will start waiting once the command is sent, we have to // lock the bus before sending; this way, IRQs that are fired // shortly before/after sending of command are delayed until the // command is really sent (start_waiting unlocks the bus) and then // the IRQ handler can check savely whether the IRQ really signals // finishing of command or not by testing the busy-signal of the device if (new_state != ide_state_accessing) { IDE_LOCK(bus); } if (irq_guard) { // now it's clear why IRQs gets fired, so we can enable them again if (bus->controller->write_device_control(bus->channel_cookie, ide_devctrl_bit3) != B_OK) goto err1; } // write command code - this will start the actual command SHOW_FLOW(3, "Writing command 0x%02x", (int)device->tf.write.command); if (bus->controller->write_command_block_regs(bus->channel_cookie, &device->tf, ide_mask_command) != B_OK) goto err1; // start waiting now; also un-blocks IRQ handler (see above) if (new_state != ide_state_accessing) start_waiting(bus, timeout, new_state); return true; err1: if (timeout > 0) { bus->state = ide_state_accessing; IDE_UNLOCK(bus); } err: device->subsys_status = SCSI_HBA_ERR; return false; }
static inline void scsi_io( ide_bus_info *bus, CCB_HEADER *ccb ) { CCB_SCSIIO *request = (CCB_SCSIIO *)ccb; ide_device_info *device; bool queuable; ide_qrequest *qrequest; //ide_request_priv *priv; if( ccb->cam_target_id >= 2 || ccb->cam_target_lun != 0 ) goto err_inv_device; device = bus->devices[ccb->cam_target_id]; if( device == NULL ) goto err_inv_device; queuable = is_queuable( device, request ); IDE_LOCK( bus ); if( bus->state != ide_state_idle ) goto err_bus_busy; if( device->free_qrequests == NULL || (device->num_running_reqs > 0 && !queuable )) goto err_device_busy; bus->state = ide_state_accessing; IDE_UNLOCK( bus ); qrequest = device->free_qrequests; device->free_qrequests = qrequest->next; qrequest->request = request; qrequest->queuable = queuable; qrequest->running = true; /*priv = get_request_priv( request ); priv->qrequest = qrequest; priv->device = device;*/ ++device->num_running_reqs; ++bus->num_running_reqs; bus->active_qrequest = qrequest; device->exec_io( device, qrequest ); return; err_inv_device: ccb->cam_status = CAM_SEL_TIMEOUT; xpt->done( ccb ); return; err_bus_busy: //xpt->block_bus( bus->xpt_cookie ); ccb->cam_status = CAM_BUS_QUEUE_FULL; xpt->done( ccb ); IDE_UNLOCK( bus ); return; err_device_busy: //xpt->block_device( bus->xpt_cookie, ccb->cam_target_id, 0 ); ccb->cam_status = CAM_DEV_QUEUE_FULL; xpt->done( ccb ); IDE_UNLOCK( bus ); return; }
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; }
// new_state must be either accessing, async_waiting or sync_waiting // param_mask must not include command register bool send_command( ide_device_info *device, bool need_drdy, bigtime_t timeout, ide_bus_state new_state ) { ide_bus_info *bus = device->bus; bigtime_t irq_disabled_at = 0; // make compiler happy bool irq_guard = bus->num_running_reqs > 1; SHOW_FLOW0( 3, "" ); reset_timeouts( device ); if( irq_guard ) { if( bus->controller->write_device_control( bus->channel, ide_devctrl_nien | ide_devctrl_bit3 ) != NO_ERROR ) goto err; irq_disabled_at = system_time(); } if( bus->controller->write_command_block_regs( bus->channel, &device->tf, ide_mask_device_head ) != NO_ERROR ) goto err; SHOW_FLOW0( 3, "1" ); bus->active_device = device; if( !ide_wait( device, 0, ide_status_bsy | ide_status_drq, false, 50000 )) { uint8 status; SHOW_FLOW0( 1, "device is not ready" ); status = bus->controller->get_altstatus( bus->channel ); if( status == 0xff ) { // this shouldn't happen unless the device has died // as we only submit commands to existing devices // (only detection routines shoot at will) set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE ); return false; } if( !reset_bus( device )) return false; SHOW_FLOW0( 1, "retrying" ); if( bus->controller->write_command_block_regs( bus->channel, &device->tf, ide_mask_device_head ) != NO_ERROR ) goto err; bus->active_device = device; if( !ide_wait( device, 0, ide_status_bsy | ide_status_drq, false, 50000 )) { // XXX this is not a device but a bus error, we should return // CAM_SEL_TIMEOUT instead SHOW_FLOW0( 1, "device is dead" ); set_sense( device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_LUN_SEL_FAILED ); return false; } } SHOW_FLOW0( 3, "3" ); if( need_drdy && (bus->controller->get_altstatus( bus->channel ) & ide_status_drdy) == 0 ) { SHOW_FLOW0( 3, "drdy not set" ); set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_LUN_TIMEOUT ); return false; } SHOW_FLOW0( 3, "4" ); if( bus->controller->write_command_block_regs( bus->channel, &device->tf, device->tf_param_mask ) != NO_ERROR ) goto err; SHOW_FLOW0( 3, "5" ); if( irq_guard ) { // enable IRQs now // IRQ may be fired by service requests and by the process of disabling(!) // them (I heard this is caused by edge triggered PCI IRQs) // wait at least 50 µs to catch all pending irq's // (at my system, up to 30 µs elapsed) // additionally, old drives (at least my IBM-DTTA-351010) loose // sync if they are pushed too hard - on heavy overlapped write // stress this drive tends to forget outstanding requests, // waiting at least 50 µs seems(!) to solve this while( system_time() - irq_disabled_at < MAX_IRQ_DELAY ) cpu_spin( 1 ); } SHOW_FLOW0( 3, "6" ); if( new_state != ide_state_accessing ) { IDE_LOCK( bus ); } SHOW_FLOW( 3, "Writing command %x", (int)device->tf.write.command ); if( bus->controller->write_command_block_regs( bus->channel, &device->tf, ide_mask_command ) != NO_ERROR ) goto err2; SHOW_FLOW0( 3, "7" ); if( irq_guard ) { if( bus->controller->write_device_control( bus->channel, ide_devctrl_bit3 ) != NO_ERROR ) goto err1; } SHOW_FLOW0( 3, "8" ); if( new_state != ide_state_accessing ) { start_waiting( bus, timeout, new_state ); } SHOW_FLOW0( 3, "9" ); return true; err2: if( irq_guard ) bus->controller->write_device_control( bus->channel, ide_devctrl_bit3 ); err1: if( timeout > 0 ) { bus->state = ide_state_accessing; IDE_UNLOCK( bus ); } err: set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE ); return false; }