int32_t ide_pio_readwrite(uint8_t rw, uint8_t drive, uint64_t lba, uint8_t *buf, uint32_t numsectors) { /* Sanity */ if(rw > 1 || buf == 0) return 0; /* Vars */ uint64_t addr = lba; uint8_t lba_mode = 1; /* 1 - 28, 2 - 48 */ uint8_t cmd = 0; uint8_t channel = ide_devices[drive].channel; uint32_t slave = ide_devices[drive].drive; uint32_t bus = ide_channels[channel].base; uint32_t words = (numsectors * 512) / 2; /* Make sure IRQs are disabled */ _outb(bus + IDE_REGISTER_CTRL, 0x02); /* Wait for it to acknowledge */ ide_wait(channel, 0); /* Determine LBA mode */ if(ide_devices[drive].flags & 0x1) lba_mode = 2; /* Read or write? */ if(rw == IDE_READ) cmd = IDE_COMMAND_PIO_READ; else cmd = IDE_COMMAND_PIO_WRITE; /* Reset IRQ counter */ ide_channels[channel].irq_wait = 0; /* Now, send the command */ if(lba_mode == 2) { /* LBA48 */ cmd += 0x04; /* Send it */ ide_write(channel, IDE_REGISTER_HDDSEL, (0x40 | (slave << 4))); ide_wait(channel, 0); ide_write(channel, IDE_REGISTER_SECCOUNT0, 0x00); ide_write(channel, IDE_REGISTER_LBA0, (uint8_t)((addr >> 24) & 0xFF)); ide_write(channel, IDE_REGISTER_LBA1, (uint8_t)((addr >> 32) & 0xFF)); ide_write(channel, IDE_REGISTER_LBA2, (uint8_t)((addr >> 40) & 0xFF)); }
bool reset_device(ide_device_info *device, ide_qrequest *ignore) { ide_bus_info *bus = device->bus; status_t res; uint8 orig_command; dprintf("ide: reset_device() device %p\n", device); SHOW_FLOW0(3, ""); if (!device->is_atapi) goto err; if (device->reconnect_timer_installed) { cancel_timer(&device->reconnect_timer.te); device->reconnect_timer_installed = false; } // select device if (bus->controller->write_command_block_regs(bus->channel_cookie, &device->tf, ide_mask_device_head) != B_OK) goto err; // safe original command to let caller restart it orig_command = device->tf.write.command; // send device reset, independ of current device state // (that's the point of a reset) device->tf.write.command = IDE_CMD_DEVICE_RESET; res = bus->controller->write_command_block_regs(bus->channel_cookie, &device->tf, ide_mask_command); device->tf.write.command = orig_command; if (res != B_OK) goto err; // don't know how long to wait, but 31 seconds, like soft reset, // should be enough if (!ide_wait(device, 0, ide_status_bsy, true, 31000000)) goto err; // alright, resubmit all requests finish_all_requests(device, ignore, SCSI_SCSI_BUS_RESET, true); SHOW_FLOW0(3, "done"); dprintf("ide: reset_device() device %p success\n", device); return true; err: // do the hard way dprintf("ide: reset_device() device %p failed, calling reset_bus\n", device); return reset_bus(device, ignore); }
bool device_start_service(ide_device_info *device, int *tag) { ide_bus_info *bus = device->bus; device->tf.write.command = IDE_CMD_SERVICE; device->tf.queued.mode = ide_mode_lba; if (bus->active_device != device) { // don't apply any precautions in terms of IRQ // -> the bus is in accessing state, so IRQs are ignored anyway if (bus->controller->write_command_block_regs(bus->channel_cookie, &device->tf, ide_mask_device_head) != B_OK) // on error, pretend that this device asks for service // -> the disappeared controller will be recognized soon ;) return true; bus->active_device = device; // give one clock (400 ns) to take notice spin(1); } // here we go... if (bus->controller->write_command_block_regs(bus->channel_cookie, &device->tf, ide_mask_command) != B_OK) goto err; // we need to wait for the device as we want to read the tag if (!ide_wait(device, ide_status_drdy, ide_status_bsy, false, 1000000)) return false; // read tag if (bus->controller->read_command_block_regs(bus->channel_cookie, &device->tf, ide_mask_sector_count) != B_OK) goto err; if (device->tf.queued.release) { // bus release is the wrong answer to a service request set_sense(device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE); return false; } *tag = device->tf.queued.tag; return true; err: set_sense(device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE); return false; }
static int hd_read_udma(block_dev_t *bdev, char *buffer, size_t count, blkno_t blkno) { hd_t *hd; hdc_t *hdc; int sectsleft; int nsects; int result = 0; char *bufp; if (count == 0) { return 0; } bufp = (char *) buffer; hd = (hd_t *) bdev->privdata; hdc = hd->hdc; sectsleft = count / SECTOR_SIZE; while (sectsleft > 0) { /* Select drive */ ide_select_drive(hd); /* Wait for controller ready */ result = ide_wait(hdc, HDCS_DRDY, HDTIMEOUT_DRDY); if (result != 0) { result = -EIO; break; } /* Calculate maximum number of sectors we can transfer */ if (sectsleft > 256) { nsects = 256; } else { nsects = sectsleft; } if (nsects > MAX_DMA_XFER_SIZE / SECTOR_SIZE) { nsects = MAX_DMA_XFER_SIZE / SECTOR_SIZE; } /* Prepare transfer */ result = 0; hdc->dir = HD_XFER_DMA; hdc->active = hd; hd_setup_transfer(hd, blkno, nsects); /* Setup DMA */ setup_dma(hdc, bufp, nsects * SECTOR_SIZE, BM_CR_WRITE); /* Start read */ outb(HDCMD_READDMA, hdc->iobase + HDC_COMMAND); start_dma(hdc); /* Stop DMA channel and check DMA status */ result = stop_dma(hdc); if (result < 0) { break; } /* Check controller status */ if (hdc->status & HDCS_ERR) { result = -EIO; break; } /* Advance to next */ sectsleft -= nsects; bufp += nsects * SECTOR_SIZE; } /* Cleanup */ hdc->dir = HD_XFER_IDLE; hdc->active = NULL; return result == 0 ? count : result; }
bool reset_bus(ide_device_info *device, ide_qrequest *ignore) { ide_bus_info *bus = device->bus; ide_controller_interface *controller = bus->controller; ide_channel_cookie channel = bus->channel_cookie; dprintf("ide: reset_bus() device %p, bus %p\n", device, bus); if (device->reconnect_timer_installed) { cancel_timer(&device->reconnect_timer.te); device->reconnect_timer_installed = false; } if (device->other_device->reconnect_timer_installed) { cancel_timer(&device->other_device->reconnect_timer.te); device->other_device->reconnect_timer_installed = false; } // activate srst signal for 5 µs // also, deactivate IRQ // (as usual, we will get an IRQ on disabling, but as we leave them // disabled for 2 ms, this false report is ignored) if (controller->write_device_control(channel, ide_devctrl_nien | ide_devctrl_srst | ide_devctrl_bit3) != B_OK) goto err0; spin(5); if (controller->write_device_control(channel, ide_devctrl_nien | ide_devctrl_bit3) != B_OK) goto err0; // let devices wake up snooze(2000); // ouch, we have to wait up to 31 seconds! if (!ide_wait(device, 0, ide_status_bsy, true, 31000000)) { // as we don't know which of the devices is broken // we leave them both alive if (controller->write_device_control(channel, ide_devctrl_bit3) != B_OK) goto err0; set_sense(device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_LUN_TIMEOUT); goto err1; } if (controller->write_device_control(channel, ide_devctrl_bit3) != B_OK) goto err0; finish_all_requests(bus->devices[0], ignore, SCSI_SCSI_BUS_RESET, true); finish_all_requests(bus->devices[1], ignore, SCSI_SCSI_BUS_RESET, true); dprintf("ide: reset_bus() device %p, bus %p success\n", device, bus); return true; err0: set_sense(device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE); err1: finish_all_requests(bus->devices[0], ignore, SCSI_SCSI_BUS_RESET, true); finish_all_requests(bus->devices[1], ignore, SCSI_SCSI_BUS_RESET, true); //xpt->call_async( bus->xpt_cookie, -1, -1, AC_BUS_RESET, NULL, 0 ); dprintf("ide: reset_bus() device %p, bus %p failed\n", device, bus); return false; }
bool wait_for_drdy(ide_device_info *device) { return ide_wait(device, ide_status_drdy, ide_status_bsy, false, 5000000); }
bool wait_for_drqdown(ide_device_info *device) { return ide_wait(device, 0, ide_status_drq, true, 1000000); }
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 int hd_write_pio(block_dev_t *bdev, char *buffer, size_t count, blkno_t blkno) { hd_t *hd; hdc_t *hdc; int sectsleft; int nsects; int n; int result = 0; char *bufp; if (count == 0) { return 0; } bufp = (char *) buffer; hd = (hd_t *) bdev->privdata; hdc = hd->hdc; sectsleft = count / bdev->block_size; while (sectsleft > 0) { /* Select drive */ ide_select_drive(hd); /* Wait for controller ready */ result = ide_wait(hdc, HDCS_DRDY, HDTIMEOUT_DRDY); if (result != 0) { hdc->result = -EIO; break; } nsects = 1; /* Prepare transfer */ hdc->bufp = bufp; hdc->nsects = nsects; hdc->result = 0; hdc->dir = HD_XFER_WRITE; hdc->active = hd; hd_setup_transfer(hd, blkno, nsects); outb(hd->multsect > 1 ? HDCMD_MULTWRITE : HDCMD_WRITE, hdc->iobase + HDC_COMMAND); /* Wait for data ready */ if (!(inb(hdc->iobase + HDC_ALT_STATUS) & HDCS_DRQ)) { result = ide_wait(hdc, HDCS_DRQ, HDTIMEOUT_DRQ); if (result != 0) { hdc->result = -EIO; break; } } /* Write first sector(s) */ n = hd->multsect; if (n > nsects) { n = nsects; } while (n-- > 0) { pio_write_buffer(hd, hdc->bufp, bdev->block_size); hdc->bufp += bdev->block_size; } /* Wait until data written */ WAITQ_WAIT(&hdc->waitq, hdc->result); if (hdc->result < 0) { break; } /* Advance to next */ sectsleft -= nsects; bufp += nsects * bdev->block_size; blkno += nsects; /*WTF?*/ } /* Cleanup */ hdc->dir = HD_XFER_IDLE; hdc->active = NULL; /* * FIXME This assignment crashes writing, because * hdc->result equal 1 after writing. So, it set result to 1, afterward * (return result == 0 ? count : result) return 1. * --Alexander * result = hdc->result; */ return result == 0 ? count : result; }
static int hd_read_pio(block_dev_t *bdev, char *buffer, size_t count, blkno_t blkno) { hd_t *hd; hdc_t *hdc; int sectsleft; int nsects; int result = 0; char *bufp; if (count == 0) { return 0; } bufp = (char *) buffer; hd = (hd_t *) bdev->privdata; hdc = hd->hdc; sectsleft = count / bdev->block_size; if (count % bdev->block_size) { sectsleft++; } while (sectsleft > 0) { /* Select drive */ ide_select_drive(hd); /* Wait for controller ready */ result = ide_wait(hdc, HDCS_DRDY, HDTIMEOUT_DRDY); if (result != 0) { hdc->result = -EIO; break; } nsects = 1; /* Prepare transfer */ hdc->bufp = bufp; hdc->nsects = nsects; hdc->result = 0; hdc->dir = HD_XFER_READ; hdc->active = hd; hd_setup_transfer(hd, blkno, nsects); outb(hd->multsect > 1 ? HDCMD_MULTREAD : HDCMD_READ, hdc->iobase + HDC_COMMAND); /* Wait until data read */ WAITQ_WAIT(&hdc->waitq, hdc->result); if (hdc->result < 0) { break; } /* Advance to next */ sectsleft -= nsects; bufp += nsects * bdev->block_size; blkno += nsects; /*WTF?*/ } /* Cleanup */ hdc->dir = HD_XFER_IDLE; hdc->active = NULL; if (0 < hdc->result) { result = hdc->result = 0; } return result == 0 ? count : result; }
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; }
// we need a device to store sense information // (we could just take device 0, but this were not fair if the reset // was done because of a device 1 failure) bool reset_bus( ide_device_info *device ) { ide_bus_info *bus = device->bus; ide_controller_interface *controller = bus->controller; ide_channel_cookie channel = bus->channel; SHOW_FLOW0( 3, "" ); // activate srst signal for 5 µs reset_timeouts( device ); reset_timeouts( device->other_device ); //set_irq_state( device, ide_irq_state_ignore ); SHOW_FLOW0( 3, "1" ); if( controller->write_device_control( channel, ide_devctrl_nien | ide_devctrl_srst | ide_devctrl_bit3 ) != NO_ERROR ) goto err0; SHOW_FLOW0( 3, "2" ); cpu_spin( 5 ); if( controller->write_device_control( channel, ide_devctrl_nien | ide_devctrl_bit3 ) != NO_ERROR ) goto err0; SHOW_FLOW0( 3, "3" ); // let devices wake up thread_snooze( 2000 ); SHOW_FLOW0( 3, "4" ); // ouch, we have to wait up to 31 seconds! if( !ide_wait( device, 0, ide_status_bsy, false, 31000000 )) { // we don't know which of the devices is broken // so we don't disable them if( controller->write_device_control( channel, ide_devctrl_bit3 ) != NO_ERROR ) goto err0; set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_LUN_TIMEOUT ); goto err1; } SHOW_FLOW0( 3, "5" ); if( controller->write_device_control( channel, ide_devctrl_bit3 ) != NO_ERROR ) goto err0; SHOW_FLOW0( 3, "6" ); finish_all_requests( bus->devices[0], CAM_SCSI_BUS_RESET ); finish_all_requests( bus->devices[1], CAM_SCSI_BUS_RESET ); SHOW_FLOW0( 3, "7" ); xpt->call_async( bus->xpt_cookie, -1, -1, AC_BUS_RESET, NULL, 0 ); SHOW_FLOW0( 3, "8" ); return true; err0: set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE ); err1: finish_all_requests( bus->devices[0], CAM_SCSI_BUS_RESET ); finish_all_requests( bus->devices[1], CAM_SCSI_BUS_RESET ); xpt->call_async( bus->xpt_cookie, -1, -1, AC_BUS_RESET, NULL, 0 ); return false; }
bool device_start_service( ide_device_info *device, int *tag ) { ide_bus_info *bus = device->bus; bigtime_t irq_disabled_at = 0; // makes compiler happy bool irq_guard = bus->num_running_reqs > 1; device->tf.write.command = IDE_CMD_SERVICE; device->tf.queued.mode = ide_mode_lba; reset_timeouts( device ); //set_irq_state( device, ide_irq_state_ignore ); if( irq_guard ) { irq_disabled_at = system_time(); if( bus->controller->write_device_control( bus->channel, ide_devctrl_nien | ide_devctrl_bit3 ) != NO_ERROR ) goto err; } 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 set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE ); return false; } if( irq_guard ) { // see send_ata while( system_time() - irq_disabled_at < MAX_IRQ_DELAY ) cpu_spin( 1 ); if( bus->controller->write_device_control( bus->channel, ide_devctrl_bit3 ) != NO_ERROR ) goto err; } // here we go... if( bus->controller->write_command_block_regs( bus->channel, &device->tf, ide_mask_command ) != NO_ERROR ) goto err; if( !ide_wait( device, ide_status_drdy, ide_status_bsy, false, 1000000 )) { set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_LUN_TIMEOUT ); return false; } if( bus->controller->read_command_block_regs( bus->channel, &device->tf, ide_mask_sector_count ) != NO_ERROR ) goto err; if( device->tf.queued.release ) { // bus release is the wrong answer to a service request set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE ); return false; } *tag = device->tf.queued.tag; return true; err: set_sense( device, SCSIS_KEY_HARDWARE_ERROR, SCSIS_ASC_INTERNAL_FAILURE ); return false; }
// 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; }