[BACK]Return to atapi_wdc.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / scsipi

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/dev/scsipi/atapi_wdc.c between version 1.55 and 1.55.6.7

version 1.55, 2002/09/27 15:37:33 version 1.55.6.7, 2005/11/10 14:07:47
Line 14 
Line 14 
  * 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 Manuel Bouyer.   *      This product includes software developed by Manuel Bouyer.
  * 4. Neither the name of the University nor the names of its contributors   * 4. The name of the author may not be used to endorse or promote products
  *    may be used to endorse or promote products derived from this software   *    derived from this software without specific prior written permission.
  *    without specific prior written permission.  
  *   *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  
  */   */
   
 #include <sys/cdefs.h>  #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD$");  __KERNEL_RCSID(0, "$NetBSD$");
   
 #ifndef WDCDEBUG  #ifndef ATADEBUG
 #define WDCDEBUG  #define ATADEBUG
 #endif /* WDCDEBUG */  #endif /* ATADEBUG */
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/systm.h>  #include <sys/systm.h>
Line 54  __KERNEL_RCSID(0, "$NetBSD$");
Line 52  __KERNEL_RCSID(0, "$NetBSD$");
 #include <machine/bus.h>  #include <machine/bus.h>
   
 #ifndef __BUS_SPACE_HAS_STREAM_METHODS  #ifndef __BUS_SPACE_HAS_STREAM_METHODS
 #define    bus_space_write_multi_stream_2    bus_space_write_multi_2  #define bus_space_write_multi_stream_2  bus_space_write_multi_2
 #define    bus_space_write_multi_stream_4    bus_space_write_multi_4  #define bus_space_write_multi_stream_4  bus_space_write_multi_4
 #define    bus_space_read_multi_stream_2    bus_space_read_multi_2  #define bus_space_read_multi_stream_2   bus_space_read_multi_2
 #define    bus_space_read_multi_stream_4    bus_space_read_multi_4  #define bus_space_read_multi_stream_4   bus_space_read_multi_4
 #endif /* __BUS_SPACE_HAS_STREAM_METHODS */  #endif /* __BUS_SPACE_HAS_STREAM_METHODS */
   
 #include <dev/ata/atareg.h>  #include <dev/ata/atareg.h>
Line 72  __KERNEL_RCSID(0, "$NetBSD$");
Line 70  __KERNEL_RCSID(0, "$NetBSD$");
 #define DEBUG_STATUS 0x04  #define DEBUG_STATUS 0x04
 #define DEBUG_FUNCS  0x08  #define DEBUG_FUNCS  0x08
 #define DEBUG_PROBE  0x10  #define DEBUG_PROBE  0x10
 #ifdef WDCDEBUG  #ifdef ATADEBUG
 int wdcdebug_atapi_mask = 0;  int wdcdebug_atapi_mask = 0;
 #define WDCDEBUG_PRINT(args, level) \  #define ATADEBUG_PRINT(args, level) \
         if (wdcdebug_atapi_mask & (level)) \          if (wdcdebug_atapi_mask & (level)) \
                 printf args                  printf args
 #else  #else
 #define WDCDEBUG_PRINT(args, level)  #define ATADEBUG_PRINT(args, level)
 #endif  #endif
   
 #define ATAPI_DELAY 10  /* 10 ms, this is used only before sending a cmd */  #define ATAPI_DELAY 10  /* 10 ms, this is used only before sending a cmd */
 int   wdc_atapi_get_params __P((struct scsipi_channel *, int, int,  #define ATAPI_MODE_DELAY 1000   /* 1s, timeout for SET_FEATYRE cmds */
                                 struct ataparams *));  
 void  wdc_atapi_probe_device __P((struct atapibus_softc *, int));  static int      wdc_atapi_get_params(struct scsipi_channel *, int,
 void  wdc_atapi_minphys  __P((struct buf *bp));                                       struct ataparams *);
 void  wdc_atapi_start   __P((struct channel_softc *,struct wdc_xfer *));  static void     wdc_atapi_probe_device(struct atapibus_softc *, int);
 int   wdc_atapi_intr     __P((struct channel_softc *, struct wdc_xfer *, int));  static void     wdc_atapi_minphys (struct buf *bp);
 void  wdc_atapi_kill_xfer __P((struct channel_softc *, struct wdc_xfer *));  static void     wdc_atapi_start(struct ata_channel *,struct ata_xfer *);
 int   wdc_atapi_ctrl     __P((struct channel_softc *, struct wdc_xfer *, int));  static int      wdc_atapi_intr(struct ata_channel *, struct ata_xfer *, int);
 void  wdc_atapi_phase_complete __P((struct wdc_xfer *));  static void     wdc_atapi_kill_xfer(struct ata_channel *,
 void  wdc_atapi_done     __P((struct channel_softc *, struct wdc_xfer *));                                      struct ata_xfer *, int);
 void  wdc_atapi_reset    __P((struct channel_softc *, struct wdc_xfer *));  static void     wdc_atapi_phase_complete(struct ata_xfer *);
 void  wdc_atapi_scsipi_request __P((struct scsipi_channel *,  static void     wdc_atapi_done(struct ata_channel *, struct ata_xfer *);
         scsipi_adapter_req_t, void *));  static void     wdc_atapi_reset(struct ata_channel *, struct ata_xfer *);
 void  wdc_atapi_kill_pending __P((struct scsipi_periph *));  static void     wdc_atapi_scsipi_request(struct scsipi_channel *,
 void  wdc_atapi_polldsc __P((void *arg));                                           scsipi_adapter_req_t, void *);
   static void     wdc_atapi_kill_pending(struct scsipi_periph *);
   static void     wdc_atapi_polldsc(void *arg);
   
 #define MAX_SIZE MAXPHYS  #define MAX_SIZE MAXPHYS
   
 const struct scsipi_bustype wdc_atapi_bustype = {  static const struct scsipi_bustype wdc_atapi_bustype = {
         SCSIPI_BUSTYPE_ATAPI,          SCSIPI_BUSTYPE_ATAPI,
         atapi_scsipi_cmd,          atapi_scsipi_cmd,
         atapi_interpret_sense,          atapi_interpret_sense,
Line 109  const struct scsipi_bustype wdc_atapi_bu
Line 109  const struct scsipi_bustype wdc_atapi_bu
 };  };
   
 void  void
 wdc_atapibus_attach(chp)  wdc_atapibus_attach(struct atabus_softc *ata_sc)
         struct channel_softc *chp;  
 {  {
         struct wdc_softc *wdc = chp->wdc;          struct ata_channel *chp = ata_sc->sc_chan;
         struct scsipi_adapter *adapt = &wdc->sc_atapi_adapter._generic;          struct atac_softc *atac = chp->ch_atac;
           struct scsipi_adapter *adapt = &atac->atac_atapi_adapter._generic;
         struct scsipi_channel *chan = &chp->ch_atapi_channel;          struct scsipi_channel *chan = &chp->ch_atapi_channel;
   
         /*          /*
          * Fill in the scsipi_adapter.           * Fill in the scsipi_adapter.
          */           */
         adapt->adapt_dev = &wdc->sc_dev;          adapt->adapt_dev = &atac->atac_dev;
         adapt->adapt_nchannels = wdc->nchannels;          adapt->adapt_nchannels = atac->atac_nchannels;
         adapt->adapt_request = wdc_atapi_scsipi_request;          adapt->adapt_request = wdc_atapi_scsipi_request;
         adapt->adapt_minphys = wdc_atapi_minphys;          adapt->adapt_minphys = wdc_atapi_minphys;
         if (wdc->cap & WDC_CAPABILITY_NOIRQ)          if (atac->atac_cap & ATAC_CAP_NOIRQ)
                 adapt->adapt_flags |= SCSIPI_ADAPT_POLL_ONLY;                  adapt->adapt_flags |= SCSIPI_ADAPT_POLL_ONLY;
         wdc->sc_atapi_adapter.atapi_probe_device = wdc_atapi_probe_device;          atac->atac_atapi_adapter.atapi_probe_device = wdc_atapi_probe_device;
   
         /*          /*
          * Fill in the scsipi_channel.           * Fill in the scsipi_channel.
Line 133  wdc_atapibus_attach(chp)
Line 133  wdc_atapibus_attach(chp)
         memset(chan, 0, sizeof(*chan));          memset(chan, 0, sizeof(*chan));
         chan->chan_adapter = adapt;          chan->chan_adapter = adapt;
         chan->chan_bustype = &wdc_atapi_bustype;          chan->chan_bustype = &wdc_atapi_bustype;
         chan->chan_channel = chp->channel;          chan->chan_channel = chp->ch_channel;
         chan->chan_flags = SCSIPI_CHAN_OPENINGS;          chan->chan_flags = SCSIPI_CHAN_OPENINGS;
         chan->chan_openings = 1;          chan->chan_openings = 1;
         chan->chan_max_periph = 1;          chan->chan_max_periph = 1;
         chan->chan_ntargets = 2;          chan->chan_ntargets = 2;
         chan->chan_nluns = 1;          chan->chan_nluns = 1;
   
         chp->atapibus = config_found(&wdc->sc_dev, chan, atapiprint);          chp->atapibus = config_found_ia(&ata_sc->sc_dev, "atapi", chan,
                   atapiprint);
 }  }
   
 void  static void
 wdc_atapi_minphys(bp)  wdc_atapi_minphys(struct buf *bp)
         struct buf *bp;  
 {  {
   
         if (bp->b_bcount > MAX_SIZE)          if (bp->b_bcount > MAX_SIZE)
Line 158  wdc_atapi_minphys(bp)
Line 158  wdc_atapi_minphys(bp)
  *   *
  * Must be called at splbio().   * Must be called at splbio().
  */   */
 void  static void
 wdc_atapi_kill_pending(periph)  wdc_atapi_kill_pending(struct scsipi_periph *periph)
         struct scsipi_periph *periph;  
 {  {
         struct wdc_softc *wdc =          struct atac_softc *atac =
             (void *)periph->periph_channel->chan_adapter->adapt_dev;              (void *)periph->periph_channel->chan_adapter->adapt_dev;
         struct channel_softc *chp =          struct ata_channel *chp =
             wdc->channels[periph->periph_channel->chan_channel];              atac->atac_channels[periph->periph_channel->chan_channel];
   
         wdc_kill_pending(chp);          ata_kill_pending(&chp->ch_drive[periph->periph_target]);
 }  }
   
 void  static void
 wdc_atapi_kill_xfer(chp, xfer)  wdc_atapi_kill_xfer(struct ata_channel *chp, struct ata_xfer *xfer, int reason)
         struct channel_softc *chp;  
         struct wdc_xfer *xfer;  
 {  {
         struct scsipi_xfer *sc_xfer = xfer->cmd;          struct scsipi_xfer *sc_xfer = xfer->c_cmd;
   
         callout_stop(&chp->ch_callout);  
         /* remove this command from xfer queue */          /* remove this command from xfer queue */
         wdc_free_xfer(chp, xfer);          switch (reason) {
         sc_xfer->error = XS_DRIVER_STUFFUP;          case KILL_GONE:
                   sc_xfer->error = XS_DRIVER_STUFFUP;
                   break;
           case KILL_RESET:
                   sc_xfer->error = XS_RESET;
                   break;
           default:
                   printf("wdc_ata_bio_kill_xfer: unknown reason %d\n",
                       reason);
                   panic("wdc_ata_bio_kill_xfer");
           }
           ata_free_xfer(chp, xfer);
         scsipi_done(sc_xfer);          scsipi_done(sc_xfer);
 }  }
   
 int  static int
 wdc_atapi_get_params(chan, drive, flags, id)  wdc_atapi_get_params(struct scsipi_channel *chan, int drive,
         struct scsipi_channel *chan;      struct ataparams *id)
         int drive, flags;  
         struct ataparams *id;  
 {  {
         struct wdc_softc *wdc = (void *)chan->chan_adapter->adapt_dev;          struct wdc_softc *wdc = (void *)chan->chan_adapter->adapt_dev;
         struct channel_softc *chp = wdc->channels[chan->chan_channel];          struct atac_softc *atac = &wdc->sc_atac;
         struct wdc_command wdc_c;          struct wdc_regs *wdr = &wdc->regs[chan->chan_channel];
           struct ata_channel *chp = atac->atac_channels[chan->chan_channel];
           struct ata_command ata_c;
   
         /* if no ATAPI device detected at wdc attach time, skip */          /* if no ATAPI device detected at wdc attach time, skip */
         /*  
          * XXX this will break scsireprobe if this is of any interest for  
          * ATAPI devices one day.  
          */  
         if ((chp->ch_drive[drive].drive_flags & DRIVE_ATAPI) == 0) {          if ((chp->ch_drive[drive].drive_flags & DRIVE_ATAPI) == 0) {
                 WDCDEBUG_PRINT(("wdc_atapi_get_params: drive %d not present\n",                  ATADEBUG_PRINT(("wdc_atapi_get_params: drive %d not present\n",
                     drive), DEBUG_PROBE);                      drive), DEBUG_PROBE);
                 return -1;                  return -1;
         }          }
         memset(&wdc_c, 0, sizeof(struct wdc_command));  
         wdc_c.r_command = ATAPI_SOFT_RESET;          memset(&ata_c, 0, sizeof(struct ata_command));
         wdc_c.r_st_bmask = 0;          ata_c.r_command = ATAPI_SOFT_RESET;
         wdc_c.r_st_pmask = 0;          ata_c.r_st_bmask = 0;
         wdc_c.flags = AT_POLL;          ata_c.r_st_pmask = 0;
         wdc_c.timeout = WDC_RESET_WAIT;          ata_c.flags = AT_WAIT | AT_POLL;
         if (wdc_exec_command(&chp->ch_drive[drive], &wdc_c) != WDC_COMPLETE) {          ata_c.timeout = WDC_RESET_WAIT;
           if (wdc_exec_command(&chp->ch_drive[drive], &ata_c) != ATACMD_COMPLETE) {
                 printf("wdc_atapi_get_params: ATAPI_SOFT_RESET failed for"                  printf("wdc_atapi_get_params: ATAPI_SOFT_RESET failed for"
                     " drive %s:%d:%d: driver failed\n",                      " drive %s:%d:%d: driver failed\n",
                     chp->wdc->sc_dev.dv_xname, chp->channel, drive);                      atac->atac_dev.dv_xname, chp->ch_channel, drive);
                 panic("wdc_atapi_get_params");                  panic("wdc_atapi_get_params");
         }          }
         if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {          if (ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
                 WDCDEBUG_PRINT(("wdc_atapi_get_params: ATAPI_SOFT_RESET "                  ATADEBUG_PRINT(("wdc_atapi_get_params: ATAPI_SOFT_RESET "
                     "failed for drive %s:%d:%d: error 0x%x\n",                      "failed for drive %s:%d:%d: error 0x%x\n",
                     chp->wdc->sc_dev.dv_xname, chp->channel, drive,                      atac->atac_dev.dv_xname, chp->ch_channel, drive,
                     wdc_c.r_error), DEBUG_PROBE);                      ata_c.r_error), DEBUG_PROBE);
                 return -1;                  return -1;
         }          }
         chp->ch_drive[drive].state = 0;          chp->ch_drive[drive].state = 0;
   
         bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status);          bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_status], 0);
   
         /* Some ATAPI devices need a bit more time after software reset. */          /* Some ATAPI devices need a bit more time after software reset. */
         delay(5000);          delay(5000);
         if (ata_get_params(&chp->ch_drive[drive], AT_POLL, id) != 0) {          if (ata_get_params(&chp->ch_drive[drive], AT_WAIT, id) != 0) {
                 WDCDEBUG_PRINT(("wdc_atapi_get_params: ATAPI_IDENTIFY_DEVICE "                  ATADEBUG_PRINT(("wdc_atapi_get_params: ATAPI_IDENTIFY_DEVICE "
                     "failed for drive %s:%d:%d: error 0x%x\n",                      "failed for drive %s:%d:%d: error 0x%x\n",
                     chp->wdc->sc_dev.dv_xname, chp->channel, drive,                      atac->atac_dev.dv_xname, chp->ch_channel, drive,
                     wdc_c.r_error), DEBUG_PROBE);                      ata_c.r_error), DEBUG_PROBE);
                 return -1;                  return -1;
         }          }
         return 0;          return 0;
 }  }
   
 void  static void
 wdc_atapi_probe_device(sc, target)  wdc_atapi_probe_device(struct atapibus_softc *sc, int target)
         struct atapibus_softc *sc;  
         int target;  
 {  {
         struct scsipi_channel *chan = sc->sc_channel;          struct scsipi_channel *chan = sc->sc_channel;
         struct scsipi_periph *periph;          struct scsipi_periph *periph;
         struct ataparams ids;          struct ataparams ids;
         struct ataparams *id = &ids;          struct ataparams *id = &ids;
         struct wdc_softc *wdc = (void *)chan->chan_adapter->adapt_dev;          struct wdc_softc *wdc = (void *)chan->chan_adapter->adapt_dev;
         struct channel_softc *chp = wdc->channels[chan->chan_channel];          struct atac_softc *atac = &wdc->sc_atac;
           struct ata_channel *chp = atac->atac_channels[chan->chan_channel];
         struct ata_drive_datas *drvp = &chp->ch_drive[target];          struct ata_drive_datas *drvp = &chp->ch_drive[target];
         struct scsipibus_attach_args sa;          struct scsipibus_attach_args sa;
         char serial_number[21], model[41], firmware_revision[9];          char serial_number[21], model[41], firmware_revision[9];
           int s;
   
         /* skip if already attached */          /* skip if already attached */
         if (scsipi_lookup_periph(chan, target, 0) != NULL)          if (scsipi_lookup_periph(chan, target, 0) != NULL)
                 return;                  return;
   
         if (wdc_atapi_get_params(chan, target,          if (wdc_atapi_get_params(chan, target, id) == 0) {
             XS_CTL_POLL|XS_CTL_NOSLEEP, id) == 0) {  
 #ifdef ATAPI_DEBUG_PROBE  #ifdef ATAPI_DEBUG_PROBE
                 printf("%s drive %d: cmdsz 0x%x drqtype 0x%x\n",                  printf("%s drive %d: cmdsz 0x%x drqtype 0x%x\n",
                     sc->sc_dev.dv_xname, target,                      sc->sc_dev.dv_xname, target,
Line 277  wdc_atapi_probe_device(sc, target)
Line 280  wdc_atapi_probe_device(sc, target)
                 periph->periph_switch = &atapi_probe_periphsw;                  periph->periph_switch = &atapi_probe_periphsw;
                 periph->periph_target = target;                  periph->periph_target = target;
                 periph->periph_lun = 0;                  periph->periph_lun = 0;
                   periph->periph_quirks = PQUIRK_ONLYBIG;
   
 #ifdef SCSIPI_DEBUG  #ifdef SCSIPI_DEBUG
                 if (SCSIPI_DEBUG_TYPE == SCSIPI_BUSTYPE_ATAPI &&                  if (SCSIPI_DEBUG_TYPE == SCSIPI_BUSTYPE_ATAPI &&
Line 286  wdc_atapi_probe_device(sc, target)
Line 290  wdc_atapi_probe_device(sc, target)
                 periph->periph_type = ATAPI_CFG_TYPE(id->atap_config);                  periph->periph_type = ATAPI_CFG_TYPE(id->atap_config);
                 if (id->atap_config & ATAPI_CFG_REMOV)                  if (id->atap_config & ATAPI_CFG_REMOV)
                         periph->periph_flags |= PERIPH_REMOVABLE;                          periph->periph_flags |= PERIPH_REMOVABLE;
                 if (periph->periph_type == T_SEQUENTIAL)                  if (periph->periph_type == T_SEQUENTIAL) {
                           s = splbio();
                         drvp->drive_flags |= DRIVE_ATAPIST;                          drvp->drive_flags |= DRIVE_ATAPIST;
                           splx(s);
                   }
   
                 sa.sa_periph = periph;                  sa.sa_periph = periph;
                 sa.sa_inqbuf.type =  ATAPI_CFG_TYPE(id->atap_config);                  sa.sa_inqbuf.type =  ATAPI_CFG_TYPE(id->atap_config);
Line 311  wdc_atapi_probe_device(sc, target)
Line 318  wdc_atapi_probe_device(sc, target)
                 drvp->drv_softc = atapi_probe_device(sc, target, periph, &sa);                  drvp->drv_softc = atapi_probe_device(sc, target, periph, &sa);
   
                 if (drvp->drv_softc)                  if (drvp->drv_softc)
                         wdc_probe_caps(drvp);                          ata_probe_caps(drvp);
                   else {
                           s = splbio();
                           drvp->drive_flags &= ~DRIVE_ATAPI;
                           splx(s);
                   }
           } else {
                   s = splbio();
                   drvp->drive_flags &= ~DRIVE_ATAPI;
                   splx(s);
         }          }
 }  }
   
 void  static void
 wdc_atapi_scsipi_request(chan, req, arg)  wdc_atapi_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
         struct scsipi_channel *chan;      void *arg)
         scsipi_adapter_req_t req;  
         void *arg;  
 {  {
         struct scsipi_adapter *adapt = chan->chan_adapter;          struct scsipi_adapter *adapt = chan->chan_adapter;
         struct scsipi_periph *periph;          struct scsipi_periph *periph;
         struct scsipi_xfer *sc_xfer;          struct scsipi_xfer *sc_xfer;
         struct wdc_softc *wdc = (void *)adapt->adapt_dev;          struct wdc_softc *wdc = (void *)adapt->adapt_dev;
         struct wdc_xfer *xfer;          struct atac_softc *atac = &wdc->sc_atac;
           struct ata_xfer *xfer;
         int channel = chan->chan_channel;          int channel = chan->chan_channel;
         int drive, s;          int drive, s;
   
Line 335  wdc_atapi_scsipi_request(chan, req, arg)
Line 350  wdc_atapi_scsipi_request(chan, req, arg)
                 periph = sc_xfer->xs_periph;                  periph = sc_xfer->xs_periph;
                 drive = periph->periph_target;                  drive = periph->periph_target;
   
                 WDCDEBUG_PRINT(("wdc_atapi_scsipi_request %s:%d:%d\n",                  ATADEBUG_PRINT(("wdc_atapi_scsipi_request %s:%d:%d\n",
                     wdc->sc_dev.dv_xname, channel, drive), DEBUG_XFERS);                      atac->atac_dev.dv_xname, channel, drive), DEBUG_XFERS);
                 if ((wdc->sc_dev.dv_flags & DVF_ACTIVE) == 0) {                  if ((atac->atac_dev.dv_flags & DVF_ACTIVE) == 0) {
                         sc_xfer->error = XS_DRIVER_STUFFUP;                          sc_xfer->error = XS_DRIVER_STUFFUP;
                         scsipi_done(sc_xfer);                          scsipi_done(sc_xfer);
                         return;                          return;
                 }                  }
   
                 xfer = wdc_get_xfer(WDC_NOSLEEP);                  xfer = ata_get_xfer(ATAXF_NOSLEEP);
                 if (xfer == NULL) {                  if (xfer == NULL) {
                         sc_xfer->error = XS_RESOURCE_SHORTAGE;                          sc_xfer->error = XS_RESOURCE_SHORTAGE;
                         scsipi_done(sc_xfer);                          scsipi_done(sc_xfer);
Line 352  wdc_atapi_scsipi_request(chan, req, arg)
Line 367  wdc_atapi_scsipi_request(chan, req, arg)
   
                 if (sc_xfer->xs_control & XS_CTL_POLL)                  if (sc_xfer->xs_control & XS_CTL_POLL)
                         xfer->c_flags |= C_POLL;                          xfer->c_flags |= C_POLL;
                 xfer->drive = drive;                  if ((atac->atac_channels[channel]->ch_drive[drive].drive_flags &
                       (DRIVE_DMA | DRIVE_UDMA)) && sc_xfer->datalen > 0)
                           xfer->c_flags |= C_DMA;
                   xfer->c_drive = drive;
                 xfer->c_flags |= C_ATAPI;                  xfer->c_flags |= C_ATAPI;
                 if (sc_xfer->cmd->opcode == GPCMD_REPORT_KEY ||                  if (sc_xfer->cmd->opcode == GPCMD_REPORT_KEY ||
                     sc_xfer->cmd->opcode == GPCMD_SEND_KEY ||                      sc_xfer->cmd->opcode == GPCMD_SEND_KEY ||
Line 361  wdc_atapi_scsipi_request(chan, req, arg)
Line 379  wdc_atapi_scsipi_request(chan, req, arg)
                          * DVD authentication commands must always be done in                           * DVD authentication commands must always be done in
                          * PIO mode.                           * PIO mode.
                          */                           */
                         xfer->c_flags |= C_FORCEPIO;                          xfer->c_flags &= ~C_DMA;
                 }                  }
                 /*                  /*
                  * DMA can't deal with transfers which are not a multiple of                   * DMA can't deal with transfers which are not a multiple of
Line 372  wdc_atapi_scsipi_request(chan, req, arg)
Line 390  wdc_atapi_scsipi_request(chan, req, arg)
                  * 4 bytes.                   * 4 bytes.
                  */                   */
                 if (sc_xfer->datalen < 4 || (sc_xfer->datalen & 0x01))                  if (sc_xfer->datalen < 4 || (sc_xfer->datalen & 0x01))
                         xfer->c_flags |= C_FORCEPIO;                          xfer->c_flags &= ~C_DMA;
   
                 xfer->cmd = sc_xfer;                  xfer->c_cmd = sc_xfer;
                 xfer->databuf = sc_xfer->data;                  xfer->c_databuf = sc_xfer->data;
                 xfer->c_bcount = sc_xfer->datalen;                  xfer->c_bcount = sc_xfer->datalen;
                 xfer->c_start = wdc_atapi_start;                  xfer->c_start = wdc_atapi_start;
                 xfer->c_intr = wdc_atapi_intr;                  xfer->c_intr = wdc_atapi_intr;
                 xfer->c_kill_xfer = wdc_atapi_kill_xfer;                  xfer->c_kill_xfer = wdc_atapi_kill_xfer;
                 xfer->c_dscpoll = 0;                  xfer->c_dscpoll = 0;
                 s = splbio();                  s = splbio();
                 wdc_exec_xfer(wdc->channels[channel], xfer);                  ata_exec_xfer(atac->atac_channels[channel], xfer);
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
                 if ((sc_xfer->xs_control & XS_CTL_POLL) != 0 &&                  if ((sc_xfer->xs_control & XS_CTL_POLL) != 0 &&
                     (sc_xfer->xs_status & XS_STS_DONE) == 0)                      (sc_xfer->xs_status & XS_STS_DONE) == 0)
Line 398  wdc_atapi_scsipi_request(chan, req, arg)
Line 416  wdc_atapi_scsipi_request(chan, req, arg)
         }          }
 }  }
   
 void  static void
 wdc_atapi_start(chp, xfer)  wdc_atapi_start(struct ata_channel *chp, struct ata_xfer *xfer)
         struct channel_softc *chp;  
         struct wdc_xfer *xfer;  
 {  {
         struct scsipi_xfer *sc_xfer = xfer->cmd;          struct atac_softc *atac = chp->ch_atac;
         struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];          struct wdc_softc *wdc = CHAN_TO_WDC(chp);
           struct wdc_regs *wdr = &wdc->regs[chp->ch_channel];
           struct scsipi_xfer *sc_xfer = xfer->c_cmd;
           struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
           int wait_flags = (sc_xfer->xs_control & XS_CTL_POLL) ? AT_POLL : 0;
           const char *errstring;
   
         WDCDEBUG_PRINT(("wdc_atapi_start %s:%d:%d, scsi flags 0x%x \n",          ATADEBUG_PRINT(("wdc_atapi_start %s:%d:%d, scsi flags 0x%x \n",
             chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive,              atac->atac_dev.dv_xname, chp->ch_channel, drvp->drive,
             sc_xfer->xs_control), DEBUG_XFERS);              sc_xfer->xs_control), DEBUG_XFERS);
         /* Adjust C_DMA, it may have changed if we are requesting sense */          if ((xfer->c_flags & C_DMA) && (drvp->n_xfers <= NXFER))
         if ((drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) &&                  drvp->n_xfers++;
             sc_xfer->datalen > 0 && !(xfer->c_flags & C_FORCEPIO)) {          /* Do control operations specially. */
                 if (drvp->n_xfers <= NXFER)          if (__predict_false(drvp->state < READY)) {
                         drvp->n_xfers++;                  /* If it's not a polled command, we need the kernel thread */
                 xfer->c_flags |= C_DMA;                  if ((sc_xfer->xs_control & XS_CTL_POLL) == 0 &&
         } else {                      (chp->ch_flags & ATACH_TH_RUN) == 0) {
                 xfer->c_flags &= ~C_DMA;                          chp->ch_queue->queue_freeze++;
                           wakeup(&chp->ch_thread);
                           return;
                   }
                   /*
                    * disable interrupts, all commands here should be quick
                    * enouth to be able to poll, and we don't go here that often
                    */
                    bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr,
                        WDCTL_4BIT | WDCTL_IDS);
                   if (wdc->select)
                           wdc->select(chp, xfer->c_drive);
                   bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0,
                       WDSD_IBM | (xfer->c_drive << 4));
                   /* Don't try to set mode if controller can't be adjusted */
                   if (atac->atac_set_modes == NULL)
                           goto ready;
                   /* Also don't try if the drive didn't report its mode */
                   if ((drvp->drive_flags & DRIVE_MODE) == 0)
                           goto ready;
                   errstring = "unbusy";
                   if (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags))
                           goto timeout;
                   wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
                       0x08 | drvp->PIO_mode, WDSF_SET_MODE);
                   errstring = "piomode";
                   if (wdc_wait_for_unbusy(chp, ATAPI_MODE_DELAY, wait_flags))
                           goto timeout;
                   if (chp->ch_status & WDCS_ERR) {
                           if (chp->ch_error == WDCE_ABRT) {
                                   /*
                                    * Some ATAPI drives reject PIO settings.
                                    * Fall back to PIO mode 3 since that's the
                                    * minimum for ATAPI.
                                    */
                                   printf("%s:%d:%d: PIO mode %d rejected, "
                                       "falling back to PIO mode 3\n",
                                       atac->atac_dev.dv_xname,
                                       chp->ch_channel, xfer->c_drive,
                                       drvp->PIO_mode);
                                   if (drvp->PIO_mode > 3)
                                           drvp->PIO_mode = 3;
                           } else
                                   goto error;
                   }
                   if (drvp->drive_flags & DRIVE_UDMA) {
                           wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
                               0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
                   } else if (drvp->drive_flags & DRIVE_DMA) {
                           wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
                               0x20 | drvp->DMA_mode, WDSF_SET_MODE);
                   } else {
                           goto ready;
                   }
                   errstring = "dmamode";
                   if (wdc_wait_for_unbusy(chp, ATAPI_MODE_DELAY, wait_flags))
                           goto timeout;
                   if (chp->ch_status & WDCS_ERR) {
                           if (chp->ch_error == WDCE_ABRT) {
                                   if (drvp->drive_flags & DRIVE_UDMA)
                                           goto error;
                                   else {
                                           /*
                                            * The drive rejected our DMA setting.
                                            * Fall back to mode 1.
                                            */
                                           printf("%s:%d:%d: DMA mode %d rejected, "
                                               "falling back to DMA mode 0\n",
                                               atac->atac_dev.dv_xname,
                                               chp->ch_channel, xfer->c_drive,
                                               drvp->DMA_mode);
                                           if (drvp->DMA_mode > 0)
                                                   drvp->DMA_mode = 0;
                                   }
                           } else
                                   goto error;
                   }
   ready:
                   drvp->state = READY;
                   bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr,
                       WDCTL_4BIT);
                   delay(10); /* some drives need a little delay here */
         }          }
         /* start timeout machinery */          /* start timeout machinery */
         if ((sc_xfer->xs_control & XS_CTL_POLL) == 0)          if ((sc_xfer->xs_control & XS_CTL_POLL) == 0)
                 callout_reset(&chp->ch_callout, mstohz(sc_xfer->timeout),                  callout_reset(&chp->ch_callout, mstohz(sc_xfer->timeout),
                     wdctimeout, chp);                      wdctimeout, chp);
         /* Do control operations specially. */  
         if (drvp->state < READY) {          if (wdc->select)
                 if (drvp->state != RESET) {                  wdc->select(chp, xfer->c_drive);
                         printf("%s:%d:%d: bad state %d in wdc_atapi_start\n",          bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0,
                             chp->wdc->sc_dev.dv_xname, chp->channel,              WDSD_IBM | (xfer->c_drive << 4));
                             xfer->drive, drvp->state);          switch (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags)  < 0) {
                         panic("wdc_atapi_start: bad state");          case WDCWAIT_OK:
                 }                  break;
                 drvp->state = PIOMODE;          case WDCWAIT_TOUT:
                 wdc_atapi_ctrl(chp, xfer, 0);  
                 return;  
         }  
         bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,  
             WDSD_IBM | (xfer->drive << 4));  
         if (wait_for_unbusy(chp, ATAPI_DELAY) < 0) {  
                 printf("wdc_atapi_start: not ready, st = %02x\n",                  printf("wdc_atapi_start: not ready, st = %02x\n",
                     chp->ch_status);                      chp->ch_status);
                 sc_xfer->error = XS_TIMEOUT;                  sc_xfer->error = XS_TIMEOUT;
                 wdc_atapi_reset(chp, xfer);                  wdc_atapi_reset(chp, xfer);
                 return;                  return;
           case WDCWAIT_THR:
                   return;
         }          }
   
         /*          /*
Line 453  wdc_atapi_start(chp, xfer)
Line 551  wdc_atapi_start(chp, xfer)
          * data is necessary, multiple data transfer phases will be done.           * data is necessary, multiple data transfer phases will be done.
          */           */
   
         wdccommand(chp, xfer->drive, ATAPI_PKT_CMD,          wdccommand(chp, xfer->c_drive, ATAPI_PKT_CMD,
             xfer->c_bcount <= 0xffff ? xfer->c_bcount : 0xffff,              xfer->c_bcount <= 0xffff ? xfer->c_bcount : 0xffff,
             0, 0, 0,              0, 0, 0,
             (xfer->c_flags & C_DMA) ? ATAPI_PKT_CMD_FTRE_DMA : 0);              (xfer->c_flags & C_DMA) ? ATAPI_PKT_CMD_FTRE_DMA : 0);
   
         /*          /*
          * If there is no interrupt for CMD input, busy-wait for it (done in           * If there is no interrupt for CMD input, busy-wait for it (done in
          * the interrupt routine. If it is a polled command, call the interrupt           * the interrupt routine. If it is a polled command, call the interrupt
          * routine until command is done.           * routine until command is done.
          */           */
Line 467  wdc_atapi_start(chp, xfer)
Line 565  wdc_atapi_start(chp, xfer)
             ATAPI_CFG_IRQ_DRQ || (sc_xfer->xs_control & XS_CTL_POLL)) {              ATAPI_CFG_IRQ_DRQ || (sc_xfer->xs_control & XS_CTL_POLL)) {
                 /* Wait for at last 400ns for status bit to be valid */                  /* Wait for at last 400ns for status bit to be valid */
                 DELAY(1);                  DELAY(1);
                 if (chp->ch_flags & WDCF_DMA_WAIT) {  
                         wdc_dmawait(chp, xfer, sc_xfer->timeout);  
                         chp->ch_flags &= ~WDCF_DMA_WAIT;  
                 }  
                 wdc_atapi_intr(chp, xfer, 0);                  wdc_atapi_intr(chp, xfer, 0);
         } else {          } else {
                 chp->ch_flags |= WDCF_IRQ_WAIT;                  chp->ch_flags |= ATACH_IRQ_WAIT;
         }          }
         if (sc_xfer->xs_control & XS_CTL_POLL) {          if (sc_xfer->xs_control & XS_CTL_POLL) {
                   if (chp->ch_flags & ATACH_DMA_WAIT) {
                           wdc_dmawait(chp, xfer, sc_xfer->timeout);
                           chp->ch_flags &= ~ATACH_DMA_WAIT;
                   }
                 while ((sc_xfer->xs_status & XS_STS_DONE) == 0) {                  while ((sc_xfer->xs_status & XS_STS_DONE) == 0) {
                         /* Wait for at last 400ns for status bit to be valid */                          /* Wait for at last 400ns for status bit to be valid */
                         DELAY(1);                          DELAY(1);
                         wdc_atapi_intr(chp, xfer, 0);                          wdc_atapi_intr(chp, xfer, 0);
                 }                  }
         }          }
           return;
   timeout:
           printf("%s:%d:%d: %s timed out\n",
               atac->atac_dev.dv_xname, chp->ch_channel, xfer->c_drive,
               errstring);
           sc_xfer->error = XS_TIMEOUT;
           bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
           delay(10); /* some drives need a little delay here */
           wdc_atapi_reset(chp, xfer);
           return;
   error:
           printf("%s:%d:%d: %s ",
               atac->atac_dev.dv_xname, chp->ch_channel, xfer->c_drive,
               errstring);
           printf("error (0x%x)\n", chp->ch_error);
           sc_xfer->error = XS_SHORTSENSE;
           sc_xfer->sense.atapi_sense = chp->ch_error;
           bus_space_write_1(wdr->ctl_iot, wdr->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
           delay(10); /* some drives need a little delay here */
           wdc_atapi_reset(chp, xfer);
           return;
 }  }
   
 int  static int
 wdc_atapi_intr(chp, xfer, irq)  wdc_atapi_intr(struct ata_channel *chp, struct ata_xfer *xfer, int irq)
         struct channel_softc *chp;  
         struct wdc_xfer *xfer;  
         int irq;  
 {  {
         struct scsipi_xfer *sc_xfer = xfer->cmd;          struct atac_softc *atac = chp->ch_atac;
         struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];          struct wdc_softc *wdc = CHAN_TO_WDC(chp);
           struct wdc_regs *wdr = &wdc->regs[chp->ch_channel];
           struct scsipi_xfer *sc_xfer = xfer->c_cmd;
           struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
         int len, phase, i, retries=0;          int len, phase, i, retries=0;
         int ire;          int ire, error;
         int dma_flags = 0;          int dma_flags = 0;
         void *cmd;          void *cmd;
   
         WDCDEBUG_PRINT(("wdc_atapi_intr %s:%d:%d\n",          ATADEBUG_PRINT(("wdc_atapi_intr %s:%d:%d\n",
             chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive), DEBUG_INTR);              atac->atac_dev.dv_xname, chp->ch_channel, drvp->drive),
               DEBUG_INTR);
   
         /* Is it not a transfer, but a control operation? */          /* Is it not a transfer, but a control operation? */
         if (drvp->state < READY) {          if (drvp->state < READY) {
                 printf("%s:%d:%d: bad state %d in wdc_atapi_intr\n",                  printf("%s:%d:%d: bad state %d in wdc_atapi_intr\n",
                     chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,                      atac->atac_dev.dv_xname, chp->ch_channel, xfer->c_drive,
                     drvp->state);                      drvp->state);
                 panic("wdc_atapi_intr: bad state");                  panic("wdc_atapi_intr: bad state");
         }          }
Line 515  wdc_atapi_intr(chp, xfer, irq)
Line 635  wdc_atapi_intr(chp, xfer, irq)
                 sc_xfer->error = XS_TIMEOUT;                  sc_xfer->error = XS_TIMEOUT;
                 wdc_atapi_reset(chp, xfer);                  wdc_atapi_reset(chp, xfer);
                 return 1;                  return 1;
         }          }
   
         /* Ack interrupt done in wait_for_unbusy */          /* Ack interrupt done in wdc_wait_for_unbusy */
         bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,          if (wdc->select)
             WDSD_IBM | (xfer->drive << 4));                  wdc->select(chp, xfer->c_drive);
         if (wait_for_unbusy(chp,          bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh], 0,
             (irq == 0) ? sc_xfer->timeout : 0) != 0) {              WDSD_IBM | (xfer->c_drive << 4));
           if (wdc_wait_for_unbusy(chp,
               (irq == 0) ? sc_xfer->timeout : 0, AT_POLL) == WDCWAIT_TOUT) {
                 if (irq && (xfer->c_flags & C_TIMEOU) == 0)                  if (irq && (xfer->c_flags & C_TIMEOU) == 0)
                         return 0; /* IRQ was not for us */                          return 0; /* IRQ was not for us */
                 printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d\n",                  printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d\n",
                     chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,                      atac->atac_dev.dv_xname, chp->ch_channel, xfer->c_drive,
                     xfer->c_bcount, xfer->c_skip);                      xfer->c_bcount, xfer->c_skip);
                 if (xfer->c_flags & C_DMA) {                  if (xfer->c_flags & C_DMA) {
                         ata_dmaerr(drvp);                          ata_dmaerr(drvp,
                               (xfer->c_flags & C_POLL) ? AT_POLL : 0);
                 }                  }
                 sc_xfer->error = XS_TIMEOUT;                  sc_xfer->error = XS_TIMEOUT;
                 wdc_atapi_reset(chp, xfer);                  wdc_atapi_reset(chp, xfer);
                 return 1;                  return 1;
         }          }
         if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)          if (wdc->irqack)
                 chp->wdc->irqack(chp);                  wdc->irqack(chp);
   
         /*          /*
          * If we missed an IRQ and were using DMA, flag it as a DMA error           * If we missed an IRQ and were using DMA, flag it as a DMA error
          * and reset device.           * and reset device.
          */           */
         if ((xfer->c_flags & C_TIMEOU) && (xfer->c_flags & C_DMA)) {          if ((xfer->c_flags & C_TIMEOU) && (xfer->c_flags & C_DMA)) {
                 ata_dmaerr(drvp);                  ata_dmaerr(drvp, (xfer->c_flags & C_POLL) ? AT_POLL : 0);
                 sc_xfer->error = XS_RESET;                  sc_xfer->error = XS_RESET;
                 wdc_atapi_reset(chp, xfer);                  wdc_atapi_reset(chp, xfer);
                 return (1);                  return (1);
         }          }
         /*          /*
          * if the request sense command was aborted, report the short sense           * if the request sense command was aborted, report the short sense
          * previously recorded, else continue normal processing           * previously recorded, else continue normal processing
          */           */
Line 556  wdc_atapi_intr(chp, xfer, irq)
Line 679  wdc_atapi_intr(chp, xfer, irq)
                 dma_flags = (sc_xfer->xs_control & XS_CTL_DATA_IN)                  dma_flags = (sc_xfer->xs_control & XS_CTL_DATA_IN)
                     ?  WDC_DMA_READ : 0;                      ?  WDC_DMA_READ : 0;
 again:  again:
         len = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo) +          len = bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_cyl_lo], 0) +
             256 * bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_hi);              256 * bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_cyl_hi], 0);
         ire = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_ireason);          ire = bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_ireason], 0);
         phase = (ire & (WDCI_CMD | WDCI_IN)) | (chp->ch_status & WDCS_DRQ);          phase = (ire & (WDCI_CMD | WDCI_IN)) | (chp->ch_status & WDCS_DRQ);
         WDCDEBUG_PRINT(("wdc_atapi_intr: c_bcount %d len %d st 0x%x err 0x%x "          ATADEBUG_PRINT(("wdc_atapi_intr: c_bcount %d len %d st 0x%x err 0x%x "
             "ire 0x%x :", xfer->c_bcount,              "ire 0x%x :", xfer->c_bcount,
             len, chp->ch_status, chp->ch_error, ire), DEBUG_INTR);              len, chp->ch_status, chp->ch_error, ire), DEBUG_INTR);
   
         switch (phase) {          switch (phase) {
         case PHASE_CMDOUT:          case PHASE_CMDOUT:
                 cmd  = sc_xfer->cmd;                  cmd = sc_xfer->cmd;
                 WDCDEBUG_PRINT(("PHASE_CMDOUT\n"), DEBUG_INTR);                  ATADEBUG_PRINT(("PHASE_CMDOUT\n"), DEBUG_INTR);
                 /* Init the DMA channel if necessary */                  /* Init the DMA channel if necessary */
                 if (xfer->c_flags & C_DMA) {                  if (xfer->c_flags & C_DMA) {
                         if ((*chp->wdc->dma_init)(chp->wdc->dma_arg,                          error = (*wdc->dma_init)(wdc->dma_arg,
                             chp->channel, xfer->drive,                              chp->ch_channel, xfer->c_drive,
                             xfer->databuf, xfer->c_bcount, dma_flags) != 0) {                              xfer->c_databuf, xfer->c_bcount, dma_flags);
                                 sc_xfer->error = XS_DRIVER_STUFFUP;                          if (error) {
                                 break;                                  if (error == EINVAL) {
                                           /*
                                            * We can't do DMA on this transfer
                                            * for some reason.  Fall back to
                                            * PIO.
                                            */
                                           xfer->c_flags &= ~C_DMA;
                                           error = 0;
                                   } else {
                                           sc_xfer->error = XS_DRIVER_STUFFUP;
                                           break;
                                   }
                         }                          }
                 }                  }
   
                 /* send packet command */                  /* send packet command */
                 /* Commands are 12 or 16 bytes long. It's 32-bit aligned */                  /* Commands are 12 or 16 bytes long. It's 32-bit aligned */
                 if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM)) {                  wdc->dataout_pio(chp, drvp->drive_flags, cmd, sc_xfer->cmdlen);
                         if (drvp->drive_flags & DRIVE_CAP32) {  
                                 bus_space_write_multi_4(chp->data32iot,  
                                     chp->data32ioh, 0,  
                                     (u_int32_t *)cmd,  
                                     sc_xfer->cmdlen >> 2);  
                         } else {  
                                 bus_space_write_multi_2(chp->cmd_iot,  
                                     chp->cmd_ioh, wd_data,  
                                     (u_int16_t *)cmd,  
                                     sc_xfer->cmdlen >> 1);  
                         }  
                 } else {  
                         if (drvp->drive_flags & DRIVE_CAP32) {  
                                 bus_space_write_multi_stream_4(chp->data32iot,  
                                     chp->data32ioh, 0,  
                                     (u_int32_t *)cmd,  
                                     sc_xfer->cmdlen >> 2);  
                         } else {  
                                 bus_space_write_multi_stream_2(chp->cmd_iot,  
                                     chp->cmd_ioh, wd_data,  
                                     (u_int16_t *)cmd,  
                                     sc_xfer->cmdlen >> 1);  
                         }  
                 }  
                 /* Start the DMA channel if necessary */                  /* Start the DMA channel if necessary */
                 if (xfer->c_flags & C_DMA) {                  if (xfer->c_flags & C_DMA) {
                         (*chp->wdc->dma_start)(chp->wdc->dma_arg,                          (*wdc->dma_start)(wdc->dma_arg,
                             chp->channel, xfer->drive);                              chp->ch_channel, xfer->c_drive);
                         chp->ch_flags |= WDCF_DMA_WAIT;                          chp->ch_flags |= ATACH_DMA_WAIT;
                 }                  }
   
                 if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) {                  if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) {
                         chp->ch_flags |= WDCF_IRQ_WAIT;                          chp->ch_flags |= ATACH_IRQ_WAIT;
                 }                  }
                 return 1;                  return 1;
   
          case PHASE_DATAOUT:           case PHASE_DATAOUT:
                 /* write data */                  /* write data */
                 WDCDEBUG_PRINT(("PHASE_DATAOUT\n"), DEBUG_INTR);                  ATADEBUG_PRINT(("PHASE_DATAOUT\n"), DEBUG_INTR);
                 if ((sc_xfer->xs_control & XS_CTL_DATA_OUT) == 0 ||                  if ((sc_xfer->xs_control & XS_CTL_DATA_OUT) == 0 ||
                     (xfer->c_flags & C_DMA) != 0) {                      (xfer->c_flags & C_DMA) != 0) {
                         printf("wdc_atapi_intr: bad data phase DATAOUT\n");                          printf("wdc_atapi_intr: bad data phase DATAOUT\n");
                         if (xfer->c_flags & C_DMA) {                          if (xfer->c_flags & C_DMA) {
                                 ata_dmaerr(drvp);                                  ata_dmaerr(drvp,
                                       (xfer->c_flags & C_POLL) ? AT_POLL : 0);
                         }                          }
                         sc_xfer->error = XS_TIMEOUT;                          sc_xfer->error = XS_TIMEOUT;
                         wdc_atapi_reset(chp, xfer);                          wdc_atapi_reset(chp, xfer);
Line 632  again:
Line 745  again:
                 if (xfer->c_bcount < len) {                  if (xfer->c_bcount < len) {
                         printf("wdc_atapi_intr: warning: write only "                          printf("wdc_atapi_intr: warning: write only "
                             "%d of %d requested bytes\n", xfer->c_bcount, len);                              "%d of %d requested bytes\n", xfer->c_bcount, len);
                         if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM)) {                          wdc->dataout_pio(chp, drvp->drive_flags,
                                 bus_space_write_multi_2(chp->cmd_iot,                              (char *)xfer->c_databuf + xfer->c_skip,
                                     chp->cmd_ioh, wd_data,                              xfer->c_bcount);
                                     (u_int16_t *)((char *)xfer->databuf +  
                                                   xfer->c_skip),  
                                     xfer->c_bcount >> 1);  
                         } else {  
                                 bus_space_write_multi_stream_2(chp->cmd_iot,  
                                     chp->cmd_ioh, wd_data,  
                                     (u_int16_t *)((char *)xfer->databuf +  
                                                   xfer->c_skip),  
                                     xfer->c_bcount >> 1);  
                         }  
                         for (i = xfer->c_bcount; i < len; i += 2)                          for (i = xfer->c_bcount; i < len; i += 2)
                                 bus_space_write_2(chp->cmd_iot, chp->cmd_ioh,                                  bus_space_write_2(wdr->cmd_iot,
                                     wd_data, 0);                                      wdr->cmd_iohs[wd_data], 0, 0);
                         xfer->c_skip += xfer->c_bcount;                          xfer->c_skip += xfer->c_bcount;
                         xfer->c_bcount = 0;                          xfer->c_bcount = 0;
                 } else {                  } else {
                         if (drvp->drive_flags & DRIVE_CAP32) {                          wdc->dataout_pio(chp, drvp->drive_flags,
                             if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM))                              (char *)xfer->c_databuf + xfer->c_skip, len);
                                 bus_space_write_multi_4(chp->data32iot,                          xfer->c_skip += len;
                                     chp->data32ioh, 0,                          xfer->c_bcount -= len;
                                     (u_int32_t *)((char *)xfer->databuf +  
                                                   xfer->c_skip),  
                                     len >> 2);  
                             else  
                                 bus_space_write_multi_stream_4(chp->data32iot,  
                                     chp->data32ioh, wd_data,  
                                     (u_int32_t *)((char *)xfer->databuf +  
                                                   xfer->c_skip),  
                                     len >> 2);  
   
                             xfer->c_skip += len & 0xfffffffc;  
                             xfer->c_bcount -= len & 0xfffffffc;  
                             len = len & 0x03;  
                         }  
                         if (len > 0) {  
                             if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM))  
                                 bus_space_write_multi_2(chp->cmd_iot,  
                                     chp->cmd_ioh, wd_data,  
                                     (u_int16_t *)((char *)xfer->databuf +  
                                                   xfer->c_skip),  
                                     len >> 1);  
                             else  
                                 bus_space_write_multi_stream_2(chp->cmd_iot,  
                                     chp->cmd_ioh, wd_data,  
                                     (u_int16_t *)((char *)xfer->databuf +  
                                                   xfer->c_skip),  
                                     len >> 1);  
                             xfer->c_skip += len;  
                             xfer->c_bcount -= len;  
                         }  
                 }                  }
                 if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) {                  if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) {
                         chp->ch_flags |= WDCF_IRQ_WAIT;                          chp->ch_flags |= ATACH_IRQ_WAIT;
                 }                  }
                 return 1;                  return 1;
   
         case PHASE_DATAIN:          case PHASE_DATAIN:
                 /* Read data */                  /* Read data */
                 WDCDEBUG_PRINT(("PHASE_DATAIN\n"), DEBUG_INTR);                  ATADEBUG_PRINT(("PHASE_DATAIN\n"), DEBUG_INTR);
                 if ((sc_xfer->xs_control & XS_CTL_DATA_IN) == 0 ||                  if ((sc_xfer->xs_control & XS_CTL_DATA_IN) == 0 ||
                     (xfer->c_flags & C_DMA) != 0) {                      (xfer->c_flags & C_DMA) != 0) {
                         printf("wdc_atapi_intr: bad data phase DATAIN\n");                          printf("wdc_atapi_intr: bad data phase DATAIN\n");
                         if (xfer->c_flags & C_DMA) {                          if (xfer->c_flags & C_DMA) {
                                 ata_dmaerr(drvp);                                  ata_dmaerr(drvp,
                                       (xfer->c_flags & C_POLL) ? AT_POLL : 0);
                         }                          }
                         sc_xfer->error = XS_TIMEOUT;                          sc_xfer->error = XS_TIMEOUT;
                         wdc_atapi_reset(chp, xfer);                          wdc_atapi_reset(chp, xfer);
Line 707  again:
Line 781  again:
                 if (xfer->c_bcount < len) {                  if (xfer->c_bcount < len) {
                         printf("wdc_atapi_intr: warning: reading only "                          printf("wdc_atapi_intr: warning: reading only "
                             "%d of %d bytes\n", xfer->c_bcount, len);                              "%d of %d bytes\n", xfer->c_bcount, len);
                         if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM)) {                          wdc->datain_pio(chp, drvp->drive_flags,
                             bus_space_read_multi_2(chp->cmd_iot,                              (char *)xfer->c_databuf + xfer->c_skip,
                             chp->cmd_ioh, wd_data,                              xfer->c_bcount);
                             (u_int16_t *)((char *)xfer->databuf +  
                                           xfer->c_skip),  
                             xfer->c_bcount >> 1);  
                         } else {  
                             bus_space_read_multi_stream_2(chp->cmd_iot,  
                             chp->cmd_ioh, wd_data,  
                             (u_int16_t *)((char *)xfer->databuf +  
                                           xfer->c_skip),  
                             xfer->c_bcount >> 1);  
                         }  
                         wdcbit_bucket(chp, len - xfer->c_bcount);                          wdcbit_bucket(chp, len - xfer->c_bcount);
                         xfer->c_skip += xfer->c_bcount;                          xfer->c_skip += xfer->c_bcount;
                         xfer->c_bcount = 0;                          xfer->c_bcount = 0;
                 } else {                  } else {
                         if (drvp->drive_flags & DRIVE_CAP32) {                          wdc->datain_pio(chp, drvp->drive_flags,
                             if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM))                              (char *)xfer->c_databuf + xfer->c_skip, len);
                                 bus_space_read_multi_4(chp->data32iot,                          xfer->c_skip += len;
                                     chp->data32ioh, 0,                          xfer->c_bcount -=len;
                                     (u_int32_t *)((char *)xfer->databuf +  
                                                   xfer->c_skip),  
                                     len >> 2);  
                             else  
                                 bus_space_read_multi_stream_4(chp->data32iot,  
                                     chp->data32ioh, wd_data,  
                                     (u_int32_t *)((char *)xfer->databuf +  
                                                   xfer->c_skip),  
                                     len >> 2);  
   
                             xfer->c_skip += len & 0xfffffffc;  
                             xfer->c_bcount -= len & 0xfffffffc;  
                             len = len & 0x03;  
                         }  
                         if (len > 0) {  
                             if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM))  
                                 bus_space_read_multi_2(chp->cmd_iot,  
                                     chp->cmd_ioh, wd_data,  
                                     (u_int16_t *)((char *)xfer->databuf +  
                                                   xfer->c_skip),  
                                     len >> 1);  
                             else  
                                 bus_space_read_multi_stream_2(chp->cmd_iot,  
                                     chp->cmd_ioh, wd_data,  
                                     (u_int16_t *)((char *)xfer->databuf +  
                                                   xfer->c_skip),  
                                     len >> 1);  
                             xfer->c_skip += len;  
                             xfer->c_bcount -=len;  
                         }  
                 }                  }
                 if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) {                  if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) {
                         chp->ch_flags |= WDCF_IRQ_WAIT;                          chp->ch_flags |= ATACH_IRQ_WAIT;
                 }                  }
                 return 1;                  return 1;
   
         case PHASE_ABORTED:          case PHASE_ABORTED:
         case PHASE_COMPLETED:          case PHASE_COMPLETED:
                 WDCDEBUG_PRINT(("PHASE_COMPLETED\n"), DEBUG_INTR);                  ATADEBUG_PRINT(("PHASE_COMPLETED\n"), DEBUG_INTR);
                 if (xfer->c_flags & C_DMA) {                  if (xfer->c_flags & C_DMA) {
                         xfer->c_bcount -= sc_xfer->datalen;                          xfer->c_bcount -= sc_xfer->datalen;
                 }                  }
Line 777  again:
Line 811  again:
         default:          default:
                 if (++retries<500) {                  if (++retries<500) {
                         DELAY(100);                          DELAY(100);
                         chp->ch_status = bus_space_read_1(chp->cmd_iot,                          chp->ch_status = bus_space_read_1(wdr->cmd_iot,
                             chp->cmd_ioh, wd_status);                              wdr->cmd_iohs[wd_status], 0);
                         chp->ch_error = bus_space_read_1(chp->cmd_iot,                          chp->ch_error = bus_space_read_1(wdr->cmd_iot,
                             chp->cmd_ioh, wd_error);                              wdr->cmd_iohs[wd_error], 0);
                         goto again;                          goto again;
                 }                  }
                 printf("wdc_atapi_intr: unknown phase 0x%x\n", phase);                  printf("wdc_atapi_intr: unknown phase 0x%x\n", phase);
Line 789  again:
Line 823  again:
                         sc_xfer->sense.atapi_sense = chp->ch_error;                          sc_xfer->sense.atapi_sense = chp->ch_error;
                 } else {                  } else {
                         if (xfer->c_flags & C_DMA) {                          if (xfer->c_flags & C_DMA) {
                                 ata_dmaerr(drvp);                                  ata_dmaerr(drvp,
                                       (xfer->c_flags & C_POLL) ? AT_POLL : 0);
                         }                          }
                         sc_xfer->error = XS_RESET;                          sc_xfer->error = XS_RESET;
                         wdc_atapi_reset(chp, xfer);                          wdc_atapi_reset(chp, xfer);
                         return (1);                          return (1);
                 }                  }
         }          }
         WDCDEBUG_PRINT(("wdc_atapi_intr: wdc_atapi_done() (end), error 0x%x "          ATADEBUG_PRINT(("wdc_atapi_intr: wdc_atapi_done() (end), error 0x%x "
             "sense 0x%x\n", sc_xfer->error, sc_xfer->sense.atapi_sense),              "sense 0x%x\n", sc_xfer->error, sc_xfer->sense.atapi_sense),
             DEBUG_INTR);              DEBUG_INTR);
         wdc_atapi_done(chp, xfer);          wdc_atapi_done(chp, xfer);
         return (1);          return (1);
 }  }
   
 int  static void
 wdc_atapi_ctrl(chp, xfer, irq)  wdc_atapi_phase_complete(struct ata_xfer *xfer)
         struct channel_softc *chp;  
         struct wdc_xfer *xfer;  
         int irq;  
 {  {
         struct scsipi_xfer *sc_xfer = xfer->cmd;          struct ata_channel *chp = xfer->c_chp;
         struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];          struct atac_softc *atac = chp->ch_atac;
         char *errstring = NULL;          struct wdc_softc *wdc = CHAN_TO_WDC(chp);
         int delay = (irq == 0) ? ATAPI_DELAY : 0;          struct scsipi_xfer *sc_xfer = xfer->c_cmd;
           struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
         /* Ack interrupt done in wait_for_unbusy */  
 again:  
         WDCDEBUG_PRINT(("wdc_atapi_ctrl %s:%d:%d state %d\n",  
             chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive, drvp->state),  
             DEBUG_INTR | DEBUG_FUNCS);  
         bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,  
             WDSD_IBM | (xfer->drive << 4));  
         switch (drvp->state) {  
         case PIOMODE:  
                 /* Don't try to set mode if controller can't be adjusted */  
                 if ((chp->wdc->cap & WDC_CAPABILITY_MODE) == 0)  
                         goto ready;  
                 /* Also don't try if the drive didn't report its mode */  
                 if ((drvp->drive_flags & DRIVE_MODE) == 0)  
                         goto ready;  
                 wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,  
                     0x08 | drvp->PIO_mode, WDSF_SET_MODE);  
                 drvp->state = PIOMODE_WAIT;  
                 break;  
         case PIOMODE_WAIT:  
                 errstring = "piomode";  
                 if (wait_for_unbusy(chp, delay))  
                         goto timeout;  
                 if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)  
                         chp->wdc->irqack(chp);  
                 if (chp->ch_status & WDCS_ERR) {  
                         if (chp->ch_error == WDCE_ABRT) {  
                                 /*  
                                  * some ATAPI drives rejects pio settings.  
                                  * all we can do here is fall back to PIO 0  
                                  */  
                                 drvp->drive_flags &= ~DRIVE_MODE;  
                                 drvp->drive_flags &= ~(DRIVE_DMA|DRIVE_UDMA);  
                                 drvp->PIO_mode = 0;  
                                 drvp->DMA_mode = 0;  
                                 printf("%s:%d:%d: pio setting rejected, "  
                                     "falling back to PIO mode 0\n",  
                                     chp->wdc->sc_dev.dv_xname,  
                                     chp->channel, xfer->drive);  
                                 chp->wdc->set_modes(chp);  
                                 goto ready;  
                         }  
                         goto error;  
                 }  
         /* fall through */  
   
         case DMAMODE:  
                 if (drvp->drive_flags & DRIVE_UDMA) {  
                         wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,  
                             0x40 | drvp->UDMA_mode, WDSF_SET_MODE);  
                 } else if (drvp->drive_flags & DRIVE_DMA) {  
                         wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,  
                             0x20 | drvp->DMA_mode, WDSF_SET_MODE);  
                 } else {  
                         goto ready;  
                 }  
                 drvp->state = DMAMODE_WAIT;  
                 break;  
         case DMAMODE_WAIT:  
                 errstring = "dmamode";  
                 if (wait_for_unbusy(chp, delay))  
                         goto timeout;  
                 if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)  
                         chp->wdc->irqack(chp);  
                 if (chp->ch_status & WDCS_ERR)  
                         goto error;  
         /* fall through */  
   
         case READY:  
         ready:  
                 drvp->state = READY;  
                 xfer->c_intr = wdc_atapi_intr;  
                 callout_stop(&chp->ch_callout);  
                 wdc_atapi_start(chp, xfer);  
                 return 1;  
         }  
         if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) {  
                 chp->ch_flags |= WDCF_IRQ_WAIT;  
                 xfer->c_intr = wdc_atapi_ctrl;  
         } else {  
                 goto again;  
         }  
         return 1;  
   
 timeout:  
         if (irq && (xfer->c_flags & C_TIMEOU) == 0) {  
                 return 0; /* IRQ was not for us */  
         }  
         printf("%s:%d:%d: %s timed out\n",  
             chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, errstring);  
         sc_xfer->error = XS_TIMEOUT;  
         wdc_atapi_reset(chp, xfer);  
         return 1;  
 error:  
         printf("%s:%d:%d: %s ",  
             chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,  
             errstring);  
         printf("error (0x%x)\n", chp->ch_error);  
         sc_xfer->error = XS_SHORTSENSE;  
         sc_xfer->sense.atapi_sense = chp->ch_error;  
         wdc_atapi_reset(chp, xfer);  
         return 1;  
 }  
   
 void  
 wdc_atapi_phase_complete(xfer)  
         struct wdc_xfer *xfer;  
 {  
         struct channel_softc *chp = xfer->chp;  
         struct scsipi_xfer *sc_xfer = xfer->cmd;  
         struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];  
   
         /* wait for DSC if needed */          /* wait for DSC if needed */
         if (drvp->drive_flags & DRIVE_ATAPIST) {          if (drvp->drive_flags & DRIVE_ATAPIST) {
                 WDCDEBUG_PRINT(("wdc_atapi_phase_complete(%s:%d:%d) "                  ATADEBUG_PRINT(("wdc_atapi_phase_complete(%s:%d:%d) "
                     "polldsc %d\n", chp->wdc->sc_dev.dv_xname, chp->channel,                      "polldsc %d\n", atac->atac_dev.dv_xname, chp->ch_channel,
                     xfer->drive, xfer->c_dscpoll), DEBUG_XFERS);                      xfer->c_drive, xfer->c_dscpoll), DEBUG_XFERS);
                 if (cold) {  #if 1
                         if (wdcwait(chp, WDCS_DSC, WDCS_DSC,                  if (cold)
                             sc_xfer->timeout)) {                          panic("wdc_atapi_phase_complete: cold");
                                 printf("%s:%d:%d: wait_for_dsc failed\n",  #endif
                                     chp->wdc->sc_dev.dv_xname, chp->channel,                  if (wdcwait(chp, WDCS_DSC, WDCS_DSC, 10,
                                     xfer->drive);                      AT_POLL) == WDCWAIT_TOUT) {
                           /* 10ms not enough, try again in 1 tick */
                           if (xfer->c_dscpoll++ >
                               mstohz(sc_xfer->timeout)) {
                                   printf("%s:%d:%d: wait_for_dsc "
                                       "failed\n",
                                       atac->atac_dev.dv_xname,
                                       chp->ch_channel, xfer->c_drive);
                                 sc_xfer->error = XS_TIMEOUT;                                  sc_xfer->error = XS_TIMEOUT;
                                 wdc_atapi_reset(chp, xfer);                                  wdc_atapi_reset(chp, xfer);
                                 return;                                  return;
                         }                          } else
                 } else {  
                         if (wdcwait(chp, WDCS_DSC, WDCS_DSC, 10)) {  
                                 /* 10ms not enough, try again in 1 tick */  
                                 if (xfer->c_dscpoll++ >  
                                     mstohz(sc_xfer->timeout)) {  
                                         printf("%s:%d:%d: wait_for_dsc "  
                                             "failed\n",  
                                             chp->wdc->sc_dev.dv_xname,  
                                             chp->channel, xfer->drive);  
                                         sc_xfer->error = XS_TIMEOUT;  
                                         wdc_atapi_reset(chp, xfer);  
                                         return;  
                                 }  
                                 callout_reset(&chp->ch_callout, 1,                                  callout_reset(&chp->ch_callout, 1,
                                     wdc_atapi_polldsc, xfer);                                      wdc_atapi_polldsc, xfer);
                                 return;                          return;
                         }  
                 }                  }
         }          }
   
         /*          /*
          * Some drive occasionally set WDCS_ERR with           * Some drive occasionally set WDCS_ERR with
          * "ATA illegal length indication" in the error           * "ATA illegal length indication" in the error
          * register. If we read some data the sense is valid           * register. If we read some data the sense is valid
          * anyway, so don't report the error.           * anyway, so don't report the error.
Line 978  wdc_atapi_phase_complete(xfer)
Line 892  wdc_atapi_phase_complete(xfer)
                         /* ask scsipi to send a REQUEST_SENSE */                          /* ask scsipi to send a REQUEST_SENSE */
                         sc_xfer->error = XS_BUSY;                          sc_xfer->error = XS_BUSY;
                         sc_xfer->status = SCSI_CHECK;                          sc_xfer->status = SCSI_CHECK;
                 } else if (chp->wdc->dma_status &                  } else if (wdc->dma_status &
                     (WDC_DMAST_NOIRQ | WDC_DMAST_ERR)) {                      (WDC_DMAST_NOIRQ | WDC_DMAST_ERR)) {
                         ata_dmaerr(drvp);                          ata_dmaerr(drvp,
                               (xfer->c_flags & C_POLL) ? AT_POLL : 0);
                         sc_xfer->error = XS_RESET;                          sc_xfer->error = XS_RESET;
                         wdc_atapi_reset(chp, xfer);                          wdc_atapi_reset(chp, xfer);
                         return;                          return;
                 }                  }
         }          }
         if (xfer->c_bcount != 0) {          if (xfer->c_bcount != 0) {
                 WDCDEBUG_PRINT(("wdc_atapi_intr: bcount value is "                  ATADEBUG_PRINT(("wdc_atapi_intr: bcount value is "
                     "%d after io\n", xfer->c_bcount), DEBUG_XFERS);                      "%d after io\n", xfer->c_bcount), DEBUG_XFERS);
         }          }
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
Line 996  wdc_atapi_phase_complete(xfer)
Line 911  wdc_atapi_phase_complete(xfer)
                     "is %d after io\n", xfer->c_bcount);                      "is %d after io\n", xfer->c_bcount);
         }          }
 #endif  #endif
         WDCDEBUG_PRINT(("wdc_atapi_phase_complete: wdc_atapi_done(), "          ATADEBUG_PRINT(("wdc_atapi_phase_complete: wdc_atapi_done(), "
             "error 0x%x sense 0x%x\n", sc_xfer->error,              "error 0x%x sense 0x%x\n", sc_xfer->error,
             sc_xfer->sense.atapi_sense), DEBUG_INTR);              sc_xfer->sense.atapi_sense), DEBUG_INTR);
         wdc_atapi_done(chp, xfer);          wdc_atapi_done(chp, xfer);
 }  }
   
 void  static void
 wdc_atapi_done(chp, xfer)  wdc_atapi_done(struct ata_channel *chp, struct ata_xfer *xfer)
         struct channel_softc *chp;  
         struct wdc_xfer *xfer;  
 {  {
         struct scsipi_xfer *sc_xfer = xfer->cmd;          struct atac_softc *atac = chp->ch_atac;
           struct scsipi_xfer *sc_xfer = xfer->c_cmd;
           int drive = xfer->c_drive;
   
         WDCDEBUG_PRINT(("wdc_atapi_done %s:%d:%d: flags 0x%x\n",          ATADEBUG_PRINT(("wdc_atapi_done %s:%d:%d: flags 0x%x\n",
             chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,              atac->atac_dev.dv_xname, chp->ch_channel, xfer->c_drive,
             (u_int)xfer->c_flags), DEBUG_XFERS);              (u_int)xfer->c_flags), DEBUG_XFERS);
         callout_stop(&chp->ch_callout);          callout_stop(&chp->ch_callout);
         /* remove this command from xfer queue */          /* mark controller inactive and free the command */
         wdc_free_xfer(chp, xfer);          chp->ch_queue->active_xfer = NULL;
           ata_free_xfer(chp, xfer);
   
         WDCDEBUG_PRINT(("wdc_atapi_done: scsipi_done\n"), DEBUG_XFERS);          if (chp->ch_drive[drive].drive_flags & DRIVE_WAITDRAIN) {
                   sc_xfer->error = XS_DRIVER_STUFFUP;
                   chp->ch_drive[drive].drive_flags &= ~DRIVE_WAITDRAIN;
                   wakeup(&chp->ch_queue->active_xfer);
           }
   
           ATADEBUG_PRINT(("wdc_atapi_done: scsipi_done\n"), DEBUG_XFERS);
         scsipi_done(sc_xfer);          scsipi_done(sc_xfer);
         WDCDEBUG_PRINT(("wdcstart from wdc_atapi_done, flags 0x%x\n",          ATADEBUG_PRINT(("atastart from wdc_atapi_done, flags 0x%x\n",
             chp->ch_flags), DEBUG_XFERS);              chp->ch_flags), DEBUG_XFERS);
         wdcstart(chp);          atastart(chp);
 }  }
   
 void  static void
 wdc_atapi_reset(chp, xfer)  wdc_atapi_reset(struct ata_channel *chp, struct ata_xfer *xfer)
         struct channel_softc *chp;  
         struct wdc_xfer *xfer;  
 {  {
         struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];          struct atac_softc *atac = chp->ch_atac;
         struct scsipi_xfer *sc_xfer = xfer->cmd;          struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
           struct scsipi_xfer *sc_xfer = xfer->c_cmd;
   
         wdccommandshort(chp, xfer->drive, ATAPI_SOFT_RESET);          wdccommandshort(chp, xfer->c_drive, ATAPI_SOFT_RESET);
         drvp->state = 0;          drvp->state = 0;
         if (wait_for_unbusy(chp, WDC_RESET_WAIT) != 0) {          if (wdc_wait_for_unbusy(chp, WDC_RESET_WAIT, AT_POLL) != 0) {
                 printf("%s:%d:%d: reset failed\n",                  printf("%s:%d:%d: reset failed\n",
                     chp->wdc->sc_dev.dv_xname, chp->channel,                      atac->atac_dev.dv_xname, chp->ch_channel,
                     xfer->drive);                      xfer->c_drive);
                 sc_xfer->error = XS_SELTIMEOUT;                  sc_xfer->error = XS_SELTIMEOUT;
         }          }
         wdc_atapi_done(chp, xfer);          wdc_atapi_done(chp, xfer);
         return;          return;
 }  }
   
 void  static void
 wdc_atapi_polldsc(arg)  wdc_atapi_polldsc(void *arg)
         void *arg;  
 {  {
   
         wdc_atapi_phase_complete(arg);          wdc_atapi_phase_complete(arg);
 }  }

Legend:
Removed from v.1.55  
changed lines
  Added in v.1.55.6.7

CVSweb <webmaster@jp.NetBSD.org>