wdc - machine-independent IDE/ATAPI driver
#include <dev/ata/atavar.h>
#include <sys/dev/ic/wdcvar.h>
int
wdcprobe(struct channel_softc * chp);
void
wdcattach(struct channel_softc * chp);
The wdc driver provides the machine independent core functions for driving
IDE devices. IDE devices-specific drivers ( wd or atapibus) will use
services provided by wdc.
The machine-dependent bus front-end provides informations to wdc with the
wdc_softc and channel_softc structures. The first one defines global
controller properties, and the second contains per-channel informations.
wdc returns informations about the attached devices in the
ata_drive_datas structure.
struct wdc_softc { /* Per controller state */
struct device sc_dev;
int cap;
#define WDC_CAPABILITY_DATA16 0x0001
#define WDC_CAPABILITY_DATA32 0x0002
#define WDC_CAPABILITY_MODE 0x0004
#define WDC_CAPABILITY_DMA 0x0008
#define WDC_CAPABILITY_UDMA 0x0010
#define WDC_CAPABILITY_HWLOCK 0x0020
#define WDC_CAPABILITY_ATA_NOSTREAM 0x0040
#define WDC_CAPABILITY_ATAPI_NOSTREAM 0x0080
#define WDC_CAPABILITY_NO_EXTRA_RESETS 0x0100
u_int8_t pio_mode;
u_int8_t dma_mode;
int nchannels;
struct channel_softc *channels;
void *dma_arg;
int (*dma_init)(void *, int, int, void *, size_t, int);
void (*dma_start)(void *, int, int, int);
int (*dma_finish)(void *, int, int, int);
#define WDC_DMA_READ 0x01
#define WDC_DMA_POLL 0x02
int (*claim_hw)(void *, int);
void (*free_hw)(void *);
};
struct channel_softc { /* Per channel data */
int channel;
struct wdc_softc *wdc;
bus_space_tag_t cmd_iot;
bus_space_handle_t cmd_ioh;
bus_space_tag_t ctl_iot;
bus_space_handle_t ctl_ioh;
bus_space_tag_t data32iot;
bus_space_handle_t data32ioh;
int ch_flags;
#define WDCF_ACTIVE 0x01
#define WDCF_IRQ_WAIT 0x10
u_int8_t ch_status;
u_int8_t ch_error;
struct ata_drive_datas ch_drive[2];
struct channel_queue *ch_queue;
};
struct ata_drive_datas {
u_int8_t drive;
u_int8_t drive_flags;
#define DRIVE_ATA 0x01
#define DRIVE_ATAPI 0x02
#define DRIVE (DRIVE_ATA|DRIVE_ATAPI)
#define DRIVE_CAP32 0x04
#define DRIVE_DMA 0x08
#define DRIVE_UDMA 0x10
#define DRIVE_MODE 0x20
u_int8_t PIO_mode;
u_int8_t DMA_mode;
u_int8_t UDMA_mode;
u_int8_t state;
struct device *drv_softc;
void* chnl_softc;
};
The bus front-end needs to fill in the following elements of wdc_softc:
cap supports one or more of the WDC_CAPABILITY flags
nchannels number of channels supported by this controller
channels array of struct channel_softc of size nchannels properly
initialised
The following elements are optional:
pio_mode
dma_mode
dma_arg
dma_init
dma_start
dma_finish
claim_hw
free_hw
The WDC_CAPABILITY_DATA16 and WDC_CAPABILITY_DATA32 flags informs wdc
whether the controller supports 16- or 32-bit I/O accesses on the data
port. If both are set, a test will be done for each drive using the ATA
or ATAPI IDENTIFY command, to automatically select the working mode.
The WDC_CAPABILITY_DMA and WDC_CAPABILITY_UDMA flags are set for controllers
supporting the DMA and Ultra-DMA modes. The bus front-end needs
to provide the dma_init(), dma_start() and dma_finish() functions.
dma_init() is called just before issuing a DMA command to the IDE device.
The arguments are, respectively: dma_arg, the channel number, the drive
number on this channel, the virtual address of the DMA buffer, the size
of the transfer, and the WDC_DMA flags. dma_start() is called just after
issuing a DMA command to the IDE device. The arguments are, respectively:
dma_arg, the channel number, the drive number on this channel,
and the WDC_DMA flags. dma_finish() is called once the transfer is complete.
The arguments are, respectively: dma_arg, the channel number, the
drive number on this channel, and the WDC_DMA flags. WDC_DMA_READ indicates
the direction of the data transfer, and WDC_DMA_POLL indicates if
the transfer will use (or used) interrupts.
The WDC_CAPABILITY_MODE flag means that the bus front-end can program the
PIO and DMA modes, so wdc needs to provide back the supported modes for
each drive, and set the drives modes. The pio_mode and dma_mode needs to
be set to the highest PIO and DMA mode supported. If WDC_CAPABILITY_UDMA
is set, then dma_mode must be set to the highest Ultra-DMA mode supported.
If WDC_CAPABILITY_MODE is not set, wdc will not attempt to
change the current drive's settings, assuming the host's firmware has
done it right.
The WDC_CAPABILITY_HWLOCK flag is set for controllers needing hardware
looking before accessing the I/O ports. If this flag is set, the bus
front-end needs to provide the claim_hw() and free_hw() functions.
claim_hw() will be called when the driver wants to access the controller
ports. The second parameter is set to 1 when it is possible to sleep
waiting for the lock, 0 otherwise. It should return 1 when access has
been granted, 0 otherwise. When access has not been granted and sleep is
not allowed, the bus front-end shall call wdcrestart() with the first
argument passed to claim_hw() as argument. This arguments will also be
the one passed to free_hw(). This function is called once the transfer
is complete, so that the lock can be released.
Accesses to the data port are done by using the bus_space stream functions,
unless the WDC_CAPABILITY_ATA_NOSTREAM or
WDC_CAPABILITY_ATAPI_NOSTREAM flags are set. This should not be used,
unless the data bus is not wired properly (which seems common on bigendian
systems), and byte-order needs to be preserved for compatibility
with the host's firmware. Also note that the IDE bus is a little-endian
bus, so the bus_space functions used for the bus_space tag passed in the
channel_softc have to do the appropriate byte-swapping for big-endian
systems.
WDC_CAPABILITY_NO_EXTRA_RESETS avoid the controller reset at the end of
the disks probe. This reset is needed for some controllers, but causes
problems with some others.
The bus front-end needs to fill in the following elements of
channel_softc:
channel The channel number on the controller
wdc A pointer to the controller's wdc_softc
cmd_iot, cmd_ioh
Bus-space tag and handle for access to the command block
registers (which includes the 16-bit data port)
ctl_iot, ctl_ioh
Bus-space tag and handle for access to the control block
registers
ch_queue A pointer to a struct channel_queue. This will hold the
queues of outstanding commands for this controller.
The following elements are optional:
data32iot, data32ioh
Bus-space tag and handle for 32-bit data accesses. Only
needed if WDC_CAPABILITY_DATA32 is set in the controller's
wdc_softc.
ch_queue can point to a common struct channel_queue if the controller
doesn't support concurrent access to its different channels. If all
channels are independent, it is recommended that each channel has its own
ch_queue (for better performance).
The bus-specific front-end can use the wdcprobe() function, with a properly
initialised struct channel_softc as argument ( wdc can be set to
NULL. This allows wdcprobe() to be easily used in bus front-end probe
functions). This function will return an integer where bit 0 will be set
if the master device has been found, and 1 if the slave device has been
found.
The bus-specific attach function has to call wdcattach() for each channel,
with a pointer to a properly initialised channel softc as argument.
This will probe devices attached to the IDE channel and attach them.
Once this function returns, the ch_drive array of the channel_softc will
contain the drive's capabilities. This can be used to properly initialise
the controller's mode, or disable a channel without drives.
The elements of interest in ata_drive_datas for a bus front-end are:
drive The drive number
drive_flags
Flags indicating the drive capabilities. A null
drive_flags indicate either that no drive is here, or
that no driver was found for this device.
PIO_mode, DMA_mode, UDMA_mode
the highest supported modes for this drive compatible
with the controller's capabilities. Needs to be reset to
the mode to use by the drive, if known.
drv_softc A pointer to the drive's softc. Can be used to print the
drive's name.
drive_flags handles the following flags:
DRIVE_ATA, DRIVE_ATAPI
Gives the drive type, if any. The shortcut DRIVE can be
used to just test the presence/absence of a drive.
DRIVE_CAP32
This drive works with 32-bit data I/O.
DRIVE_DMA This drive supports DMA.
DRIVE_UDMA This drive supports Ultra-DMA.
DRIVE_MODE This drive properly reported its PIO and DMA mode.
Once the controller has been initialised, it has to reset the DRIVE_DMA
and DRIVE_UDMA, as well as the values of PIO_mode, DMA_mode and UDMA_mode
if the modes to be used are not highest ones supported by the drive.
wdc(4), bus_space(9)
The wdc core functions are implemented in sys/dev/ic/wdc.c. Low-level
ATA and ATAPI support is provided by sys/dev/ata_wdc.c and
sys/dev/scsipi/atapi_wdc.c respectively.
An example of a simple bus front-end can be found in
sys/dev/isapnp/wdc_isapnp.c. A more complex one, with multiple channels
and bus-master DMA support is sys/dev/pci/pciide.c.
sys/arch/atari/dev/wdc_mb.c makes use of hardware locking, and also provides
an example of bus-front end for a big-endian system, which needs
byte-swapping bus_space functions.
BSD October 18, 1998 BSD
[ Back ] |