version 1.30, 2001/06/13 18:17:40 |
version 1.30.2.3, 2002/06/23 17:45:53 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
|
|
/* |
/* |
* Copyright (c) 1998 Manuel Bouyer. |
* Copyright (c) 1998, 2001 Manuel Bouyer. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* modification, are permitted provided that the following conditions |
|
|
* documentation and/or other materials provided with the distribution. |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* This product includes software developed by Manuel Bouyer. |
* California, Berkeley and its contributors. |
|
* 4. Neither the name of the University nor the names of its contributors |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* without specific prior written permission. |
|
|
* POSSIBILITY OF SUCH DAMAGE. |
* POSSIBILITY OF SUCH DAMAGE. |
*/ |
*/ |
|
|
|
#include <sys/cdefs.h> |
|
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
#ifndef WDCDEBUG |
#ifndef WDCDEBUG |
#define WDCDEBUG |
#define WDCDEBUG |
#endif /* WDCDEBUG */ |
#endif /* WDCDEBUG */ |
Line 115 int wdcdebug_wd_mask = 0; |
|
Line 117 int wdcdebug_wd_mask = 0; |
|
|
|
#define ATA_DELAY 10000 /* 10s for a drive I/O */ |
#define ATA_DELAY 10000 /* 10s for a drive I/O */ |
|
|
|
int wdc_ata_bio __P((struct ata_drive_datas*, struct ata_bio*)); |
void wdc_ata_bio_start __P((struct channel_softc *,struct wdc_xfer *)); |
void wdc_ata_bio_start __P((struct channel_softc *,struct wdc_xfer *)); |
void _wdc_ata_bio_start __P((struct channel_softc *,struct wdc_xfer *)); |
void _wdc_ata_bio_start __P((struct channel_softc *,struct wdc_xfer *)); |
int wdc_ata_bio_intr __P((struct channel_softc *, struct wdc_xfer *, int)); |
int wdc_ata_bio_intr __P((struct channel_softc *, struct wdc_xfer *, int)); |
Line 125 int wdc_ata_err __P((struct ata_drive_ |
|
Line 128 int wdc_ata_err __P((struct ata_drive_ |
|
#define WDC_ATA_NOERR 0x00 /* Drive doesn't report an error */ |
#define WDC_ATA_NOERR 0x00 /* Drive doesn't report an error */ |
#define WDC_ATA_RECOV 0x01 /* There was a recovered error */ |
#define WDC_ATA_RECOV 0x01 /* There was a recovered error */ |
#define WDC_ATA_ERR 0x02 /* Drive reports an error */ |
#define WDC_ATA_ERR 0x02 /* Drive reports an error */ |
|
int wdc_ata_addref __P((struct ata_drive_datas *)); |
|
void wdc_ata_delref __P((struct ata_drive_datas *)); |
|
void wdc_ata_kill_pending __P((struct ata_drive_datas *)); |
|
|
|
const struct ata_bustype wdc_ata_bustype = { |
|
SCSIPI_BUSTYPE_ATA, |
|
wdc_ata_bio, |
|
wdc_reset_channel, |
|
wdc_exec_command, |
|
ata_get_params, |
|
wdc_ata_addref, |
|
wdc_ata_delref, |
|
wdc_ata_kill_pending, |
|
}; |
|
|
|
|
|
/* |
|
* Convert a 32 bit command to a 48 bit command. |
|
*/ |
|
static __inline__ |
|
int to48(int cmd32) |
|
{ |
|
switch (cmd32) { |
|
case WDCC_READ: |
|
return WDCC_READ_EXT; |
|
case WDCC_WRITE: |
|
return WDCC_WRITE_EXT; |
|
case WDCC_READMULTI: |
|
return WDCC_READMULTI_EXT; |
|
case WDCC_WRITEMULTI: |
|
return WDCC_WRITEMULTI_EXT; |
|
case WDCC_READDMA: |
|
return WDCC_READDMA_EXT; |
|
case WDCC_WRITEDMA: |
|
return WDCC_WRITEDMA_EXT; |
|
default: |
|
panic("ata_wdc: illegal 32 bit command %d", cmd32); |
|
/*NOTREACHED*/ |
|
} |
|
} |
|
|
/* |
/* |
* Handle block I/O operation. Return WDC_COMPLETE, WDC_QUEUED, or |
* Handle block I/O operation. Return WDC_COMPLETE, WDC_QUEUED, or |
|
|
} |
} |
/* Transfer is okay now. */ |
/* Transfer is okay now. */ |
} |
} |
if (ata_bio->flags & ATA_LBA) { |
if (ata_bio->flags & ATA_LBA48) { |
|
sect = 0; |
|
cyl = 0; |
|
head = 0; |
|
} else if (ata_bio->flags & ATA_LBA) { |
sect = (ata_bio->blkno >> 0) & 0xff; |
sect = (ata_bio->blkno >> 0) & 0xff; |
cyl = (ata_bio->blkno >> 8) & 0xffff; |
cyl = (ata_bio->blkno >> 8) & 0xffff; |
head = (ata_bio->blkno >> 24) & 0x0f; |
head = (ata_bio->blkno >> 24) & 0x0f; |
|
|
WDSD_IBM | (xfer->drive << 4)); |
WDSD_IBM | (xfer->drive << 4)); |
if (wait_for_ready(chp, ata_delay) < 0) |
if (wait_for_ready(chp, ata_delay) < 0) |
goto timeout; |
goto timeout; |
wdccommand(chp, xfer->drive, cmd, cyl, |
if (ata_bio->flags & ATA_LBA48) { |
head, sect, nblks, 0); |
wdccommandext(chp, xfer->drive, to48(cmd), |
|
(u_int64_t)ata_bio->blkno, nblks); |
|
} else { |
|
wdccommand(chp, xfer->drive, cmd, cyl, |
|
head, sect, nblks, 0); |
|
} |
/* start the DMA channel */ |
/* start the DMA channel */ |
(*chp->wdc->dma_start)(chp->wdc->dma_arg, |
(*chp->wdc->dma_start)(chp->wdc->dma_arg, |
chp->channel, xfer->drive); |
chp->channel, xfer->drive); |
|
|
WDSD_IBM | (xfer->drive << 4)); |
WDSD_IBM | (xfer->drive << 4)); |
if (wait_for_ready(chp, ata_delay) < 0) |
if (wait_for_ready(chp, ata_delay) < 0) |
goto timeout; |
goto timeout; |
wdccommand(chp, xfer->drive, cmd, cyl, |
if (ata_bio->flags & ATA_LBA48) { |
head, sect, nblks, |
wdccommandext(chp, xfer->drive, to48(cmd), |
(ata_bio->lp->d_type == DTYPE_ST506) ? |
(u_int64_t) ata_bio->blkno, nblks); |
ata_bio->lp->d_precompcyl / 4 : 0); |
} else { |
|
wdccommand(chp, xfer->drive, cmd, cyl, |
|
head, sect, nblks, |
|
(ata_bio->lp->d_type == DTYPE_ST506) ? |
|
ata_bio->lp->d_precompcyl / 4 : 0); |
|
} |
} else if (ata_bio->nblks > 1) { |
} else if (ata_bio->nblks > 1) { |
/* The number of blocks in the last stretch may be smaller. */ |
/* The number of blocks in the last stretch may be smaller. */ |
nblks = xfer->c_bcount / ata_bio->lp->d_secsize; |
nblks = xfer->c_bcount / ata_bio->lp->d_secsize; |