Newer
Older
}
#endif /* __PPC__ */
/* -------------------------------------------------------------------------
*/
static void ide_ident (block_dev_desc_t *dev_desc)
{
ulong iobuf[ATA_SECTORWORDS];
unsigned char c;
hd_driveid_t *iop = (hd_driveid_t *)iobuf;
#ifdef CONFIG_AMIGAONEG3SE
int max_bus_scan;
char *s;
#endif
#ifdef CONFIG_ATAPI
int retries = 0;
int do_retry = 0;
#endif
#ifdef CONFIG_TUNE_PIO
int pio_mode;
#endif
#if 0
int mode, cycle_time;
#endif
int device;
device=dev_desc->dev;
printf (" Device %d: ", device);
#ifdef CONFIG_AMIGAONEG3SE
s = getenv("ide_maxbus");
if (s) {
max_bus_scan = simple_strtol(s, NULL, 10);
} else {
max_bus_scan = CONFIG_SYS_IDE_MAXBUS;
}
if (device >= max_bus_scan*2) {
dev_desc->type=DEV_TYPE_UNKNOWN;
return;
}
#endif
ide_led (DEVICE_LED(device), 1); /* LED on */
/* Select device
*/
ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
dev_desc->if_type=IF_TYPE_IDE;
#ifdef CONFIG_ATAPI
do_retry = 0;
retries = 0;
/* Warning: This will be tricky to read */
if ((ide_inb(device,ATA_SECT_CNT) == 0x01) &&
(ide_inb(device,ATA_SECT_NUM) == 0x01) &&
(ide_inb(device,ATA_CYL_LOW) == 0x14) &&
(ide_inb(device,ATA_CYL_HIGH) == 0xEB)) {
/* ATAPI Signature found */
dev_desc->if_type=IF_TYPE_ATAPI;
/* Start Ident Command
*/
ide_outb (device, ATA_COMMAND, ATAPI_CMD_IDENT);
/*
* Wait for completion - ATAPI devices need more time
* to become ready
*/
c = ide_wait (device, ATAPI_TIME_OUT);
ide_outb (device, ATA_COMMAND, ATA_CMD_IDENT);
/* Wait for completion
*/
c = ide_wait (device, IDE_TIME_OUT);
}
ide_led (DEVICE_LED(device), 0); /* LED off */
if (((c & ATA_STAT_DRQ) == 0) ||
((c & (ATA_STAT_FAULT|ATA_STAT_ERR)) != 0) ) {
#ifdef CONFIG_ATAPI
s = getenv("ide_doreset");
if (s && strcmp(s, "on") == 0)
#endif
{
/* Need to soft reset the device in case it's an ATAPI... */
debug ("Retrying...\n");
ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
udelay(100000);
ide_outb (device, ATA_COMMAND, 0x08);
udelay (500000); /* 500 ms */
}
/* Select device
*/
ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
retries++;
#else
return;
#endif
#ifdef CONFIG_ATAPI
else
break;
} /* see above - ugly to read */
if (retries == 2) /* Not found */
return;
#endif
input_swap_data (device, iobuf, ATA_SECTORWORDS);
ident_cpy ((unsigned char*)dev_desc->revision, iop->fw_rev, sizeof(dev_desc->revision));
ident_cpy ((unsigned char*)dev_desc->vendor, iop->model, sizeof(dev_desc->vendor));
ident_cpy ((unsigned char*)dev_desc->product, iop->serial_no, sizeof(dev_desc->product));
Richard Retanubun
committed
* firmware revision, model, and serial number have Big Endian Byte
* order in Word. Convert all three to little endian.
*
* See CF+ and CompactFlash Specification Revision 2.0:
Richard Retanubun
committed
* 6.2.1.6: Identify Drive, Table 39 for more details
*/
strswab (dev_desc->revision);
strswab (dev_desc->vendor);
Richard Retanubun
committed
strswab (dev_desc->product);
if ((iop->config & 0x0080)==0x0080)
dev_desc->removable = 1;
else
dev_desc->removable = 0;
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
#ifdef CONFIG_TUNE_PIO
/* Mode 0 - 2 only, are directly determined by word 51. */
pio_mode = iop->tPIO;
if (pio_mode > 2) {
printf("WARNING: Invalid PIO (word 51 = %d).\n", pio_mode);
pio_mode = 0; /* Force it to dead slow, and hope for the best... */
}
/* Any CompactFlash Storage Card that supports PIO mode 3 or above
* shall set bit 1 of word 53 to one and support the fields contained
* in words 64 through 70.
*/
if (iop->field_valid & 0x02) {
/* Mode 3 and above are possible. Check in order from slow
* to fast, so we wind up with the highest mode allowed.
*/
if (iop->eide_pio_modes & 0x01)
pio_mode = 3;
if (iop->eide_pio_modes & 0x02)
pio_mode = 4;
if (ata_id_is_cfa((u16 *)iop)) {
if ((iop->cf_advanced_caps & 0x07) == 0x01)
pio_mode = 5;
if ((iop->cf_advanced_caps & 0x07) == 0x02)
pio_mode = 6;
}
}
/* System-specific, depends on bus speeds, etc. */
ide_set_piomode(pio_mode);
#endif /* CONFIG_TUNE_PIO */
#if 0
/*
* Drive PIO mode autoselection
*/
mode = iop->tPIO;
printf ("tPIO = 0x%02x = %d\n",mode, mode);
if (mode > 2) { /* 2 is maximum allowed tPIO value */
mode = 2;
debug ("Override tPIO -> 2\n");
}
if (iop->field_valid & 2) { /* drive implements ATA2? */
debug ("Drive implements ATA2\n");
if (iop->capability & 8) { /* drive supports use_iordy? */
cycle_time = iop->eide_pio_iordy;
} else {
cycle_time = iop->eide_pio;
}
debug ("cycle time = %d\n", cycle_time);
mode = 4;
if (cycle_time > 120) mode = 3; /* 120 ns for PIO mode 4 */
if (cycle_time > 180) mode = 2; /* 180 ns for PIO mode 3 */
if (cycle_time > 240) mode = 1; /* 240 ns for PIO mode 4 */
if (cycle_time > 383) mode = 0; /* 383 ns for PIO mode 4 */
}
printf ("PIO mode to use: PIO %d\n", mode);
#endif /* 0 */
#ifdef CONFIG_ATAPI
if (dev_desc->if_type==IF_TYPE_ATAPI) {
atapi_inquiry(dev_desc);
return;
}
#endif /* CONFIG_ATAPI */
/* swap shorts */
dev_desc->lba = (iop->lba_capacity << 16) | (iop->lba_capacity >> 16);
#else /* ! __BIG_ENDIAN */
/*
* do not swap shorts on little endian
*
* See CF+ and CompactFlash Specification Revision 2.0:
* 6.2.1.6: Identfy Drive, Table 39, Word Address 57-58 for details.
*/
dev_desc->lba = iop->lba_capacity;
#endif /* __BIG_ENDIAN */
if (iop->command_set_2 & 0x0400) { /* LBA 48 support */
dev_desc->lba48 = 1;
dev_desc->lba = (unsigned long long)iop->lba48_capacity[0] |
((unsigned long long)iop->lba48_capacity[1] << 16) |
((unsigned long long)iop->lba48_capacity[2] << 32) |
((unsigned long long)iop->lba48_capacity[3] << 48);
} else {
dev_desc->lba48 = 0;
}
#endif /* CONFIG_LBA48 */
/* assuming HD */
dev_desc->type=DEV_TYPE_HARDDISK;
dev_desc->blksz=ATA_BLOCKSIZE;
dev_desc->lun=0; /* just to fill something in... */
#if 0 /* only used to test the powersaving mode,
* if enabled, the drive goes after 5 sec
* in standby mode */
ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
ide_outb (device, ATA_SECT_CNT, 1);
ide_outb (device, ATA_LBA_LOW, 0);
ide_outb (device, ATA_LBA_MID, 0);
ide_outb (device, ATA_LBA_HIGH, 0);
ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
ide_outb (device, ATA_COMMAND, 0xe3);
udelay (50);
c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */
#endif
}
/* ------------------------------------------------------------------------- */
Grant Likely
committed
ulong ide_read (int device, lbaint_t blknr, ulong blkcnt, void *buffer)
{
ulong n = 0;
unsigned char c;
unsigned char pwrsave=0; /* power save */
if (blknr & 0x0000fffff0000000ULL) {
/* more than 28 bits used, use 48bit mode */
lba48 = 1;
}
#endif
debug ("ide_read dev %d start %LX, blocks %lX buffer at %lX\n",
device, blknr, blkcnt, (ulong)buffer);
ide_led (DEVICE_LED(device), 1); /* LED on */
/* Select device
*/
ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
c = ide_wait (device, IDE_TIME_OUT);
if (c & ATA_STAT_BUSY) {
printf ("IDE read: device %d not ready\n", device);
goto IDE_READ_E;
}
/* first check if the drive is in Powersaving mode, if yes,
* increase the timeout value */
ide_outb (device, ATA_COMMAND, ATA_CMD_CHK_PWR);
udelay (50);
c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */
if (c & ATA_STAT_BUSY) {
printf ("IDE read: device %d not ready\n", device);
goto IDE_READ_E;
}
if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
printf ("No Powersaving mode %X\n", c);
} else {
c = ide_inb(device,ATA_SECT_CNT);
debug ("Powersaving %02X\n",c);
if(c==0)
pwrsave=1;
}
while (blkcnt-- > 0) {
c = ide_wait (device, IDE_TIME_OUT);
if (c & ATA_STAT_BUSY) {
printf ("IDE read: device %d not ready\n", device);
break;
}
if (lba48) {
/* write high bits */
ide_outb (device, ATA_SECT_CNT, 0);
ide_outb (device, ATA_LBA_LOW, (blknr >> 24) & 0xFF);
#ifdef CONFIG_SYS_64BIT_LBA
ide_outb (device, ATA_LBA_MID, (blknr >> 32) & 0xFF);
ide_outb (device, ATA_LBA_HIGH, (blknr >> 40) & 0xFF);
#else
ide_outb (device, ATA_LBA_MID, 0);
ide_outb (device, ATA_LBA_HIGH, 0);
#endif
ide_outb (device, ATA_SECT_CNT, 1);
ide_outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
ide_outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
ide_outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
if (lba48) {
ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device) );
ide_outb (device, ATA_COMMAND, ATA_CMD_READ_EXT);
} else
#endif
{
ide_outb (device, ATA_DEV_HD, ATA_LBA |
ATA_DEVICE(device) |
((blknr >> 24) & 0xF) );
ide_outb (device, ATA_COMMAND, ATA_CMD_READ);
}
udelay (50);
if(pwrsave) {
c = ide_wait (device, IDE_SPIN_UP_TIME_OUT); /* may take up to 4 sec */
pwrsave=0;
} else {
c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */
}
if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
#if defined(CONFIG_SYS_64BIT_LBA) && defined(CONFIG_SYS_64BIT_VSPRINTF)
printf ("Error (no IRQ) dev %d blk %Ld: status 0x%02x\n",
#else
printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
device, (ulong)blknr, c);
#endif
break;
}
input_data (device, buffer, ATA_SECTORWORDS);
(void) ide_inb (device, ATA_STATUS); /* clear IRQ */
buffer += ATA_BLOCKSIZE;
}
IDE_READ_E:
ide_led (DEVICE_LED(device), 0); /* LED off */
return (n);
}
/* ------------------------------------------------------------------------- */
Grant Likely
committed
ulong ide_write (int device, lbaint_t blknr, ulong blkcnt, void *buffer)
if (blknr & 0x0000fffff0000000ULL) {
/* more than 28 bits used, use 48bit mode */
lba48 = 1;
}
#endif
ide_led (DEVICE_LED(device), 1); /* LED on */
/* Select device
*/
ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
while (blkcnt-- > 0) {
c = ide_wait (device, IDE_TIME_OUT);
if (c & ATA_STAT_BUSY) {
printf ("IDE read: device %d not ready\n", device);
goto WR_OUT;
}
if (lba48) {
/* write high bits */
ide_outb (device, ATA_SECT_CNT, 0);
ide_outb (device, ATA_LBA_LOW, (blknr >> 24) & 0xFF);
#ifdef CONFIG_SYS_64BIT_LBA
ide_outb (device, ATA_LBA_MID, (blknr >> 32) & 0xFF);
ide_outb (device, ATA_LBA_HIGH, (blknr >> 40) & 0xFF);
#else
ide_outb (device, ATA_LBA_MID, 0);
ide_outb (device, ATA_LBA_HIGH, 0);
#endif
ide_outb (device, ATA_SECT_CNT, 1);
ide_outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
ide_outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
ide_outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
if (lba48) {
ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device) );
ide_outb (device, ATA_COMMAND, ATA_CMD_WRITE_EXT);
} else
#endif
{
ide_outb (device, ATA_DEV_HD, ATA_LBA |
ATA_DEVICE(device) |
((blknr >> 24) & 0xF) );
ide_outb (device, ATA_COMMAND, ATA_CMD_WRITE);
}
udelay (50);
c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */
if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
#if defined(CONFIG_SYS_64BIT_LBA) && defined(CONFIG_SYS_64BIT_VSPRINTF)
printf ("Error (no IRQ) dev %d blk %Ld: status 0x%02x\n",
#else
printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
device, (ulong)blknr, c);
#endif
goto WR_OUT;
}
output_data (device, buffer, ATA_SECTORWORDS);
c = ide_inb (device, ATA_STATUS); /* clear IRQ */
buffer += ATA_BLOCKSIZE;
}
WR_OUT:
ide_led (DEVICE_LED(device), 0); /* LED off */
return (n);
}
/* ------------------------------------------------------------------------- */
/*
* copy src to dest, skipping leading and trailing blanks and null
* terminate the string
* "len" is the size of available memory including the terminating '\0'
static void ident_cpy (unsigned char *dst, unsigned char *src, unsigned int len)
unsigned char *end, *last;
last = dst;
/* reserve space for '\0' */
if (len < 2)
goto OUT;
/* skip leading white space */
while ((*src) && (src<end) && (*src==' '))
++src;
/* copy string, omitting trailing white space */
while ((*src) && (src<end)) {
*dst++ = *src;
if (*src++ != ' ')
last = dst;
}
/* ------------------------------------------------------------------------- */
/*
* Wait until Busy bit is off, or timeout (in ms)
* Return last status
*/
static uchar ide_wait (int dev, ulong t)
{
ulong delay = 10 * t; /* poll every 100 us */
uchar c;
while ((c = ide_inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) {
udelay (100);
if (delay-- == 0) {
break;
}
}
return (c);
}
/* ------------------------------------------------------------------------- */
#ifdef CONFIG_IDE_RESET
extern void ide_set_reset(int idereset);
static void ide_reset (void)
{
#if defined(CONFIG_SYS_PB_12V_ENABLE) || defined(CONFIG_SYS_PB_IDE_MOTOR)
volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
for (i=0; i<CONFIG_SYS_IDE_MAXBUS; ++i)
for (i=0; i<CONFIG_SYS_IDE_MAXDEVICE; ++i)
ide_dev_desc[i].type = DEV_TYPE_UNKNOWN;
ide_set_reset (1); /* assert reset */
/* the reset signal shall be asserted for et least 25 us */
udelay(25);
#ifdef CONFIG_SYS_PB_12V_ENABLE
immr->im_cpm.cp_pbdat &= ~(CONFIG_SYS_PB_12V_ENABLE); /* 12V Enable output OFF */
immr->im_cpm.cp_pbpar &= ~(CONFIG_SYS_PB_12V_ENABLE);
immr->im_cpm.cp_pbodr &= ~(CONFIG_SYS_PB_12V_ENABLE);
immr->im_cpm.cp_pbdir |= CONFIG_SYS_PB_12V_ENABLE;
/* wait 500 ms for the voltage to stabilize
*/
for (i=0; i<500; ++i) {
udelay (1000);
}
immr->im_cpm.cp_pbdat |= CONFIG_SYS_PB_12V_ENABLE; /* 12V Enable output ON */
#endif /* CONFIG_SYS_PB_12V_ENABLE */
#ifdef CONFIG_SYS_PB_IDE_MOTOR
/* configure IDE Motor voltage monitor pin as input */
immr->im_cpm.cp_pbpar &= ~(CONFIG_SYS_PB_IDE_MOTOR);
immr->im_cpm.cp_pbodr &= ~(CONFIG_SYS_PB_IDE_MOTOR);
immr->im_cpm.cp_pbdir &= ~(CONFIG_SYS_PB_IDE_MOTOR);
/* wait up to 1 s for the motor voltage to stabilize
*/
for (i=0; i<1000; ++i) {
if ((immr->im_cpm.cp_pbdat & CONFIG_SYS_PB_IDE_MOTOR) != 0) {
break;
}
udelay (1000);
}
if (i == 1000) { /* Timeout */
printf ("\nWarning: 5V for IDE Motor missing\n");
# ifdef CONFIG_STATUS_LED
# ifdef STATUS_LED_YELLOW
status_led_set (STATUS_LED_YELLOW, STATUS_LED_ON );
# endif
# ifdef STATUS_LED_GREEN
status_led_set (STATUS_LED_GREEN, STATUS_LED_OFF);
# endif
# endif /* CONFIG_STATUS_LED */
}
#endif /* CONFIG_SYS_PB_IDE_MOTOR */
WATCHDOG_RESET();
/* de-assert RESET signal */
ide_set_reset(0);
/* wait 250 ms */
for (i=0; i<250; ++i) {
udelay (1000);
}
}
#endif /* CONFIG_IDE_RESET */
/* ------------------------------------------------------------------------- */
#if defined(CONFIG_IDE_LED) && \
!defined(CONFIG_AMIGAONEG3SE)&& \
!defined(CONFIG_CPC45) && \
!defined(CONFIG_HMI10) && \
!defined(CONFIG_KUP4K) && \
!defined(CONFIG_KUP4X)
static uchar led_buffer = 0; /* Buffer for current LED status */
static void ide_led (uchar led, uchar status)
{
uchar *led_port = LED_PORT;
if (status) { /* switch LED on */
led_buffer |= led;
} else { /* switch LED off */
led_buffer &= ~led;
}
*led_port = led_buffer;
}
#endif /* CONFIG_IDE_LED */
#if defined(CONFIG_OF_IDE_FIXUP)
int ide_device_present(int dev)
{
if (dev >= CONFIG_SYS_IDE_MAXBUS)
return 0;
return (ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN ? 0 : 1);
}
#endif
/* ------------------------------------------------------------------------- */
#ifdef CONFIG_ATAPI
/****************************************************************************
* ATAPI Support
*/
#if defined(__PPC__) || defined(CONFIG_PXA_PCMCIA)
/* since ATAPI may use commands with not 4 bytes alligned length
* we have our own transfer functions, 2 bytes alligned */
static void
output_data_shorts(int dev, ushort *sect_buf, int shorts)
{
#if defined(CONFIG_HMI10) || defined(CONFIG_CPC45)
uchar *dbuf;
volatile uchar *pbuf_even;
volatile uchar *pbuf_odd;
pbuf_even = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_EVEN);
pbuf_odd = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_ODD);
while (shorts--) {
EIEIO;
*pbuf_even = *dbuf++;
EIEIO;
*pbuf_odd = *dbuf++;
}
ushort *dbuf;
volatile ushort *pbuf;
pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
dbuf = (ushort *)sect_buf;
debug ("in output data shorts base for read is %lx\n", (unsigned long) pbuf);
EIEIO;
*pbuf = *dbuf++;
#endif
}
static void
input_data_shorts(int dev, ushort *sect_buf, int shorts)
{
#if defined(CONFIG_HMI10) || defined(CONFIG_CPC45)
uchar *dbuf;
volatile uchar *pbuf_even;
volatile uchar *pbuf_odd;
pbuf_even = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_EVEN);
pbuf_odd = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_ODD);
while (shorts--) {
EIEIO;
*dbuf++ = *pbuf_even;
EIEIO;
*dbuf++ = *pbuf_odd;
}
#else
ushort *dbuf;
volatile ushort *pbuf;
pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
dbuf = (ushort *)sect_buf;
debug("in input data shorts base for read is %lx\n", (unsigned long) pbuf);
while (shorts--) {
EIEIO;
*dbuf++ = *pbuf;
}
#endif
#else /* ! __PPC__ */
static void
output_data_shorts(int dev, ushort *sect_buf, int shorts)
{
outsw(ATA_CURR_BASE(dev)+ATA_DATA_REG, sect_buf, shorts);
}
static void
input_data_shorts(int dev, ushort *sect_buf, int shorts)
{
insw(ATA_CURR_BASE(dev)+ATA_DATA_REG, sect_buf, shorts);
}
#endif /* __PPC__ */
/*
* Wait until (Status & mask) == res, or timeout (in ms)
* Return last status
* This is used since some ATAPI CD ROMs clears their Busy Bit first
* and then they set their DRQ Bit
*/
static uchar atapi_wait_mask (int dev, ulong t,uchar mask, uchar res)
{
ulong delay = 10 * t; /* poll every 100 us */
uchar c;
c = ide_inb(dev,ATA_DEV_CTL); /* prevents to read the status before valid */
while (((c = ide_inb(dev, ATA_STATUS)) & mask) != res) {
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
/* break if error occurs (doesn't make sense to wait more) */
if((c & ATA_STAT_ERR)==ATA_STAT_ERR)
break;
udelay (100);
if (delay-- == 0) {
break;
}
}
return (c);
}
/*
* issue an atapi command
*/
unsigned char atapi_issue(int device,unsigned char* ccb,int ccblen, unsigned char * buffer,int buflen)
{
unsigned char c,err,mask,res;
int n;
ide_led (DEVICE_LED(device), 1); /* LED on */
/* Select device
*/
mask = ATA_STAT_BUSY|ATA_STAT_DRQ;
res = 0;
#ifdef CONFIG_AMIGAONEG3SE
# warning THF: Removed LBA mode ???
#endif
ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
if ((c & mask) != res) {
printf ("ATAPI_ISSUE: device %d not ready status %X\n", device,c);
err=0xFF;
goto AI_OUT;
}
/* write taskfile */
ide_outb (device, ATA_ERROR_REG, 0); /* no DMA, no overlaped */
ide_outb (device, ATA_SECT_CNT, 0);
ide_outb (device, ATA_SECT_NUM, 0);
ide_outb (device, ATA_CYL_LOW, (unsigned char)(buflen & 0xFF));
ide_outb (device, ATA_CYL_HIGH, (unsigned char)((buflen>>8) & 0xFF));
#ifdef CONFIG_AMIGAONEG3SE
# warning THF: Removed LBA mode ???
#endif
ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
ide_outb (device, ATA_COMMAND, ATAPI_CMD_PACKET);
udelay (50);
mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR;
res = ATA_STAT_DRQ;
c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
if ((c & mask) != res) { /* DRQ must be 1, BSY 0 */
printf ("ATAPI_ISSUE: Error (no IRQ) before sending ccb dev %d status 0x%02x\n",device,c);
err=0xFF;
goto AI_OUT;
}
output_data_shorts (device, (unsigned short *)ccb,ccblen/2); /* write command block */
/* ATAPI Command written wait for completition */
udelay (5000); /* device must set bsy */
mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR;
/* if no data wait for DRQ = 0 BSY = 0
* if data wait for DRQ = 1 BSY = 0 */
res=0;
if(buflen)
res = ATA_STAT_DRQ;
c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
if ((c & mask) != res ) {
if (c & ATA_STAT_ERR) {
err=(ide_inb(device,ATA_ERROR_REG))>>4;
debug ("atapi_issue 1 returned sense key %X status %02X\n",err,c);
printf ("ATAPI_ISSUE: (no DRQ) after sending ccb (%x) status 0x%02x\n", ccb[0],c);
n=ide_inb(device, ATA_CYL_HIGH);
n+=ide_inb(device, ATA_CYL_LOW);
if(n>buflen) {
printf("ERROR, transfer bytes %d requested only %d\n",n,buflen);
err=0xff;
goto AI_OUT;
}
if((n==0)&&(buflen<0)) {
printf("ERROR, transfer bytes %d requested %d\n",n,buflen);
err=0xff;
goto AI_OUT;
}
if(n!=buflen) {
debug ("WARNING, transfer bytes %d not equal with requested %d\n",n,buflen);
debug ("ATAPI_ISSUE: %d Bytes to transfer\n",n);
/* we transfer shorts */
n>>=1;
/* ok now decide if it is an in or output */
if ((ide_inb(device, ATA_SECT_CNT)&0x02)==0) {
debug ("Write to device\n");
output_data_shorts(device,(unsigned short *)buffer,n);
} else {
debug ("Read from device @ %p shorts %d\n",buffer,n);
input_data_shorts(device,(unsigned short *)buffer,n);
}
}
udelay(5000); /* seems that some CD ROMs need this... */
mask = ATA_STAT_BUSY|ATA_STAT_ERR;
res=0;
c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res);
if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
err=(ide_inb(device,ATA_ERROR_REG) >> 4);
debug ("atapi_issue 2 returned sense key %X status %X\n",err,c);
} else {
err = 0;
}
AI_OUT:
ide_led (DEVICE_LED(device), 0); /* LED off */
return (err);
}
/*
* sending the command to atapi_issue. If an status other than good
* returns, an request_sense will be issued
*/
#define ATAPI_UNIT_ATTN 10
unsigned char atapi_issue_autoreq (int device,
unsigned char* ccb,
int ccblen,
unsigned char *buffer,
int buflen)
{
unsigned char sense_data[18],sense_ccb[12];
unsigned char res,key,asc,ascq;
int notready,unitattn;
#ifdef CONFIG_AMIGAONEG3SE
char *s;
unsigned int timeout, retrycnt;
s = getenv("ide_cd_timeout");
timeout = s ? (simple_strtol(s, NULL, 10)*1000000)/5 : 0;
retrycnt = 0;
#endif
unitattn=ATAPI_UNIT_ATTN;
notready=ATAPI_DRIVE_NOT_READY;
retry:
res= atapi_issue(device,ccb,ccblen,buffer,buflen);
if (res==0)
return (0); /* Ok */
if (res==0xFF)
return (0xFF); /* error */
debug ("(auto_req)atapi_issue returned sense key %X\n",res);
memset(sense_ccb,0,sizeof(sense_ccb));
memset(sense_data,0,sizeof(sense_data));
sense_ccb[0]=ATAPI_CMD_REQ_SENSE;
sense_ccb[4]=18; /* allocation Length */
res=atapi_issue(device,sense_ccb,12,sense_data,18);
key=(sense_data[2]&0xF);
asc=(sense_data[12]);
ascq=(sense_data[13]);
debug ("ATAPI_CMD_REQ_SENSE returned %x\n",res);
debug (" Sense page: %02X key %02X ASC %02X ASCQ %02X\n",
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
sense_data[0],
key,
asc,
ascq);
if((key==0))
return 0; /* ok device ready */
if((key==6)|| (asc==0x29) || (asc==0x28)) { /* Unit Attention */
if(unitattn-->0) {
udelay(200*1000);
goto retry;
}
printf("Unit Attention, tried %d\n",ATAPI_UNIT_ATTN);
goto error;
}
if((asc==0x4) && (ascq==0x1)) { /* not ready, but will be ready soon */
if (notready-->0) {
udelay(200*1000);
goto retry;
}
printf("Drive not ready, tried %d times\n",ATAPI_DRIVE_NOT_READY);
goto error;
}
if(asc==0x3a) {
debug ("Media not present\n");
#ifdef CONFIG_AMIGAONEG3SE
if ((sense_data[2]&0xF)==0x0B) {
debug ("ABORTED COMMAND...retry\n");
if (retrycnt++ < 4)
goto retry;
return (0xFF);
}
if ((sense_data[2]&0xf) == 0x02 &&
sense_data[12] == 0x04 &&
sense_data[13] == 0x01 ) {
debug ("Waiting for unit to become active\n");
udelay(timeout);
if (retrycnt++ < 4)
goto retry;
return 0xFF;
}
#endif /* CONFIG_AMIGAONEG3SE */
printf ("ERROR: Unknown Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq);
error:
debug ("ERROR Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq);
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
return (0xFF);
}
static void atapi_inquiry(block_dev_desc_t * dev_desc)
{
unsigned char ccb[12]; /* Command descriptor block */
unsigned char iobuf[64]; /* temp buf */
unsigned char c;
int device;
device=dev_desc->dev;
dev_desc->type=DEV_TYPE_UNKNOWN; /* not yet valid */
dev_desc->block_read=atapi_read;
memset(ccb,0,sizeof(ccb));
memset(iobuf,0,sizeof(iobuf));
ccb[0]=ATAPI_CMD_INQUIRY;
ccb[4]=40; /* allocation Legnth */
c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,40);
debug ("ATAPI_CMD_INQUIRY returned %x\n",c);
if (c!=0)
return;
/* copy device ident strings */
ident_cpy((unsigned char*)dev_desc->vendor,&iobuf[8],8);
ident_cpy((unsigned char*)dev_desc->product,&iobuf[16],16);
ident_cpy((unsigned char*)dev_desc->revision,&iobuf[32],5);
dev_desc->lun=0;
dev_desc->lba=0;
dev_desc->blksz=0;
dev_desc->type=iobuf[0] & 0x1f;
if ((iobuf[1]&0x80)==0x80)