Esempio n. 1
0
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));
    }
Esempio n. 2
0
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);
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
bool
wait_for_drdy(ide_device_info *device)
{
	return ide_wait(device, ide_status_drdy, ide_status_bsy, false, 5000000);
}
Esempio n. 7
0
bool
wait_for_drqdown(ide_device_info *device)
{
	return ide_wait(device, 0, ide_status_drq, true, 1000000);
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
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;
}
Esempio n. 11
0
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;	
}
Esempio n. 12
0
// 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;
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
// 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;
}