Updated: 2022/Sep/29

Please read Privacy Policy. It's for your privacy.


WDC(9)                     Kernel Developer's Manual                    WDC(9)

NAME
     wdc - machine-independent IDE/ATAPI driver

SYNOPSIS
     #include <dev/ata/atavar.h>
     #include <sys/dev/ic/wdcvar.h>

     int
     wdcprobe(struct channel_softc * chp);

     void
     wdcattach(struct channel_softc * chp);

DESCRIPTION
     The 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:
         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 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:
         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.

CODE REFERENCES
     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.

SEE ALSO
     wdc(4), bus_space(9)

NetBSD 10.99                    April 18, 2010                    NetBSD 10.99