#define IDE_SECTOR_SIZE 512
#define CDROM_SECTOR_SIZE 2048
-#define IDE_TIMEOUT 32000u //32 seconds max for IDE ops
+#define IDE_TIMEOUT 32000 //32 seconds max for IDE ops
struct ata_s ATA VAR16_32;
}
// Wait for ide state - pauses for one ata cycle first.
-static __always_inline int
+static inline int
pause_await_not_bsy(u16 iobase1, u16 iobase2)
{
// Wait one PIO transfer cycle.
}
// Wait for ide state - pause for 400ns first.
-static __always_inline int
+static inline int
ndelay_await_not_bsy(u16 iobase1)
{
ndelay(400);
u64 end = calc_future_tsc(IDE_TIMEOUT);
for (;;) {
outb(ATA_CB_DH_DEV1, iobase1 + ATA_CB_DH);
- status = await_not_bsy(iobase1);
+ status = ndelay_await_not_bsy(iobase1);
if (status < 0)
goto done;
if (inb(iobase1 + ATA_CB_DH) == ATA_CB_DH_DEV1)
outb(newdh, iobase1 + ATA_CB_DH);
if ((olddh ^ newdh) & (1<<4)) {
// Was a device change - wait for device to become not busy.
- status = await_not_bsy(iobase1);
+ status = ndelay_await_not_bsy(iobase1);
if (status < 0)
return status;
}
* ATA hard drive functions
****************************************************************/
-static noinline int
+static int
send_cmd_disk(const struct disk_op_s *op)
{
u64 lba = op->lba;
}
// Read/write count blocks from a harddrive.
-__always_inline int
+int
ata_cmd_data(struct disk_op_s *op)
{
int ret = send_cmd_disk(op);
****************************************************************/
// Low-level atapi command transmit function.
-static __always_inline int
+static int
send_atapi_cmd(int driveid, u8 *cmdbuf, u8 cmdlen, u16 blocksize)
{
u8 channel = driveid / 2;
return status;
if (status & ATA_CB_STAT_ERR) {
- dprintf(6, "send_atapi_cmd : read error (status=%02x err=%02x)\n"
- , status, inb(iobase1 + ATA_CB_ERR));
+ u8 err = inb(iobase1 + ATA_CB_ERR);
+ // skip "Not Ready"
+ if (err != 0x20)
+ dprintf(6, "send_atapi_cmd : read error (status=%02x err=%02x)\n"
+ , status, err);
return -2;
}
if (!(status & ATA_CB_STAT_DRQ)) {
}
// Read sectors from the cdrom.
-__always_inline int
+int
cdrom_read(struct disk_op_s *op)
{
int ret = send_cmd_cdrom(op);
// Pretend the cdrom has 512 byte sectors (instead of 2048) and read
// sectors.
-__always_inline int
+int
cdrom_read_512(struct disk_op_s *op)
{
u32 vlba = op->lba;
}
static int
-init_drive_atapi(int driveid)
+init_drive_atapi(int driveid, u16 *buffer)
{
// Send an IDENTIFY_DEVICE_PACKET command to device
- u16 buffer[256];
- memset(buffer, 0, sizeof(buffer));
+ memset(buffer, 0, IDE_SECTOR_SIZE);
struct disk_op_s dop;
dop.driveid = driveid;
dop.command = ATA_CMD_IDENTIFY_DEVICE_PACKET;
}
static int
-init_drive_ata(int driveid)
+init_drive_ata(int driveid, u16 *buffer)
{
// Send an IDENTIFY_DEVICE command to device
- u16 buffer[256];
- memset(buffer, 0, sizeof(buffer));
+ memset(buffer, 0, IDE_SECTOR_SIZE);
struct disk_op_s dop;
dop.driveid = driveid;
dop.command = ATA_CMD_IDENTIFY_DEVICE;
return 0;
}
+static int
+powerup_await_non_bsy(u16 base, u64 end)
+{
+ u8 orstatus = 0;
+ u8 status;
+ for (;;) {
+ status = inb(base+ATA_CB_STAT);
+ if (!(status & ATA_CB_STAT_BSY))
+ break;
+ orstatus |= status;
+ if (orstatus == 0xff) {
+ dprintf(1, "powerup IDE floating\n");
+ return orstatus;
+ }
+ if (rdtscll() > end) {
+ dprintf(1, "powerup IDE time out\n");
+ return -1;
+ }
+ }
+ dprintf(6, "powerup iobase=%x st=%x\n", base, status);
+ return status;
+}
+
static void
ata_detect()
{
// Device detection
+ u64 end = calc_future_tsc(IDE_TIMEOUT);
int driveid, last_reset_driveid=-1;
for(driveid=0; driveid<CONFIG_MAX_ATA_DEVICES; driveid++) {
u8 channel = driveid / 2;
if (!iobase1)
break;
- // Look for device
- outb(slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0, iobase1+ATA_CB_DH);
- outb(0x55, iobase1+ATA_CB_SC);
- outb(0xaa, iobase1+ATA_CB_SN);
- outb(0xaa, iobase1+ATA_CB_SC);
- outb(0x55, iobase1+ATA_CB_SN);
- outb(0x55, iobase1+ATA_CB_SC);
- outb(0xaa, iobase1+ATA_CB_SN);
+ // Wait for not-bsy.
+ int status = powerup_await_non_bsy(iobase1, end);
+ if (status < 0)
+ continue;
+ u8 newdh = slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0;
+ outb(newdh, iobase1+ATA_CB_DH);
+ ndelay(400);
+ status = powerup_await_non_bsy(iobase1, end);
+ if (status < 0)
+ continue;
// Check if ioport registers look valid.
+ outb(newdh, iobase1+ATA_CB_DH);
+ u8 dh = inb(iobase1+ATA_CB_DH);
+ outb(0x55, iobase1+ATA_CB_SC);
+ outb(0xaa, iobase1+ATA_CB_SN);
u8 sc = inb(iobase1+ATA_CB_SC);
u8 sn = inb(iobase1+ATA_CB_SN);
- dprintf(6, "ata_detect drive=%d sc=%x sn=%x\n", driveid, sc, sn);
- if (sc != 0x55 || sn != 0xaa)
+ dprintf(6, "ata_detect drive=%d sc=%x sn=%x dh=%x\n"
+ , driveid, sc, sn, dh);
+ if (sc != 0x55 || sn != 0xaa || dh != newdh)
continue;
// reset the channel
}
// check for ATAPI
- int ret = init_drive_atapi(driveid);
- if (!ret)
+ u16 buffer[256];
+ int ret = init_drive_atapi(driveid, buffer);
+ if (!ret) {
// Found an ATAPI drive.
- continue;
-
- u8 st = inb(iobase1+ATA_CB_STAT);
- if (!st)
- // Status not set - can't be a valid drive.
- continue;
-
- // Wait for RDY.
- ret = await_rdy(iobase1);
- if (ret < 0)
- continue;
+ } else {
+ u8 st = inb(iobase1+ATA_CB_STAT);
+ if (!st)
+ // Status not set - can't be a valid drive.
+ continue;
+
+ // Wait for RDY.
+ ret = await_rdy(iobase1);
+ if (ret < 0)
+ continue;
+
+ // check for ATA.
+ ret = init_drive_ata(driveid, buffer);
+ if (ret)
+ // No ATA drive found
+ continue;
+ }
- // check for ATA.
- init_drive_ata(driveid);
+ u16 resetresult = buffer[93];
+ dprintf(6, "ata_detect resetresult=%04x\n", resetresult);
+ if (!slave && (resetresult & 0xdf61) == 0x4041)
+ // resetresult looks valid and device 0 is responding to
+ // device 1 requests - device 1 must not be present - skip
+ // detection.
+ driveid++;
}
printf("\n");