| WDC(9) | Kernel Developer's Manual | WDC(9) | 
wdc —
#include <dev/ata/atavar.h>
#include <sys/dev/ic/wdcvar.h>
int
  
  wdcprobe(struct
    channel_softc * chp);
void
  
  wdcattach(struct
    channel_softc * chp);
wdc driver provides the machine independent core
  functions for driving IDE devices. IDE devices-specific drivers
  (wd(4) or
  atapibus(4)) will use services
  provided by wdc.
The machine-dependent bus front-end provides information to
    wdc with the wdc_softc and
    channel_softc structures. The first one defines global
    controller properties, and the second contains per-channel information.
    wdc returns information 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
#define WDC_CAPABILITY_PREATA 0x0200
#define WDC_CAPABILITY_IRQACK 0x0400
#define WDC_CAPABILITY_SINGLE_DRIVE 0x0800
#define WDC_CAPABILITY_NOIRQ  0x1000
#define WDC_CAPABILITY_SELECT  0x2000
        uint8_t      pio_mode;
        uint8_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
        uint8_t ch_status;
        uint8_t ch_error;
        struct ata_drive_datas ch_drive[2];
        struct channel_queue *ch_queue;
};
struct ata_drive_datas {
    uint8_t drive;
    uint8_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
    uint8_t PIO_mode;
    uint8_t DMA_mode;
    uint8_t UDMA_mode;
    uint8_t state;
    struct device *drv_softc;
    void* chnl_softc;
};
The bus front-end needs to fill in the following elements of wdc_softc:
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 big-endian 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.
WDC_CAPABILITY_NOIRQ tells the driver that
    this controller doesn't have its interrupt lines wired up usefully, so it
    should always use polled transfers.
The bus front-end needs to fill in the following elements of channel_softc:
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_flags handles the following flags:
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.
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.
| April 18, 2010 | NetBSD 9.4 |