version 1.172.2.7, 2004/09/17 04:04:57 |
version 1.172.2.7.2.11, 2005/10/28 01:38:58 |
Line 125 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 125 __KERNEL_RCSID(0, "$NetBSD$"); |
|
/* timeout for the control commands */ |
/* timeout for the control commands */ |
#define WDC_CTRL_DELAY 10000 /* 10s, for the recall command */ |
#define WDC_CTRL_DELAY 10000 /* 10s, for the recall command */ |
|
|
|
/* |
|
* timeout when waiting for BSY to deassert when probing. |
|
* set to 5s. From the standards this could be up to 31, but we can't |
|
* wait that much at boot time, and 5s seems to be enouth. |
|
*/ |
|
#define WDC_PROBE_WAIT 5 |
|
|
struct pool wdc_xfer_pool; |
struct pool wdc_xfer_pool; |
|
|
#if NWD > 0 |
#if NWD > 0 |
Line 477 atabusconfig(struct atabus_softc *atabus |
|
Line 484 atabusconfig(struct atabus_softc *atabus |
|
int |
int |
wdcprobe(struct wdc_channel *chp) |
wdcprobe(struct wdc_channel *chp) |
{ |
{ |
|
struct wdc_softc *wdc = chp->ch_wdc; |
|
/* default reset method */ |
|
if (wdc != NULL && wdc->reset == NULL) |
|
wdc->reset = wdc_do_reset; |
|
|
return (wdcprobe1(chp, 1)); |
return (wdcprobe1(chp, 1)); |
} |
} |
|
|
wdcprobe1(struct wdc_channel *chp, int poll) |
wdcprobe1(struct wdc_channel *chp, int poll) |
{ |
{ |
struct wdc_softc *wdc = chp->ch_wdc; |
struct wdc_softc *wdc = chp->ch_wdc; |
u_int8_t st0, st1, sc, sn, cl, ch; |
u_int8_t st0 = 0, st1 = 0, sc, sn, cl, ch; |
u_int8_t ret_value = 0x03; |
u_int8_t ret_value = 0x03; |
u_int8_t drive; |
u_int8_t drive; |
int s; |
int s; |
|
int wdc_probe_count = |
|
poll ? (WDC_PROBE_WAIT / WDCDELAY) : (WDC_PROBE_WAIT * hz); |
|
|
/* |
/* |
* Sanity check to see if the wdc channel responds at all. |
* Sanity check to see if the wdc channel responds at all. |
Line 497 wdcprobe1(struct wdc_channel *chp, int p |
|
Line 510 wdcprobe1(struct wdc_channel *chp, int p |
|
s = splbio(); |
s = splbio(); |
if (wdc == NULL || |
if (wdc == NULL || |
(wdc->cap & WDC_CAPABILITY_NO_EXTRA_RESETS) == 0) { |
(wdc->cap & WDC_CAPABILITY_NO_EXTRA_RESETS) == 0) { |
|
while (wdc_probe_count-- > 0) { |
|
|
if (wdc != NULL && (wdc->cap & WDC_CAPABILITY_SELECT)) |
if (wdc != NULL && (wdc->cap & WDC_CAPABILITY_SELECT)) |
wdc->select(chp,0); |
wdc->select(chp,0); |
|
|
bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], 0, |
bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], |
WDSD_IBM); |
0, WDSD_IBM); |
delay(10); /* 400ns delay */ |
delay(10); /* 400ns delay */ |
st0 = bus_space_read_1(chp->cmd_iot, |
st0 = bus_space_read_1(chp->cmd_iot, |
chp->cmd_iohs[wd_status], 0); |
chp->cmd_iohs[wd_status], 0); |
|
|
if (wdc != NULL && (wdc->cap & WDC_CAPABILITY_SELECT)) |
if (wdc != NULL && (wdc->cap & WDC_CAPABILITY_SELECT)) |
wdc->select(chp,1); |
wdc->select(chp,1); |
|
|
bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], 0, |
bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], |
WDSD_IBM | 0x10); |
0, WDSD_IBM | 0x10); |
delay(10); /* 400ns delay */ |
delay(10); /* 400ns delay */ |
st1 = bus_space_read_1(chp->cmd_iot, |
st1 = bus_space_read_1(chp->cmd_iot, |
chp->cmd_iohs[wd_status], 0); |
chp->cmd_iohs[wd_status], 0); |
|
if ((st0 & WDCS_BSY) == 0) |
|
break; |
|
} |
|
|
WDCDEBUG_PRINT(("%s:%d: before reset, st0=0x%x, st1=0x%x\n", |
WDCDEBUG_PRINT(("%s:%d: before reset, st0=0x%x, st1=0x%x\n", |
wdc != NULL ? wdc->sc_dev.dv_xname : "wdcprobe", |
wdc != NULL ? wdc->sc_dev.dv_xname : "wdcprobe", |
Line 697 wdcprobe1(struct wdc_channel *chp, int p |
|
Line 714 wdcprobe1(struct wdc_channel *chp, int p |
|
delay(5000); |
delay(5000); |
#endif |
#endif |
|
|
if (wdc != NULL && (wdc->cap & WDC_CAPABILITY_SELECT)) |
if (wdc != NULL) |
wdc->select(chp,0); |
wdc->reset(chp, RESET_POLL); |
bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], 0, WDSD_IBM); |
else |
delay(10); /* 400ns delay */ |
wdc_do_reset(chp, RESET_POLL); |
/* assert SRST, wait for reset to complete */ |
|
bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, |
|
WDCTL_RST | WDCTL_IDS | WDCTL_4BIT); |
|
DELAY(1000); |
|
bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, |
|
WDCTL_IDS | WDCTL_4BIT); |
|
DELAY(2000); |
DELAY(2000); |
(void) bus_space_read_1(chp->cmd_iot, chp->cmd_iohs[wd_error], 0); |
(void) bus_space_read_1(chp->cmd_iot, chp->cmd_iohs[wd_error], 0); |
bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT); |
bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT); |
delay(10); /* 400ns delay */ |
|
/* ACK interrupt in case there is one pending left (Promise ATA100) */ |
|
if (wdc != NULL && (wdc->cap & WDC_CAPABILITY_IRQACK)) |
|
wdc->irqack(chp); |
|
splx(s); |
splx(s); |
|
|
ret_value = __wdcwait_reset(chp, ret_value, poll); |
ret_value = __wdcwait_reset(chp, ret_value, poll); |
Line 782 wdcattach(struct wdc_channel *chp) |
|
Line 789 wdcattach(struct wdc_channel *chp) |
|
callout_init(&chp->ch_callout); |
callout_init(&chp->ch_callout); |
if (wdc->drv_probe == NULL) |
if (wdc->drv_probe == NULL) |
wdc->drv_probe = wdc_drvprobe; |
wdc->drv_probe = wdc_drvprobe; |
|
if (wdc->reset == NULL) |
|
wdc->reset = wdc_do_reset; |
if (inited == 0) { |
if (inited == 0) { |
/* Initialize the ata_xfer pool. */ |
/* Initialize the ata_xfer pool. */ |
pool_init(&wdc_xfer_pool, sizeof(struct ata_xfer), 0, |
pool_init(&wdc_xfer_pool, sizeof(struct ata_xfer), 0, |
Line 873 wdcstart(struct wdc_channel *chp) |
|
Line 882 wdcstart(struct wdc_channel *chp) |
|
if (__predict_false(chp->ch_queue->queue_freeze > 0)) { |
if (__predict_false(chp->ch_queue->queue_freeze > 0)) { |
return; /* queue froozen */ |
return; /* queue froozen */ |
} |
} |
|
/* |
|
* if someone is waiting for the command to be active, wake it up |
|
* and let it process the command |
|
*/ |
|
if (xfer->c_flags & C_WAITACT) { |
|
WDCDEBUG_PRINT(("atastart: xfer %p channel %d drive %d " |
|
"wait active\n", xfer, chp->ch_channel, xfer->c_drive), |
|
DEBUG_XFERS); |
|
wakeup(xfer); |
|
return; |
|
} |
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
if ((chp->ch_flags & WDCF_IRQ_WAIT) != 0) |
if ((chp->ch_flags & WDCF_IRQ_WAIT) != 0) |
panic("wdcstart: channel waiting for irq"); |
panic("wdcstart: channel waiting for irq"); |
Line 1022 wdcreset(struct wdc_channel *chp, int po |
|
Line 1042 wdcreset(struct wdc_channel *chp, int po |
|
{ |
{ |
struct wdc_softc *wdc = chp->ch_wdc; |
struct wdc_softc *wdc = chp->ch_wdc; |
int drv_mask1, drv_mask2; |
int drv_mask1, drv_mask2; |
|
|
|
wdc->reset(chp, poll); |
|
|
|
drv_mask1 = (chp->ch_drive[0].drive_flags & DRIVE) ? 0x01:0x00; |
|
drv_mask1 |= (chp->ch_drive[1].drive_flags & DRIVE) ? 0x02:0x00; |
|
drv_mask2 = __wdcwait_reset(chp, drv_mask1, |
|
(poll == RESET_SLEEP) ? 0 : 1); |
|
if (drv_mask2 != drv_mask1) { |
|
printf("%s channel %d: reset failed for", |
|
wdc->sc_dev.dv_xname, chp->ch_channel); |
|
if ((drv_mask1 & 0x01) != 0 && (drv_mask2 & 0x01) == 0) |
|
printf(" drive 0"); |
|
if ((drv_mask1 & 0x02) != 0 && (drv_mask2 & 0x02) == 0) |
|
printf(" drive 1"); |
|
printf("\n"); |
|
} |
|
bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT); |
|
return (drv_mask1 != drv_mask2) ? 1 : 0; |
|
} |
|
|
|
void |
|
wdc_do_reset(struct wdc_channel *chp, int poll) |
|
{ |
|
struct wdc_softc *wdc = chp->ch_wdc; |
int s = 0; |
int s = 0; |
|
|
if (wdc->cap & WDC_CAPABILITY_SELECT) |
if (wdc && wdc->cap & WDC_CAPABILITY_SELECT) |
wdc->select(chp,0); |
wdc->select(chp,0); |
if (poll != RESET_SLEEP) |
if (poll != RESET_SLEEP) |
s = splbio(); |
s = splbio(); |
Line 1032 wdcreset(struct wdc_channel *chp, int po |
|
Line 1076 wdcreset(struct wdc_channel *chp, int po |
|
bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], 0, WDSD_IBM); |
bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], 0, WDSD_IBM); |
delay(10); /* 400ns delay */ |
delay(10); /* 400ns delay */ |
bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, |
bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, |
|
WDCTL_IDS | WDCTL_4BIT); |
|
delay(10); /* 400ns delay */ |
|
/* assert SRST, wait for reset to complete */ |
|
bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, |
WDCTL_RST | WDCTL_IDS | WDCTL_4BIT); |
WDCTL_RST | WDCTL_IDS | WDCTL_4BIT); |
delay(2000); |
delay(2000); |
(void) bus_space_read_1(chp->cmd_iot, chp->cmd_iohs[wd_error], 0); |
(void) bus_space_read_1(chp->cmd_iot, chp->cmd_iohs[wd_error], 0); |
Line 1039 wdcreset(struct wdc_channel *chp, int po |
|
Line 1087 wdcreset(struct wdc_channel *chp, int po |
|
WDCTL_4BIT | WDCTL_IDS); |
WDCTL_4BIT | WDCTL_IDS); |
delay(10); /* 400ns delay */ |
delay(10); /* 400ns delay */ |
if (poll != RESET_SLEEP) { |
if (poll != RESET_SLEEP) { |
if (wdc->cap & WDC_CAPABILITY_IRQACK) |
if (wdc && wdc->cap & WDC_CAPABILITY_IRQACK) |
wdc->irqack(chp); |
wdc->irqack(chp); |
splx(s); |
splx(s); |
} |
} |
|
|
drv_mask1 = (chp->ch_drive[0].drive_flags & DRIVE) ? 0x01:0x00; |
|
drv_mask1 |= (chp->ch_drive[1].drive_flags & DRIVE) ? 0x02:0x00; |
|
drv_mask2 = __wdcwait_reset(chp, drv_mask1, |
|
(poll == RESET_SLEEP) ? 0 : 1); |
|
if (drv_mask2 != drv_mask1) { |
|
printf("%s channel %d: reset failed for", |
|
wdc->sc_dev.dv_xname, chp->ch_channel); |
|
if ((drv_mask1 & 0x01) != 0 && (drv_mask2 & 0x01) == 0) |
|
printf(" drive 0"); |
|
if ((drv_mask1 & 0x02) != 0 && (drv_mask2 & 0x02) == 0) |
|
printf(" drive 1"); |
|
printf("\n"); |
|
} |
|
bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT); |
|
return (drv_mask1 != drv_mask2) ? 1 : 0; |
|
} |
} |
|
|
static int |
static int |
Line 1573 wdc_downgrade_mode(struct ata_drive_data |
|
Line 1605 wdc_downgrade_mode(struct ata_drive_data |
|
return 0; |
return 0; |
|
|
/* |
/* |
* If we were using Ultra-DMA mode > 2, downgrade to mode 2 first. |
* If we were using Ultra-DMA mode, downgrade to the next lower mode. |
* Maybe we didn't properly notice the cable type |
|
* If we were using Ultra-DMA mode 2, downgrade to mode 1 first. |
|
* It helps in some cases. |
|
*/ |
*/ |
if ((drvp->drive_flags & DRIVE_UDMA) && drvp->UDMA_mode >= 2) { |
if ((drvp->drive_flags & DRIVE_UDMA) && drvp->UDMA_mode >= 2) { |
drvp->UDMA_mode = (drvp->UDMA_mode == 2) ? 1 : 2; |
drvp->UDMA_mode--; |
printf("%s: transfer error, downgrading to Ultra-DMA mode %d\n", |
printf("%s: transfer error, downgrading to Ultra-DMA mode %d\n", |
drv_dev->dv_xname, drvp->UDMA_mode); |
drv_dev->dv_xname, drvp->UDMA_mode); |
} |
} |
|
|
/* |
/* |
* If we were using ultra-DMA, don't downgrade to multiword DMA |
* If we were using ultra-DMA, don't downgrade to multiword DMA. |
* if we noticed a CRC error. It has been noticed that CRC errors |
|
* in ultra-DMA lead to silent data corruption in multiword DMA. |
|
* Data corruption is less likely to occur in PIO mode. |
|
*/ |
*/ |
else if ((drvp->drive_flags & DRIVE_UDMA) && |
else if (drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) { |
(drvp->drive_flags & DRIVE_DMAERR) == 0) { |
|
drvp->drive_flags &= ~DRIVE_UDMA; |
|
drvp->drive_flags |= DRIVE_DMA; |
|
drvp->DMA_mode = drvp->DMA_cap; |
|
printf("%s: transfer error, downgrading to DMA mode %d\n", |
|
drv_dev->dv_xname, drvp->DMA_mode); |
|
} else if (drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) { |
|
drvp->drive_flags &= ~(DRIVE_DMA | DRIVE_UDMA); |
drvp->drive_flags &= ~(DRIVE_DMA | DRIVE_UDMA); |
drvp->PIO_mode = drvp->PIO_cap; |
drvp->PIO_mode = drvp->PIO_cap; |
printf("%s: transfer error, downgrading to PIO mode %d\n", |
printf("%s: transfer error, downgrading to PIO mode %d\n", |
Line 1635 wdc_exec_command(struct ata_drive_datas |
|
Line 1654 wdc_exec_command(struct ata_drive_datas |
|
wdc_c->flags |= AT_POLL; |
wdc_c->flags |= AT_POLL; |
if (wdc_c->flags & AT_POLL) |
if (wdc_c->flags & AT_POLL) |
xfer->c_flags |= C_POLL; |
xfer->c_flags |= C_POLL; |
|
if (wdc_c->flags & AT_WAIT) |
|
xfer->c_flags |= C_WAIT; |
xfer->c_drive = drvp->drive; |
xfer->c_drive = drvp->drive; |
xfer->c_databuf = wdc_c->data; |
xfer->c_databuf = wdc_c->data; |
xfer->c_bcount = wdc_c->bcount; |
xfer->c_bcount = wdc_c->bcount; |
Line 1672 __wdccommand_start(struct wdc_channel *c |
|
Line 1693 __wdccommand_start(struct wdc_channel *c |
|
struct wdc_softc *wdc = chp->ch_wdc; |
struct wdc_softc *wdc = chp->ch_wdc; |
int drive = xfer->c_drive; |
int drive = xfer->c_drive; |
struct wdc_command *wdc_c = xfer->c_cmd; |
struct wdc_command *wdc_c = xfer->c_cmd; |
|
int wait_flags = (xfer->c_flags & C_POLL) ? AT_POLL : 0; |
|
|
WDCDEBUG_PRINT(("__wdccommand_start %s:%d:%d\n", |
WDCDEBUG_PRINT(("__wdccommand_start %s:%d:%d\n", |
wdc->sc_dev.dv_xname, chp->ch_channel, xfer->c_drive), |
wdc->sc_dev.dv_xname, chp->ch_channel, xfer->c_drive), |
Line 1682 __wdccommand_start(struct wdc_channel *c |
|
Line 1704 __wdccommand_start(struct wdc_channel *c |
|
bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], 0, |
bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], 0, |
WDSD_IBM | (drive << 4)); |
WDSD_IBM | (drive << 4)); |
switch(wdcwait(chp, wdc_c->r_st_bmask | WDCS_DRQ, |
switch(wdcwait(chp, wdc_c->r_st_bmask | WDCS_DRQ, |
wdc_c->r_st_bmask, wdc_c->timeout, wdc_c->flags)) { |
wdc_c->r_st_bmask, wdc_c->timeout, wait_flags)) { |
case WDCWAIT_OK: |
case WDCWAIT_OK: |
break; |
break; |
case WDCWAIT_TOUT: |
case WDCWAIT_TOUT: |
Line 1722 __wdccommand_intr(struct wdc_channel *ch |
|
Line 1744 __wdccommand_intr(struct wdc_channel *ch |
|
int bcount = wdc_c->bcount; |
int bcount = wdc_c->bcount; |
char *data = wdc_c->data; |
char *data = wdc_c->data; |
int wflags; |
int wflags; |
|
int drive_flags = chp->ch_drive[xfer->c_drive].drive_flags; |
|
int wdc_cap; |
|
|
|
if (wdc_c->r_command == WDCC_IDENTIFY || |
|
wdc_c->r_command == ATAPI_IDENTIFY_DEVICE) { |
|
/* |
|
* The IDENTIFY data has been designed as an array of |
|
* u_int16_t, so we can byteswap it on the fly. |
|
* Historically it's what we have always done so keeping it |
|
* here ensure binary backward compatibility. |
|
*/ |
|
wdc_cap = WDC_CAPABILITY_ATA_NOSTREAM | wdc->cap; |
|
} else { |
|
/* |
|
* Other data structure are opaque and should be transfered |
|
* as is. |
|
*/ |
|
wdc_cap = wdc->cap; |
|
} |
|
|
if ((wdc_c->flags & (AT_WAIT | AT_POLL)) == (AT_WAIT | AT_POLL)) { |
if ((wdc_c->flags & (AT_WAIT | AT_POLL)) == (AT_WAIT | AT_POLL)) { |
/* both wait and poll, we can tsleep here */ |
/* both wait and poll, we can tsleep here */ |
Line 1763 __wdccommand_intr(struct wdc_channel *ch |
|
Line 1804 __wdccommand_intr(struct wdc_channel *ch |
|
wdc_c->flags |= AT_TIMEOU; |
wdc_c->flags |= AT_TIMEOU; |
goto out; |
goto out; |
} |
} |
if (wdc->cap & WDC_CAPABILITY_IRQACK) |
if (wdc_cap & WDC_CAPABILITY_IRQACK) |
wdc->irqack(chp); |
wdc->irqack(chp); |
if (wdc_c->flags & AT_READ) { |
if (wdc_c->flags & AT_READ) { |
if ((chp->ch_status & WDCS_DRQ) == 0) { |
if ((chp->ch_status & WDCS_DRQ) == 0) { |
wdc_c->flags |= AT_TIMEOU; |
wdc_c->flags |= AT_TIMEOU; |
goto out; |
goto out; |
} |
} |
if (chp->ch_drive[xfer->c_drive].drive_flags & DRIVE_CAP32) { |
if (wdc_cap & WDC_CAPABILITY_ATA_NOSTREAM) { |
bus_space_read_multi_4(chp->data32iot, chp->data32ioh, |
if (drive_flags & DRIVE_CAP32) { |
0, (u_int32_t*)data, bcount >> 2); |
bus_space_read_multi_4(chp->data32iot, |
data += bcount & 0xfffffffc; |
chp->data32ioh, 0, (u_int32_t*)data, |
bcount = bcount & 0x03; |
bcount >> 2); |
} |
data += bcount & 0xfffffffc; |
if (bcount > 0) |
bcount = bcount & 0x03; |
bus_space_read_multi_2(chp->cmd_iot, |
} |
chp->cmd_iohs[wd_data], 0, |
if (bcount > 0) |
(u_int16_t *)data, bcount >> 1); |
bus_space_read_multi_2(chp->cmd_iot, |
|
chp->cmd_iohs[wd_data], 0, |
|
(u_int16_t *)data, bcount >> 1); |
|
} else { |
|
if (drive_flags & DRIVE_CAP32) { |
|
bus_space_read_multi_stream_4(chp->data32iot, |
|
chp->data32ioh, 0, (u_int32_t*)data, |
|
bcount >> 2); |
|
data += bcount & 0xfffffffc; |
|
bcount = bcount & 0x03; |
|
} |
|
if (bcount > 0) |
|
bus_space_read_multi_stream_2(chp->cmd_iot, |
|
chp->cmd_iohs[wd_data], 0, |
|
(u_int16_t *)data, bcount >> 1); |
|
} |
/* at this point the drive should be in its initial state */ |
/* at this point the drive should be in its initial state */ |
wdc_c->flags |= AT_XFDONE; |
wdc_c->flags |= AT_XFDONE; |
/* XXX should read status register here ? */ |
/* XXX should read status register here ? */ |
Line 1788 __wdccommand_intr(struct wdc_channel *ch |
|
Line 1844 __wdccommand_intr(struct wdc_channel *ch |
|
wdc_c->flags |= AT_TIMEOU; |
wdc_c->flags |= AT_TIMEOU; |
goto out; |
goto out; |
} |
} |
if (chp->ch_drive[xfer->c_drive].drive_flags & DRIVE_CAP32) { |
if (wdc_cap & WDC_CAPABILITY_ATA_NOSTREAM) { |
bus_space_write_multi_4(chp->data32iot, chp->data32ioh, |
if (drive_flags & DRIVE_CAP32) { |
0, (u_int32_t*)data, bcount >> 2); |
bus_space_write_multi_4(chp->data32iot, |
data += bcount & 0xfffffffc; |
chp->data32ioh, 0, (u_int32_t*)data, |
bcount = bcount & 0x03; |
bcount >> 2); |
} |
data += bcount & 0xfffffffc; |
if (bcount > 0) |
bcount = bcount & 0x03; |
bus_space_write_multi_2(chp->cmd_iot, |
} |
chp->cmd_iohs[wd_data], 0, |
if (bcount > 0) |
(u_int16_t *)data, bcount >> 1); |
bus_space_write_multi_2(chp->cmd_iot, |
|
chp->cmd_iohs[wd_data], 0, |
|
(u_int16_t *)data, bcount >> 1); |
|
} else { |
|
if (drive_flags & DRIVE_CAP32) { |
|
bus_space_write_multi_stream_4(chp->data32iot, |
|
chp->data32ioh, 0, (u_int32_t*)data, |
|
bcount >> 2); |
|
data += bcount & 0xfffffffc; |
|
bcount = bcount & 0x03; |
|
} |
|
if (bcount > 0) |
|
bus_space_write_multi_stream_2(chp->cmd_iot, |
|
chp->cmd_iohs[wd_data], 0, |
|
(u_int16_t *)data, bcount >> 1); |
|
} |
wdc_c->flags |= AT_XFDONE; |
wdc_c->flags |= AT_XFDONE; |
if ((wdc_c->flags & AT_POLL) == 0) { |
if ((wdc_c->flags & AT_POLL) == 0) { |
chp->ch_flags |= WDCF_IRQ_WAIT; /* wait for interrupt */ |
chp->ch_flags |= WDCF_IRQ_WAIT; /* wait for interrupt */ |
Line 2016 wdc_exec_xfer(struct wdc_channel *chp, s |
|
Line 2087 wdc_exec_xfer(struct wdc_channel *chp, s |
|
TAILQ_INSERT_TAIL(&chp->ch_queue->queue_xfer, xfer, c_xferchain); |
TAILQ_INSERT_TAIL(&chp->ch_queue->queue_xfer, xfer, c_xferchain); |
WDCDEBUG_PRINT(("wdcstart from wdc_exec_xfer, flags 0x%x\n", |
WDCDEBUG_PRINT(("wdcstart from wdc_exec_xfer, flags 0x%x\n", |
chp->ch_flags), DEBUG_XFERS); |
chp->ch_flags), DEBUG_XFERS); |
|
/* |
|
* if polling and can sleep, wait for the xfer to be at head of queue |
|
*/ |
|
if ((xfer->c_flags & (C_POLL | C_WAIT)) == (C_POLL | C_WAIT)) { |
|
while (TAILQ_FIRST(&chp->ch_queue->queue_xfer) != xfer) { |
|
xfer->c_flags |= C_WAITACT; |
|
tsleep(xfer, PRIBIO, "ataact", 0); |
|
xfer->c_flags &= ~C_WAITACT; |
|
if (xfer->c_flags & C_FREE) { |
|
wdc_free_xfer(chp, xfer); |
|
return; |
|
} |
|
} |
|
} |
wdcstart(chp); |
wdcstart(chp); |
} |
} |
|
|
Line 2041 wdc_free_xfer(struct wdc_channel *chp, s |
|
Line 2126 wdc_free_xfer(struct wdc_channel *chp, s |
|
struct wdc_softc *wdc = chp->ch_wdc; |
struct wdc_softc *wdc = chp->ch_wdc; |
int s; |
int s; |
|
|
|
if (xfer->c_flags & C_WAITACT) { |
|
/* Someone is waiting for this xfer, so we can't free now */ |
|
xfer->c_flags |= C_FREE; |
|
wakeup(xfer); |
|
return; |
|
} |
|
|
if (wdc->cap & WDC_CAPABILITY_HWLOCK) |
if (wdc->cap & WDC_CAPABILITY_HWLOCK) |
(*wdc->free_hw)(chp); |
(*wdc->free_hw)(chp); |
s = splbio(); |
s = splbio(); |