modified device detection

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23281 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Marcus Overhagen
2008-01-07 19:29:15 +00:00
parent 8d44324fda
commit b44b755c91
9 changed files with 204 additions and 179 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
SubDir HAIKU_TOP src add-ons kernel bus_managers ide ;
SubDir HAIKU_TOP src add-ons kernel bus_managers ata ;
UsePrivateHeaders drivers kernel ;
UsePrivateHeaders [ FDirName kernel arch $(TARGET_ARCH) ] ;
+49
View File
@@ -15,6 +15,7 @@
#include "ide_sim.h"
#include "ide_cmds.h"
#define TRACE dprintf
/** verify that device is ready for further PIO transmission */
@@ -785,3 +786,51 @@ void
enable_CQ(ide_device_info *device, bool enable)
{
}
status_t
ata_read_infoblock(ide_device_info *device, bool isAtapi)
{
ide_bus_info *bus = device->bus;
int status;
TRACE("ata_read_infoblock: device %p, isAtapi %d\n", device, isAtapi);
// disable interrupts
bus->controller->write_device_control(bus->channel_cookie, ide_devctrl_bit3 | ide_devctrl_nien);
device->tf_param_mask = 0;
device->tf.write.command = isAtapi ? 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("ata_read_infoblock: read_command_block_regs failed\n");
return B_ERROR;
}
device->tf.lba.device = device->is_device1;
if (!send_command(device, NULL, isAtapi ? false : true, 20, ide_state_sync_waiting)) {
TRACE("ata_read_infoblock: send_command failed\n");
return B_ERROR;
}
if (ata_wait(bus, ide_status_drq, ide_status_bsy, true, 4000000) != B_OK) {
TRACE("ata_read_infoblock: wait failed\n");
return B_ERROR;
}
// 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("ata_read_infoblock: success\n");
return B_OK;
}
+1 -1
View File
@@ -201,7 +201,7 @@ packet_dpc(ide_qrequest *qrequest)
// TODO: the device will abort next command with a reset condition
// perhaps we should hide that by reading sense?
SHOW_FLOW0(3, "Reset");
reset_device(device, qrequest);
// reset_device(device, qrequest);
finish_checksense(qrequest);
return;
@@ -53,142 +53,83 @@ wait_for_drdy(ide_device_info *device)
}
/** reset entire IDE bus
* all active request apart from <ignore> are resubmitted
*/
bool
reset_bus(ide_device_info *device, ide_qrequest *ignore)
status_t
reset_bus(ide_bus_info *bus, uint32 *sigDev0, uint32 *sigDev1)
{
ide_bus_info *bus = device->bus;
ide_controller_interface *controller = bus->controller;
ide_channel_cookie channel = bus->channel_cookie;
ide_task_file tf;
status_t status;
dprintf("ide: reset_bus() device %p, bus %p\n", device, bus);
dprintf("ATA: reset_bus %p\n", bus);
FAST_LOG0(bus->log, ev_ide_reset_bus);
// disable interrupts and assert SRST for at least 5 usec
if (controller->write_device_control(channel, ide_devctrl_bit3 | ide_devctrl_nien | ide_devctrl_srst) != B_OK)
goto error;
spin(20);
if (device->reconnect_timer_installed) {
cancel_timer(&device->reconnect_timer.te);
device->reconnect_timer_installed = false;
// clear SRST for at least 2 ms
if (controller->write_device_control(channel, ide_devctrl_bit3 | ide_devctrl_nien) != B_OK)
goto error;
snooze(5000);
// wait up to 30 seconds for busy to clear, abort when error is set
status = ata_wait(bus, 0, ide_status_bsy, true, 33000000);
if (status != B_OK)
goto error;
tf.chs.head = 0;
tf.chs.mode = ide_mode_lba;
// select device 0
tf.chs.device = 0;
if (controller->write_command_block_regs(channel, &tf, ide_mask_device_head) != B_OK)
goto error;
status = ata_wait(bus, 0, ide_status_bsy | ide_status_drq, true, 50000);
if (status != B_OK) {
dprintf("ATA: reset_bus: device 0 not present\n");
*sigDev0 = 0;
} else {
if (controller->read_command_block_regs(channel, &tf, ide_mask_sector_count |
ide_mask_LBA_low | ide_mask_LBA_mid | ide_mask_LBA_high) != B_OK)
goto error;
*sigDev0 = tf.lba.sector_count;
*sigDev0 |= ((uint32)tf.lba.lba_0_7) << 8;
*sigDev0 |= ((uint32)tf.lba.lba_8_15) << 16;
*sigDev0 |= ((uint32)tf.lba.lba_16_23) << 24;
}
if (device->other_device->reconnect_timer_installed) {
cancel_timer(&device->other_device->reconnect_timer.te);
device->other_device->reconnect_timer_installed = false;
// select device 1
tf.chs.device = 1;
if (controller->write_command_block_regs(channel, &tf, ide_mask_device_head) != B_OK)
goto error;
status = ata_wait(bus, 0, ide_status_bsy | ide_status_drq, true, 50000);
if (status != B_OK) {
dprintf("ATA: reset_bus: device 1 not present\n");
*sigDev1 = 0;
} else {
if (controller->read_command_block_regs(channel, &tf, ide_mask_sector_count |
ide_mask_LBA_low | ide_mask_LBA_mid | ide_mask_LBA_high) != B_OK)
goto error;
*sigDev1 = tf.lba.sector_count;
*sigDev1 |= ((uint32)tf.lba.lba_0_7) << 8;
*sigDev1 |= ((uint32)tf.lba.lba_8_15) << 16;
*sigDev1 |= ((uint32)tf.lba.lba_16_23) << 24;
}
// 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;
dprintf("ATA: reset_bus success, device 0 signature: 0x%08lx, device 1 signature: 0x%08lx\n", *sigDev0, *sigDev1);
spin(5);
return B_OK;
if (controller->write_device_control(channel, ide_devctrl_nien | ide_devctrl_bit3) != B_OK)
goto err0;
error:
// 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;
dprintf("ATA: reset_bus failed\n");
return B_ERROR;
}
/** execute packet device reset.
* resets entire bus on fail or if device is not atapi;
* all requests but <ignore> are resubmitted
*/
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);
FAST_LOG1(bus->log, ev_ide_reset_device, device->is_device1);
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);
}
/** new_state must be either accessing, async_waiting or sync_waiting
* param_mask must not include command register
*/
@@ -250,12 +191,13 @@ retry:
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
@@ -331,6 +273,39 @@ err:
}
status_t
ata_wait(ide_bus_info *bus, uint8 mask, uint8 not_mask,
bool check_err, bigtime_t timeout)
{
bigtime_t startTime = system_time();
bigtime_t elapsedTime;
uint8 status;
spin(1); // device needs 400ns to set status
for (;;) {
status = bus->controller->get_altstatus(bus->channel_cookie);
if (check_err && (status & ide_status_err) != 0)
return B_ERROR;
if ((status & mask) == mask && (status & not_mask) == 0)
return B_OK;
elapsedTime = system_time() - startTime;
if (elapsedTime > timeout)
return B_TIMED_OUT;
if (elapsedTime < 5000)
spin(1);
else
snooze(5000);
}
}
/** busy-wait for device
* mask - bits of status register that must be set
* not_mask - bits of status register that must not be set
+19 -6
View File
@@ -49,7 +49,7 @@ cleanup_device_links(ide_device_info *device)
/** destroy device info */
static void
void
destroy_device(ide_device_info *device)
{
TRACE("destroy_device: device %p\n", device);
@@ -101,7 +101,7 @@ setup_device_links(ide_bus_info *bus, ide_device_info *device)
/** create device info */
static ide_device_info *
ide_device_info *
create_device(ide_bus_info *bus, bool is_device1)
{
ide_device_info *device;
@@ -185,7 +185,7 @@ prep_infoblock(ide_device_info *device)
/** read info block of ATA or ATAPI device */
/*
static bool
scan_device_int(ide_device_info *device, bool atapi)
{
@@ -284,10 +284,24 @@ scan_device_int(ide_device_info *device, bool atapi)
prep_infoblock(device);
return true;
}
*/
/** scan one device */
status_t
scan_device(ide_device_info *device, bool isAtapi)
{
dprintf("ATA: scan_device\n");
if (ata_read_infoblock(device, isAtapi) != B_OK) {
dprintf("ATA: couldn't read infoblock for device %p\n", device);
return B_ERROR;
}
prep_infoblock(device);
return B_OK;
}
/*
void
scan_device_worker(ide_bus_info *bus, void *arg)
{
@@ -321,12 +335,11 @@ scan_device_worker(ide_bus_info *bus, void *arg)
goto err;
bus->state = ide_state_idle;
release_sem(bus->scan_device_sem);
return;
err:
destroy_device(device);
bus->state = ide_state_idle;
release_sem(bus->scan_device_sem);
}
*/
@@ -221,9 +221,6 @@ struct ide_bus_info {
ide_device_info *devices[2];
ide_device_info *first_device;
ide_synced_pc scan_bus_syncinfo; // used to start bus scan
sem_id scan_device_sem; // released when device has been scanned
ide_synced_pc disconnect_syncinfo; // used to handle lost controller
uchar path_id;
@@ -331,6 +328,8 @@ void ata_dpc_PIO(ide_qrequest *qrequest);
void ata_exec_io(ide_device_info *device, ide_qrequest *qrequest);
status_t ata_read_infoblock(ide_device_info *device, bool isAtapi);
// atapi.c
@@ -343,6 +342,9 @@ void atapi_exec_io(ide_device_info *device, ide_qrequest *qrequest);
// basic_prot.c
status_t ata_wait(ide_bus_info *bus, uint8 mask, uint8 not_mask, bool check_err, bigtime_t timeout);
bool ide_wait(ide_device_info *device, int mask, int not_mask, bool check_err,
bigtime_t timeout);
bool wait_for_drq(ide_device_info *device);
@@ -353,11 +355,13 @@ bool wait_for_drdy(ide_device_info *device);
bool send_command(ide_device_info *device, ide_qrequest *qrequest,
bool need_drdy, uint32 timeout, ide_bus_state new_state);
bool device_start_service( ide_device_info *device, int *tag);
bool reset_device(ide_device_info *device, ide_qrequest *ignore);
bool reset_bus(ide_device_info *device, ide_qrequest *ignore);
//bool reset_device(ide_device_info *device, ide_qrequest *ignore);
//bool reset_bus(ide_device_info *device, ide_qrequest *ignore);
bool check_service_req(ide_device_info *device);
status_t reset_bus(ide_bus_info *bus, uint32 *sigDev0, uint32 *sigDev1);
// channel_mgr.c
@@ -366,7 +370,10 @@ extern ide_for_controller_interface ide_for_controller_module;
// device_mgr.c
void scan_device_worker(ide_bus_info *bus, void *arg);
status_t scan_device(ide_device_info *device, bool isAtapi);
void destroy_device(ide_device_info *device);
ide_device_info *create_device(ide_bus_info *bus, bool is_device1);
// dma.c
+22 -42
View File
@@ -79,20 +79,7 @@ static void set_check_condition(ide_qrequest *qrequest);
static inline bool
is_queuable(ide_device_info *device, scsi_ccb *request)
{
int opcode = request->cdb[0];
// XXX disable queuing
if (!device->CQ_enabled)
return false;
// make sure the caller allows queuing
if ((request->flags & SCSI_ORDERED_QTAG) != 0)
return false;
// for atapi, all commands could be queued, but all
// atapi devices I know don't support queuing anyway
return opcode == SCSI_OP_READ_6 || opcode == SCSI_OP_WRITE_6
|| opcode == SCSI_OP_READ_10 || opcode == SCSI_OP_WRITE_10;
return false;
}
@@ -241,34 +228,38 @@ sim_path_inquiry(ide_bus_info *bus, scsi_path_inquiry *info)
}
static void
scan_device(ide_bus_info *bus, int device)
{
SHOW_FLOW0(4, "");
// currently, the SCSI bus manager doesn't block the
// bus when a bus or device scan is issued, so we
// have to use a SPC for that to be sure no one else
// is accessing the device or bus concurrently
schedule_synced_pc(bus, &bus->scan_bus_syncinfo, (void *)device);
acquire_sem(bus->scan_device_sem);
}
static uchar
sim_scan_bus(ide_bus_info *bus)
{
uint32 deviceSignature[2];
ide_device_info *device;
status_t status;
bool isAtapi;
int i;
SHOW_FLOW0(4, "");
dprintf("ATA: sim_scan_bus: bus %p\n", bus);
if (bus->disconnected)
return SCSI_NO_HBA;
// IDE_LOCK(bus);
status = reset_bus(bus, &deviceSignature[0], &deviceSignature[1]);
for (i = 0; i < bus->max_devices; ++i) {
scan_device(bus, i);
if (bus->devices[i])
destroy_device(bus->devices[i]);
if (status == B_OK && deviceSignature[i] != 0) {
isAtapi = deviceSignature[i] == 0xeb140101;
device = create_device(bus, i /* isDevice1 */);
if (scan_device(device, isAtapi) != B_OK)
destroy_device(device);
}
}
// IDE_UNLOCK(bus);
dprintf("ATA: sim_scan_bus: bus %p finished\n", bus);
return SCSI_REQ_CMP;
}
@@ -581,7 +572,6 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie)
}
#endif
init_synced_pc(&bus->scan_bus_syncinfo, scan_device_worker);
init_synced_pc(&bus->disconnect_syncinfo, disconnect_worker);
bus->scsi_cookie = user_cookie;
@@ -601,12 +591,6 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie)
bus->devices[0] = bus->devices[1] = NULL;
bus->scan_device_sem = create_sem(0, "ide_scan_finished");
if (bus->scan_device_sem < 0) {
status = bus->scan_device_sem;
goto err3;
}
status = INIT_BEN(&bus->status_report_ben, "ide_status_report");
if (status < B_OK)
goto err4;
@@ -675,13 +659,11 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie)
err5:
DELETE_BEN(&bus->status_report_ben);
err4:
delete_sem(bus->scan_device_sem);
err3:
delete_sem(bus->sync_wait_sem);
err2:
scsi->free_dpc(bus->irq_dpc);
err1:
uninit_synced_pc(&bus->scan_bus_syncinfo);
uninit_synced_pc(&bus->disconnect_syncinfo);
#ifdef USE_FAST_LOG
fast_log->stop_log(bus->log);
@@ -702,10 +684,8 @@ ide_sim_uninit_bus(ide_bus_info *bus)
pnp->put_device_node(parent);
DELETE_BEN(&bus->status_report_ben);
delete_sem(bus->scan_device_sem);
delete_sem(bus->sync_wait_sem);
scsi->free_dpc(bus->irq_dpc);
uninit_synced_pc(&bus->scan_bus_syncinfo);
uninit_synced_pc(&bus->disconnect_syncinfo);
// fast_log->stop_log(bus->log);
@@ -370,5 +370,6 @@ send_abort_queue(ide_device_info *device)
err:
// ouch! device didn't react - we have to reset it
return reset_device(device, NULL);
//return reset_device(device, NULL);
return false;
}
+1 -1
View File
@@ -263,7 +263,7 @@ ide_timeout_dpc(void *arg)
FAST_LOG1(bus->log, ev_ide_timeout_dpc, (uint32)qrequest);
// this also resets overlapped commands
reset_device(device, qrequest);
// reset_device(device, qrequest);
device->subsys_status = SCSI_CMD_TIMEOUT;