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

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

Diff for /src/sys/dev/ata/ata.c between version 1.141 and 1.141.4.2

version 1.141, 2017/10/28 04:53:54 version 1.141.4.2, 2020/04/08 14:08:03
Line 32  __KERNEL_RCSID(0, "$NetBSD$");
Line 32  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/systm.h>  #include <sys/systm.h>
 #include <sys/kernel.h>  #include <sys/kernel.h>
 #include <sys/malloc.h>  
 #include <sys/device.h>  #include <sys/device.h>
 #include <sys/conf.h>  #include <sys/conf.h>
 #include <sys/fcntl.h>  #include <sys/fcntl.h>
Line 45  __KERNEL_RCSID(0, "$NetBSD$");
Line 44  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/bus.h>  #include <sys/bus.h>
 #include <sys/once.h>  #include <sys/once.h>
 #include <sys/bitops.h>  #include <sys/bitops.h>
   #include <sys/cpu.h>
   
 #define ATABUS_PRIVATE  #define ATABUS_PRIVATE
   
Line 85  int atadebug_mask = ATADEBUG_MASK;
Line 85  int atadebug_mask = ATADEBUG_MASK;
 #endif  #endif
   
 static ONCE_DECL(ata_init_ctrl);  static ONCE_DECL(ata_init_ctrl);
   static struct pool ata_xfer_pool;
   
 /*  /*
  * A queue of atabus instances, used to ensure the same bus probe order   * A queue of atabus instances, used to ensure the same bus probe order
Line 129  static bool atabus_suspend(device_t, con
Line 130  static bool atabus_suspend(device_t, con
 static void atabusconfig_thread(void *);  static void atabusconfig_thread(void *);
   
 static void ata_channel_idle(struct ata_channel *);  static void ata_channel_idle(struct ata_channel *);
 static void ata_channel_thaw_locked(struct ata_channel *);  
 static void ata_activate_xfer_locked(struct ata_channel *, struct ata_xfer *);  static void ata_activate_xfer_locked(struct ata_channel *, struct ata_xfer *);
 static void ata_channel_freeze_locked(struct ata_channel *);  static void ata_channel_freeze_locked(struct ata_channel *);
 static void ata_thread_wake_locked(struct ata_channel *);  static void ata_thread_wake_locked(struct ata_channel *);
Line 143  static int
Line 143  static int
 atabus_init(void)  atabus_init(void)
 {  {
   
           pool_init(&ata_xfer_pool, sizeof(struct ata_xfer), 0, 0, 0,
               "ataspl", NULL, IPL_BIO);
         TAILQ_INIT(&atabus_initq_head);          TAILQ_INIT(&atabus_initq_head);
         mutex_init(&atabus_qlock, MUTEX_DEFAULT, IPL_NONE);          mutex_init(&atabus_qlock, MUTEX_DEFAULT, IPL_NONE);
         cv_init(&atabus_qcv, "atainitq");          cv_init(&atabus_qcv, "atainitq");
Line 215  ata_channel_detach(struct ata_channel *c
Line 217  ata_channel_detach(struct ata_channel *c
                 return;                  return;
   
         ata_channel_destroy(chp);          ata_channel_destroy(chp);
   
           chp->ch_flags |= ATACH_DETACHED;
 }  }
   
 static void  static void
Line 226  atabusconfig(struct atabus_softc *atabus
Line 230  atabusconfig(struct atabus_softc *atabus
         int i, error;          int i, error;
   
         /* we are in the atabus's thread context */          /* we are in the atabus's thread context */
         ata_channel_lock(chp);  
         chp->ch_flags |= ATACH_TH_RUN;  
         ata_channel_unlock(chp);  
   
         /*          /*
          * Probe for the drives attached to controller, unless a PMP           * Probe for the drives attached to controller, unless a PMP
Line 244  atabusconfig(struct atabus_softc *atabus
Line 245  atabusconfig(struct atabus_softc *atabus
                     DEBUG_PROBE);                      DEBUG_PROBE);
         }          }
   
         /* next operations will occurs in a separate thread */  
         ata_channel_lock(chp);  
         chp->ch_flags &= ~ATACH_TH_RUN;  
         ata_channel_unlock(chp);  
   
         /* Make sure the devices probe in atabus order to avoid jitter. */          /* Make sure the devices probe in atabus order to avoid jitter. */
         mutex_enter(&atabus_qlock);          mutex_enter(&atabus_qlock);
         for (;;) {          for (;;) {
Line 261  atabusconfig(struct atabus_softc *atabus
Line 257  atabusconfig(struct atabus_softc *atabus
   
         ata_channel_lock(chp);          ata_channel_lock(chp);
   
           KASSERT(ata_is_thread_run(chp));
   
         /* If no drives, abort here */          /* If no drives, abort here */
         if (chp->ch_drive == NULL)          if (chp->ch_drive == NULL)
                 goto out;                  goto out;
Line 292  atabusconfig(struct atabus_softc *atabus
Line 290  atabusconfig(struct atabus_softc *atabus
         cv_broadcast(&atabus_qcv);          cv_broadcast(&atabus_qcv);
         mutex_exit(&atabus_qlock);          mutex_exit(&atabus_qlock);
   
         free(atabus_initq, M_DEVBUF);          kmem_free(atabus_initq, sizeof(*atabus_initq));
   
         ata_delref(chp);          ata_delref(chp);
   
Line 418  atabusconfig_thread(void *arg)
Line 416  atabusconfig_thread(void *arg)
         cv_broadcast(&atabus_qcv);          cv_broadcast(&atabus_qcv);
         mutex_exit(&atabus_qlock);          mutex_exit(&atabus_qlock);
   
         free(atabus_initq, M_DEVBUF);          kmem_free(atabus_initq, sizeof(*atabus_initq));
   
         ata_delref(chp);          ata_delref(chp);
   
Line 438  atabus_thread(void *arg)
Line 436  atabus_thread(void *arg)
         struct ata_channel *chp = sc->sc_chan;          struct ata_channel *chp = sc->sc_chan;
         struct ata_queue *chq = chp->ch_queue;          struct ata_queue *chq = chp->ch_queue;
         struct ata_xfer *xfer;          struct ata_xfer *xfer;
         int i, rv, s;          int i, rv;
   
         ata_channel_lock(chp);          ata_channel_lock(chp);
         chp->ch_flags |= ATACH_TH_RUN;          KASSERT(ata_is_thread_run(chp));
   
         /*          /*
          * Probe the drives.  Reset type to indicate to controllers           * Probe the drives.  Reset type to indicate to controllers
Line 460  atabus_thread(void *arg)
Line 458  atabus_thread(void *arg)
   
         ata_channel_lock(chp);          ata_channel_lock(chp);
         for (;;) {          for (;;) {
                 if ((chp->ch_flags & (ATACH_TH_RESET | ATACH_SHUTDOWN)) == 0 &&                  if ((chp->ch_flags & (ATACH_TH_RESET | ATACH_TH_DRIVE_RESET
                       | ATACH_TH_RECOVERY | ATACH_SHUTDOWN)) == 0 &&
                     (chq->queue_active == 0 || chq->queue_freeze == 0)) {                      (chq->queue_active == 0 || chq->queue_freeze == 0)) {
                         chp->ch_flags &= ~ATACH_TH_RUN;  
                         cv_wait(&chp->ch_thr_idle, &chp->ch_lock);                          cv_wait(&chp->ch_thr_idle, &chp->ch_lock);
                         chp->ch_flags |= ATACH_TH_RUN;  
                 }                  }
                 if (chp->ch_flags & ATACH_SHUTDOWN) {                  if (chp->ch_flags & ATACH_SHUTDOWN) {
                         break;                          break;
Line 476  atabus_thread(void *arg)
Line 473  atabus_thread(void *arg)
                         ata_channel_lock(chp);                          ata_channel_lock(chp);
                 }                  }
                 if (chp->ch_flags & ATACH_TH_RESET) {                  if (chp->ch_flags & ATACH_TH_RESET) {
                         /* ata_reset_channel() will unfreeze the channel */                          /* this will unfreeze the channel */
                         ata_channel_unlock(chp);                          ata_thread_run(chp, AT_WAIT,
                         s = splbio();                              ATACH_TH_RESET, ATACH_NODRIVE);
                         ata_reset_channel(chp, AT_WAIT | chp->ch_reset_flags);                  } else if (chp->ch_flags & ATACH_TH_DRIVE_RESET) {
                           /* this will unfreeze the channel */
                           for (i = 0; i < chp->ch_ndrives; i++) {
                                   struct ata_drive_datas *drvp;
   
                                   drvp = &chp->ch_drive[i];
   
                                   if (drvp->drive_flags & ATA_DRIVE_TH_RESET) {
                                           ata_thread_run(chp,
                                               AT_WAIT, ATACH_TH_DRIVE_RESET, i);
                                   }
                           }
                           chp->ch_flags &= ~ATACH_TH_DRIVE_RESET;
                   } else if (chp->ch_flags & ATACH_TH_RECOVERY) {
                           /*
                            * This will unfreeze the channel; drops locks during
                            * run, so must wrap in splbio()/splx() to avoid
                            * spurious interrupts. XXX MPSAFE
                            */
                           int s = splbio();
                           ata_thread_run(chp, AT_WAIT, ATACH_TH_RECOVERY,
                               chp->recovery_tfd);
                         splx(s);                          splx(s);
                         ata_channel_lock(chp);  
                 } else if (chq->queue_active > 0 && chq->queue_freeze == 1) {                  } else if (chq->queue_active > 0 && chq->queue_freeze == 1) {
                         /*                          /*
                          * Caller has bumped queue_freeze, decrease it. This                           * Caller has bumped queue_freeze, decrease it. This
Line 509  atabus_thread(void *arg)
Line 526  atabus_thread(void *arg)
                         }                          }
                 } else if (chq->queue_freeze > 1)                  } else if (chq->queue_freeze > 1)
                         panic("%s: queue_freeze", __func__);                          panic("%s: queue_freeze", __func__);
   
                   /* Try to run down the queue once channel is unfrozen */
                   if (chq->queue_freeze == 0) {
                           ata_channel_unlock(chp);
                           atastart(chp);
                           ata_channel_lock(chp);
                   }
         }          }
         chp->ch_thread = NULL;          chp->ch_thread = NULL;
         cv_signal(&chp->ch_thr_idle);          cv_signal(&chp->ch_thr_idle);
Line 516  atabus_thread(void *arg)
Line 540  atabus_thread(void *arg)
         kthread_exit(0);          kthread_exit(0);
 }  }
   
   bool
   ata_is_thread_run(struct ata_channel *chp)
   {
           KASSERT(mutex_owned(&chp->ch_lock));
   
           return (chp->ch_thread == curlwp && !cpu_intr_p());
   }
   
 static void  static void
 ata_thread_wake_locked(struct ata_channel *chp)  ata_thread_wake_locked(struct ata_channel *chp)
 {  {
Line 569  atabus_attach(device_t parent, device_t 
Line 601  atabus_attach(device_t parent, device_t 
   
         RUN_ONCE(&ata_init_ctrl, atabus_init);          RUN_ONCE(&ata_init_ctrl, atabus_init);
   
         initq = malloc(sizeof(*initq), M_DEVBUF, M_WAITOK);          initq = kmem_zalloc(sizeof(*initq), KM_SLEEP);
         initq->atabus_sc = sc;          initq->atabus_sc = sc;
         mutex_enter(&atabus_qlock);          mutex_enter(&atabus_qlock);
         TAILQ_INSERT_TAIL(&atabus_initq_head, initq, atabus_initq);          TAILQ_INSERT_TAIL(&atabus_initq_head, initq, atabus_initq);
         mutex_exit(&atabus_qlock);          mutex_exit(&atabus_qlock);
         config_pending_incr(sc->sc_dev);          config_pending_incr(sc->sc_dev);
   
           /* XXX MPSAFE - no KTHREAD_MPSAFE, so protected by KERNEL_LOCK() */
         if ((error = kthread_create(PRI_NONE, 0, NULL, atabus_thread, sc,          if ((error = kthread_create(PRI_NONE, 0, NULL, atabus_thread, sc,
             &chp->ch_thread, "%s", device_xname(self))) != 0)              &chp->ch_thread, "%s", device_xname(self))) != 0)
                 aprint_error_dev(self,                  aprint_error_dev(self,
Line 598  atabus_detach(device_t self, int flags)
Line 631  atabus_detach(device_t self, int flags)
         device_t dev = NULL;          device_t dev = NULL;
         int i, error = 0;          int i, error = 0;
   
         /* Shutdown the channel. */  
         ata_channel_lock(chp);  
         chp->ch_flags |= ATACH_SHUTDOWN;  
         while (chp->ch_thread != NULL) {  
                 cv_signal(&chp->ch_thr_idle);  
                 cv_wait(&chp->ch_thr_idle, &chp->ch_lock);  
         }  
         ata_channel_unlock(chp);  
   
         /*          /*
          * Detach atapibus and its children.           * Detach atapibus and its children.
          */           */
Line 641  atabus_detach(device_t self, int flags)
Line 665  atabus_detach(device_t self, int flags)
                         KASSERT(chp->ch_drive[i].drive_type == 0);                          KASSERT(chp->ch_drive[i].drive_type == 0);
                 }                  }
         }          }
   
           /* Shutdown the channel. */
           ata_channel_lock(chp);
           chp->ch_flags |= ATACH_SHUTDOWN;
           while (chp->ch_thread != NULL) {
                   cv_signal(&chp->ch_thr_idle);
                   cv_wait(&chp->ch_thr_idle, &chp->ch_lock);
           }
           ata_channel_unlock(chp);
   
         atabus_free_drives(chp);          atabus_free_drives(chp);
   
  out:   out:
Line 716  atabus_alloc_drives(struct ata_channel *
Line 750  atabus_alloc_drives(struct ata_channel *
         if (chp->ch_ndrives != ndrives)          if (chp->ch_ndrives != ndrives)
                 atabus_free_drives(chp);                  atabus_free_drives(chp);
         if (chp->ch_drive == NULL) {          if (chp->ch_drive == NULL) {
                 chp->ch_drive = malloc(                  chp->ch_drive = kmem_zalloc(
                     sizeof(struct ata_drive_datas) * ndrives,                      sizeof(struct ata_drive_datas) * ndrives, KM_NOSLEEP);
                     M_DEVBUF, M_NOWAIT | M_ZERO);  
         }          }
         if (chp->ch_drive == NULL) {          if (chp->ch_drive == NULL) {
             aprint_error_dev(chp->ch_atac->atac_dev,              aprint_error_dev(chp->ch_atac->atac_dev,
Line 761  atabus_free_drives(struct ata_channel *c
Line 794  atabus_free_drives(struct ata_channel *c
   
         if (chp->ch_drive == NULL)          if (chp->ch_drive == NULL)
                 return;                  return;
           kmem_free(chp->ch_drive,
               sizeof(struct ata_drive_datas) * chp->ch_ndrives);
         chp->ch_ndrives = 0;          chp->ch_ndrives = 0;
         free(chp->ch_drive, M_DEVBUF);  
         chp->ch_drive = NULL;          chp->ch_drive = NULL;
 }  }
   
Line 780  ata_get_params(struct ata_drive_datas *d
Line 814  ata_get_params(struct ata_drive_datas *d
   
         ATADEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);          ATADEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
   
         xfer = ata_get_xfer(chp);          xfer = ata_get_xfer(chp, false);
         if (xfer == NULL) {          if (xfer == NULL) {
                 ATADEBUG_PRINT(("%s: no xfer\n", __func__),                  ATADEBUG_PRINT(("%s: no xfer\n", __func__),
                     DEBUG_FUNCS|DEBUG_PROBE);                      DEBUG_FUNCS|DEBUG_PROBE);
Line 885  ata_set_mode(struct ata_drive_datas *drv
Line 919  ata_set_mode(struct ata_drive_datas *drv
   
         ATADEBUG_PRINT(("ata_set_mode=0x%x\n", mode), DEBUG_FUNCS);          ATADEBUG_PRINT(("ata_set_mode=0x%x\n", mode), DEBUG_FUNCS);
   
         xfer = ata_get_xfer(chp);          xfer = ata_get_xfer(chp, false);
         if (xfer == NULL) {          if (xfer == NULL) {
                 ATADEBUG_PRINT(("%s: no xfer\n", __func__),                  ATADEBUG_PRINT(("%s: no xfer\n", __func__),
                     DEBUG_FUNCS|DEBUG_PROBE);                      DEBUG_FUNCS|DEBUG_PROBE);
Line 916  out:
Line 950  out:
         return rv;          return rv;
 }  }
   
 int  
 ata_read_log_ext_ncq(struct ata_drive_datas *drvp, uint8_t flags,  
     uint8_t *slot, uint8_t *status, uint8_t *err)  
 {  
         struct ata_xfer *xfer;  
         int rv;  
         struct ata_channel *chp = drvp->chnl_softc;  
         struct atac_softc *atac = chp->ch_atac;  
         uint8_t *tb, cksum, page;  
   
         ATADEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);  
   
         /* Only NCQ ATA drives support/need this */  
         if (drvp->drive_type != ATA_DRIVET_ATA ||  
             (drvp->drive_flags & ATA_DRIVE_NCQ) == 0)  
                 return EOPNOTSUPP;  
   
         xfer = ata_get_xfer_ext(chp, C_RECOVERY, 0);  
   
         tb = drvp->recovery_blk;  
         memset(tb, 0, sizeof(drvp->recovery_blk));  
   
         /*  
          * We could use READ LOG DMA EXT if drive supports it (i.e.  
          * when it supports Streaming feature) to avoid PIO command,  
          * and to make this a little faster. Realistically, it  
          * should not matter.  
          */  
         xfer->c_flags |= C_RECOVERY;  
         xfer->c_ata_c.r_command = WDCC_READ_LOG_EXT;  
         xfer->c_ata_c.r_lba = page = WDCC_LOG_PAGE_NCQ;  
         xfer->c_ata_c.r_st_bmask = WDCS_DRDY;  
         xfer->c_ata_c.r_st_pmask = WDCS_DRDY;  
         xfer->c_ata_c.r_count = 1;  
         xfer->c_ata_c.r_device = WDSD_LBA;  
         xfer->c_ata_c.flags = AT_READ | AT_LBA | AT_LBA48 | flags;  
         xfer->c_ata_c.timeout = 1000; /* 1s */  
         xfer->c_ata_c.data = tb;  
         xfer->c_ata_c.bcount = sizeof(drvp->recovery_blk);  
   
         if ((*atac->atac_bustype_ata->ata_exec_command)(drvp,  
                                                 xfer) != ATACMD_COMPLETE) {  
                 rv = EAGAIN;  
                 goto out;  
         }  
         if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {  
                 rv = EINVAL;  
                 goto out;  
         }  
   
         cksum = 0;  
         for (int i = 0; i < sizeof(drvp->recovery_blk); i++)  
                 cksum += tb[i];  
         if (cksum != 0) {  
                 aprint_error_dev(drvp->drv_softc,  
                     "invalid checksum %x for READ LOG EXT page %x\n",  
                     cksum, page);  
                 rv = EINVAL;  
                 goto out;  
         }  
   
         if (tb[0] & WDCC_LOG_NQ) {  
                 /* not queued command */  
                 rv = EOPNOTSUPP;  
                 goto out;  
         }  
   
         *slot = tb[0] & 0x1f;  
         *status = tb[2];  
         *err = tb[3];  
   
         KASSERTMSG((*status & WDCS_ERR),  
             "%s: non-error command slot %d reported by READ LOG EXT page %x: "  
             "err %x status %x\n",  
             device_xname(drvp->drv_softc), *slot, page, *err, *status);  
   
         rv = 0;  
   
 out:  
         ata_free_xfer(chp, xfer);  
         return rv;  
 }  
   
 #if NATA_DMA  #if NATA_DMA
 void  void
 ata_dmaerr(struct ata_drive_datas *drvp, int flags)  ata_dmaerr(struct ata_drive_datas *drvp, int flags)
 {  {
           ata_channel_lock_owned(drvp->chnl_softc);
   
         /*          /*
          * Downgrade decision: if we get NERRS_MAX in NXFER.           * Downgrade decision: if we get NERRS_MAX in NXFER.
          * We start with n_dmaerrs set to NERRS_MAX-1 so that the           * We start with n_dmaerrs set to NERRS_MAX-1 so that the
Line 1061  ata_exec_xfer(struct ata_channel *chp, s
Line 1014  ata_exec_xfer(struct ata_channel *chp, s
          * Standard commands are added to the end of command list, but           * Standard commands are added to the end of command list, but
          * recovery commands must be run immediatelly.           * recovery commands must be run immediatelly.
          */           */
         if ((xfer->c_flags & C_RECOVERY) == 0)          if ((xfer->c_flags & C_SKIP_QUEUE) == 0)
                 TAILQ_INSERT_TAIL(&chp->ch_queue->queue_xfer, xfer,                  SIMPLEQ_INSERT_TAIL(&chp->ch_queue->queue_xfer, xfer,
                     c_xferchain);                      c_xferchain);
         else          else
                 TAILQ_INSERT_HEAD(&chp->ch_queue->queue_xfer, xfer,                  SIMPLEQ_INSERT_HEAD(&chp->ch_queue->queue_xfer, xfer,
                     c_xferchain);                      c_xferchain);
   
         /*          /*
Line 1073  ata_exec_xfer(struct ata_channel *chp, s
Line 1026  ata_exec_xfer(struct ata_channel *chp, s
          */           */
         if ((xfer->c_flags & (C_POLL | C_WAIT)) ==  (C_POLL | C_WAIT)) {          if ((xfer->c_flags & (C_POLL | C_WAIT)) ==  (C_POLL | C_WAIT)) {
                 while (chp->ch_queue->queue_active > 0 ||                  while (chp->ch_queue->queue_active > 0 ||
                     TAILQ_FIRST(&chp->ch_queue->queue_xfer) != xfer) {                      SIMPLEQ_FIRST(&chp->ch_queue->queue_xfer) != xfer) {
                         xfer->c_flags |= C_WAITACT;                          xfer->c_flags |= C_WAITACT;
                         cv_wait(&xfer->c_active, &chp->ch_lock);                          cv_wait(&chp->ch_queue->c_active, &chp->ch_lock);
                         xfer->c_flags &= ~C_WAITACT;                          xfer->c_flags &= ~C_WAITACT;
                   }
   
                         /*                  /*
                          * Free xfer now if it there was attempt to free it                   * Free xfer now if it there was attempt to free it
                          * while we were waiting.                   * while we were waiting.
                          */                   */
                         if ((xfer->c_flags & (C_FREE|C_WAITTIMO)) == C_FREE) {                  if ((xfer->c_flags & (C_FREE|C_WAITTIMO)) == C_FREE) {
                                 ata_channel_unlock(chp);                          ata_channel_unlock(chp);
   
                                 ata_free_xfer(chp, xfer);                          ata_free_xfer(chp, xfer);
                                 return;                          return;
                         }  
                 }                  }
         }          }
   
Line 1104  ata_exec_xfer(struct ata_channel *chp, s
Line 1057  ata_exec_xfer(struct ata_channel *chp, s
  * are shared.   * are shared.
  *   *
  * MUST BE CALLED AT splbio()!   * MUST BE CALLED AT splbio()!
    *
    * XXX FIS-based switching with PMP
    * Currently atastart() never schedules concurrent NCQ transfers to more than
    * one drive, even when channel has several SATA drives attached via PMP.
    * To support concurrent transfers to different drives with PMP, it would be
    * necessary to implement FIS-based switching support in controller driver,
    * and then adjust error handling and recovery to stop assuming at most
    * one active drive.
  */   */
 void  void
 atastart(struct ata_channel *chp)  atastart(struct ata_channel *chp)
Line 1111  atastart(struct ata_channel *chp)
Line 1072  atastart(struct ata_channel *chp)
         struct atac_softc *atac = chp->ch_atac;          struct atac_softc *atac = chp->ch_atac;
         struct ata_queue *chq = chp->ch_queue;          struct ata_queue *chq = chp->ch_queue;
         struct ata_xfer *xfer, *axfer;          struct ata_xfer *xfer, *axfer;
         bool recovery;          bool skipq;
   
 #ifdef ATA_DEBUG  #ifdef ATA_DEBUG
         int spl1, spl2;          int spl1, spl2;
Line 1129  atastart(struct ata_channel *chp)
Line 1090  atastart(struct ata_channel *chp)
         ata_channel_lock(chp);          ata_channel_lock(chp);
   
 again:  again:
         KASSERT(chq->queue_active <= chq->queue_openings);          /* is there a xfer ? */
         if (chq->queue_active == chq->queue_openings) {          if ((xfer = SIMPLEQ_FIRST(&chp->ch_queue->queue_xfer)) == NULL) {
                 ATADEBUG_PRINT(("%s(chp=%p): channel %d completely busy\n",                  ATADEBUG_PRINT(("%s(chp=%p): channel %d queue_xfer is empty\n",
                     __func__, chp, chp->ch_channel), DEBUG_XFERS);                      __func__, chp, chp->ch_channel), DEBUG_XFERS);
                 goto out;                  goto out;
         }          }
   
         /* is there a xfer ? */          /*
         if ((xfer = TAILQ_FIRST(&chp->ch_queue->queue_xfer)) == NULL) {           * if someone is waiting for the command to be active, wake it up
                 ATADEBUG_PRINT(("%s(chp=%p): channel %d queue_xfer is empty\n",           * and let it process the command
                     __func__, chp, chp->ch_channel), DEBUG_XFERS);           */
           if (__predict_false(xfer->c_flags & C_WAITACT)) {
                   ATADEBUG_PRINT(("atastart: xfer %p channel %d drive %d "
                       "wait active\n", xfer, chp->ch_channel, xfer->c_drive),
                       DEBUG_XFERS);
                   cv_broadcast(&chp->ch_queue->c_active);
                 goto out;                  goto out;
         }          }
   
         recovery = ISSET(xfer->c_flags, C_RECOVERY);          skipq = ISSET(xfer->c_flags, C_SKIP_QUEUE);
   
         /* is the queue frozen? */          /* is the queue frozen? */
         if (__predict_false(!recovery && chq->queue_freeze > 0)) {          if (__predict_false(!skipq && chq->queue_freeze > 0)) {
                 if (chq->queue_flags & QF_IDLE_WAIT) {                  if (chq->queue_flags & QF_IDLE_WAIT) {
                         chq->queue_flags &= ~QF_IDLE_WAIT;                          chq->queue_flags &= ~QF_IDLE_WAIT;
                         cv_signal(&chp->ch_queue->queue_idle);                          cv_signal(&chp->ch_queue->queue_idle);
                 }                  }
                 ATADEBUG_PRINT(("%s(chp=%p): channel %d drive %d "                  ATADEBUG_PRINT(("%s(chp=%p): channel %d drive %d "
                     "queue frozen: %d (recovery: %d)\n",                      "queue frozen: %d\n",
                     __func__, chp, chp->ch_channel, xfer->c_drive,                      __func__, chp, chp->ch_channel, xfer->c_drive,
                     chq->queue_freeze, recovery),                      chq->queue_freeze),
                     DEBUG_XFERS);                      DEBUG_XFERS);
                 goto out;                  goto out;
         }          }
Line 1170  again:
Line 1136  again:
          * Need only check first xfer.           * Need only check first xfer.
          * XXX FIS-based switching - revisit           * XXX FIS-based switching - revisit
          */           */
         if (!recovery && (axfer = TAILQ_FIRST(&chp->ch_queue->active_xfers))) {          if (!skipq && (axfer = TAILQ_FIRST(&chp->ch_queue->active_xfers))) {
                 if (!ISSET(xfer->c_flags, C_NCQ) ||                  if (!ISSET(xfer->c_flags, C_NCQ) ||
                     !ISSET(axfer->c_flags, C_NCQ) ||                      !ISSET(axfer->c_flags, C_NCQ) ||
                     xfer->c_drive != axfer->c_drive)                      xfer->c_drive != axfer->c_drive)
Line 1180  again:
Line 1146  again:
         struct ata_drive_datas * const drvp = &chp->ch_drive[xfer->c_drive];          struct ata_drive_datas * const drvp = &chp->ch_drive[xfer->c_drive];
   
         /*          /*
          * if someone is waiting for the command to be active, wake it up           * Are we on limit of active xfers ? If the queue has more
          * and let it process the command           * than 1 openings, we keep one slot reserved for recovery or dump.
          */           */
         if (xfer->c_flags & C_WAITACT) {          KASSERT(chq->queue_active <= chq->queue_openings);
                 ATADEBUG_PRINT(("atastart: xfer %p channel %d drive %d "          const uint8_t chq_openings = (!skipq && chq->queue_openings > 1)
                     "wait active\n", xfer, chp->ch_channel, xfer->c_drive),              ? (chq->queue_openings - 1) : chq->queue_openings;
                     DEBUG_XFERS);          const uint8_t drv_openings = ISSET(xfer->c_flags, C_NCQ)
                 cv_signal(&xfer->c_active);              ? drvp->drv_openings : ATA_MAX_OPENINGS;
           if (chq->queue_active >= MIN(chq_openings, drv_openings)) {
                   if (skipq) {
                           panic("%s: channel %d busy, xfer not possible",
                               __func__, chp->ch_channel);
                   }
   
                   ATADEBUG_PRINT(("%s(chp=%p): channel %d completely busy\n",
                       __func__, chp, chp->ch_channel), DEBUG_XFERS);
                 goto out;                  goto out;
         }          }
   
         if (atac->atac_claim_hw)          /* Slot allocation can fail if drv_openings < ch_openings */
                 if (!atac->atac_claim_hw(chp, 0))          if (!ata_queue_alloc_slot(chp, &xfer->c_slot, drv_openings))
                   goto out;
   
           if (__predict_false(atac->atac_claim_hw)) {
                   if (!atac->atac_claim_hw(chp, 0)) {
                           ata_queue_free_slot(chp, xfer->c_slot);
                         goto out;                          goto out;
                   }
           }
   
           /* Now committed to start the xfer */
   
         ATADEBUG_PRINT(("%s(chp=%p): xfer %p channel %d drive %d\n",          ATADEBUG_PRINT(("%s(chp=%p): xfer %p channel %d drive %d\n",
             __func__, chp, xfer, chp->ch_channel, xfer->c_drive), DEBUG_XFERS);              __func__, chp, xfer, chp->ch_channel, xfer->c_drive), DEBUG_XFERS);
Line 1207  again:
Line 1190  again:
         else          else
                 CLR(chp->ch_flags, ATACH_NCQ);                  CLR(chp->ch_flags, ATACH_NCQ);
   
           SIMPLEQ_REMOVE_HEAD(&chq->queue_xfer, c_xferchain);
   
         ata_activate_xfer_locked(chp, xfer);          ata_activate_xfer_locked(chp, xfer);
   
         if (atac->atac_cap & ATAC_CAP_NOIRQ)          if (atac->atac_cap & ATAC_CAP_NOIRQ)
Line 1222  again:
Line 1207  again:
                 break;                  break;
         }          }
   
         /* Queue more commands if possible, but not during recovery */          /* Queue more commands if possible, but not during recovery or dump */
         if (!recovery && chq->queue_active < chq->queue_openings)          if (!skipq && chq->queue_active < chq->queue_openings)
                 goto again;                  goto again;
   
 out:  out:
Line 1238  ata_xfer_start(struct ata_xfer *xfer)
Line 1223  ata_xfer_start(struct ata_xfer *xfer)
   
         KASSERT(mutex_owned(&chp->ch_lock));          KASSERT(mutex_owned(&chp->ch_lock));
   
         rv = xfer->c_start(chp, xfer);          rv = xfer->ops->c_start(chp, xfer);
         switch (rv) {          switch (rv) {
         case ATASTART_STARTED:          case ATASTART_STARTED:
                 /* nothing to do */                  /* nothing to do */
Line 1250  ata_xfer_start(struct ata_xfer *xfer)
Line 1235  ata_xfer_start(struct ata_xfer *xfer)
         case ATASTART_POLL:          case ATASTART_POLL:
                 /* can happen even in thread context for some ATAPI devices */                  /* can happen even in thread context for some ATAPI devices */
                 ata_channel_unlock(chp);                  ata_channel_unlock(chp);
                 KASSERT(xfer->c_poll != NULL);                  KASSERT(xfer->ops != NULL && xfer->ops->c_poll != NULL);
                 xfer->c_poll(chp, xfer);                  xfer->ops->c_poll(chp, xfer);
                 ata_channel_lock(chp);                  ata_channel_lock(chp);
                 break;                  break;
         case ATASTART_ABORT:          case ATASTART_ABORT:
                 ata_channel_unlock(chp);                  ata_channel_unlock(chp);
                 KASSERT(xfer->c_abort != NULL);                  KASSERT(xfer->ops != NULL && xfer->ops->c_abort != NULL);
                 xfer->c_abort(chp, xfer);                  xfer->ops->c_abort(chp, xfer);
                 ata_channel_lock(chp);                  ata_channel_lock(chp);
                 break;                  break;
         }          }
Line 1271  ata_activate_xfer_locked(struct ata_chan
Line 1256  ata_activate_xfer_locked(struct ata_chan
         struct ata_queue * const chq = chp->ch_queue;          struct ata_queue * const chq = chp->ch_queue;
   
         KASSERT(mutex_owned(&chp->ch_lock));          KASSERT(mutex_owned(&chp->ch_lock));
   
         KASSERT(chq->queue_active < chq->queue_openings);  
         KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0);          KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0);
   
         TAILQ_REMOVE(&chq->queue_xfer, xfer, c_xferchain);          if ((xfer->c_flags & C_SKIP_QUEUE) == 0)
         if ((xfer->c_flags & C_RECOVERY) == 0)  
                 TAILQ_INSERT_TAIL(&chq->active_xfers, xfer, c_activechain);                  TAILQ_INSERT_TAIL(&chq->active_xfers, xfer, c_activechain);
         else {          else {
                 /*                  /*
Line 1290  ata_activate_xfer_locked(struct ata_chan
Line 1272  ata_activate_xfer_locked(struct ata_chan
         chq->queue_active++;          chq->queue_active++;
 }  }
   
   /*
    * Does it's own locking, does not require splbio().
    * flags - whether to block waiting for free xfer
    */
   struct ata_xfer *
   ata_get_xfer(struct ata_channel *chp, bool waitok)
   {
           return pool_get(&ata_xfer_pool,
               PR_ZERO | (waitok ? PR_WAITOK : PR_NOWAIT));
   }
   
   /*
    * ata_deactivate_xfer() must be always called prior to ata_free_xfer()
    */
   void
   ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
   {
           struct ata_queue *chq = chp->ch_queue;
   
           ata_channel_lock(chp);
   
           if (__predict_false(xfer->c_flags & (C_WAITACT|C_WAITTIMO))) {
                   /* Someone is waiting for this xfer, so we can't free now */
                   xfer->c_flags |= C_FREE;
                   cv_broadcast(&chq->c_active);
                   ata_channel_unlock(chp);
                   return;
           }
   
           /* XXX move PIOBM and free_gw to deactivate? */
   #if NATA_PIOBM          /* XXX wdc dependent code */
           if (__predict_false(xfer->c_flags & C_PIOBM)) {
                   struct wdc_softc *wdc = CHAN_TO_WDC(chp);
   
                   /* finish the busmastering PIO */
                   (*wdc->piobm_done)(wdc->dma_arg,
                       chp->ch_channel, xfer->c_drive);
                   chp->ch_flags &= ~(ATACH_DMA_WAIT | ATACH_PIOBM_WAIT | ATACH_IRQ_WAIT);
           }
   #endif
   
           if (__predict_false(chp->ch_atac->atac_free_hw))
                   chp->ch_atac->atac_free_hw(chp);
   
           ata_channel_unlock(chp);
   
           if (__predict_true(!ISSET(xfer->c_flags, C_PRIVATE_ALLOC)))
                   pool_put(&ata_xfer_pool, xfer);
   }
   
 void  void
 ata_deactivate_xfer(struct ata_channel *chp, struct ata_xfer *xfer)  ata_deactivate_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
 {  {
Line 1300  ata_deactivate_xfer(struct ata_channel *
Line 1332  ata_deactivate_xfer(struct ata_channel *
         KASSERT(chq->queue_active > 0);          KASSERT(chq->queue_active > 0);
         KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) != 0);          KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) != 0);
   
         callout_stop(&xfer->c_timo_callout);          /* Stop only when this is last active xfer */
           if (chq->queue_active == 1)
                   callout_stop(&chp->c_timo_callout);
   
         if (callout_invoking(&xfer->c_timo_callout))          if (callout_invoking(&chp->c_timo_callout))
                 xfer->c_flags |= C_WAITTIMO;                  xfer->c_flags |= C_WAITTIMO;
   
         TAILQ_REMOVE(&chq->active_xfers, xfer, c_activechain);          TAILQ_REMOVE(&chq->active_xfers, xfer, c_activechain);
         chq->active_xfers_used &= ~__BIT(xfer->c_slot);          chq->active_xfers_used &= ~__BIT(xfer->c_slot);
         chq->queue_active--;          chq->queue_active--;
   
           ata_queue_free_slot(chp, xfer->c_slot);
   
           if (xfer->c_flags & C_WAIT)
                   cv_broadcast(&chq->c_cmd_finish);
   
         ata_channel_unlock(chp);          ata_channel_unlock(chp);
 }  }
   
Line 1332  ata_waitdrain_xfer_check(struct ata_chan
Line 1371  ata_waitdrain_xfer_check(struct ata_chan
         if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {          if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
                 ata_channel_unlock(chp);                  ata_channel_unlock(chp);
   
                 (*xfer->c_kill_xfer)(chp, xfer, KILL_GONE);                  xfer->ops->c_kill_xfer(chp, xfer, KILL_GONE);
   
                 ata_channel_lock(chp);                  ata_channel_lock(chp);
                 chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;                  chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
Line 1356  ata_timo_xfer_check(struct ata_xfer *xfe
Line 1395  ata_timo_xfer_check(struct ata_xfer *xfe
   
         ata_channel_lock(chp);          ata_channel_lock(chp);
   
         callout_ack(&xfer->c_timo_callout);  
   
         if (xfer->c_flags & C_WAITTIMO) {          if (xfer->c_flags & C_WAITTIMO) {
                 xfer->c_flags &= ~C_WAITTIMO;                  xfer->c_flags &= ~C_WAITTIMO;
   
Line 1366  ata_timo_xfer_check(struct ata_xfer *xfe
Line 1403  ata_timo_xfer_check(struct ata_xfer *xfe
                         xfer->c_flags &= ~C_FREE;                          xfer->c_flags &= ~C_FREE;
                         ata_channel_unlock(chp);                          ata_channel_unlock(chp);
   
                         aprint_normal_dev(drvp->drv_softc,                          device_printf(drvp->drv_softc,
                             "xfer %d freed while invoking timeout\n",                              "xfer %"PRIxPTR" freed while invoking timeout\n",
                             xfer->c_slot);                              (intptr_t)xfer & PAGE_MASK);
   
                         ata_free_xfer(chp, xfer);                          ata_free_xfer(chp, xfer);
                         return true;                          return true;
Line 1377  ata_timo_xfer_check(struct ata_xfer *xfe
Line 1414  ata_timo_xfer_check(struct ata_xfer *xfe
                 /* Race vs. callout_stop() in ata_deactivate_xfer() */                  /* Race vs. callout_stop() in ata_deactivate_xfer() */
                 ata_channel_unlock(chp);                  ata_channel_unlock(chp);
   
                 aprint_normal_dev(drvp->drv_softc,                  device_printf(drvp->drv_softc,
                     "xfer %d deactivated while invoking timeout\n",                      "xfer %"PRIxPTR" deactivated while invoking timeout\n",
                     xfer->c_slot);                      (intptr_t)xfer & PAGE_MASK);
                 return true;                  return true;
         }          }
   
Line 1389  ata_timo_xfer_check(struct ata_xfer *xfe
Line 1426  ata_timo_xfer_check(struct ata_xfer *xfe
         return false;          return false;
 }  }
   
 void  
 ata_timeout(void *v)  
 {  
         struct ata_xfer *xfer = v;  
         int s;  
   
         ATADEBUG_PRINT(("%s: slot %d\n", __func__, xfer->c_slot),  
             DEBUG_FUNCS|DEBUG_XFERS);  
   
         s = splbio();                           /* XXX MPSAFE */  
   
         if (ata_timo_xfer_check(xfer)) {  
                 /* Already logged */  
                 goto out;  
         }  
   
         /* Mark as timed out. Do not print anything, wd(4) will. */  
         xfer->c_flags |= C_TIMEOU;  
         xfer->c_intr(xfer->c_chp, xfer, 0);  
   
 out:  
         splx(s);  
 }  
   
 /*  /*
  * Kill off all active xfers for a ata_channel.   * Kill off all active xfers for a ata_channel.
  *   *
Line 1427  ata_kill_active(struct ata_channel *chp,
Line 1440  ata_kill_active(struct ata_channel *chp,
         KASSERT(mutex_owned(&chp->ch_lock));          KASSERT(mutex_owned(&chp->ch_lock));
   
         TAILQ_FOREACH_SAFE(xfer, &chq->active_xfers, c_activechain, xfernext) {          TAILQ_FOREACH_SAFE(xfer, &chq->active_xfers, c_activechain, xfernext) {
                 (*xfer->c_kill_xfer)(xfer->c_chp, xfer, reason);                  ata_channel_unlock(chp);
                   xfer->ops->c_kill_xfer(xfer->c_chp, xfer, reason);
                   ata_channel_lock(chp);
         }          }
   
         if (flags & AT_RST_EMERG)  
                 ata_queue_reset(chq);  
 }  }
   
 /*  /*
Line 1442  ata_kill_pending(struct ata_drive_datas 
Line 1454  ata_kill_pending(struct ata_drive_datas 
 {  {
         struct ata_channel * const chp = drvp->chnl_softc;          struct ata_channel * const chp = drvp->chnl_softc;
         struct ata_queue * const chq = chp->ch_queue;          struct ata_queue * const chq = chp->ch_queue;
         struct ata_xfer *xfer, *xfernext;          struct ata_xfer *xfer;
   
         ata_channel_lock(chp);          ata_channel_lock(chp);
   
         /* Kill all pending transfers */          /* Kill all pending transfers */
         TAILQ_FOREACH_SAFE(xfer, &chq->queue_xfer, c_xferchain, xfernext) {          while ((xfer = SIMPLEQ_FIRST(&chq->queue_xfer))) {
                 KASSERT(xfer->c_chp == chp);                  KASSERT(xfer->c_chp == chp);
   
                 if (xfer->c_drive != drvp->drive)                  if (xfer->c_drive != drvp->drive)
                         continue;                          continue;
   
                 TAILQ_REMOVE(&chp->ch_queue->queue_xfer, xfer, c_xferchain);                  SIMPLEQ_REMOVE_HEAD(&chp->ch_queue->queue_xfer, c_xferchain);
   
                 /*                  /*
                  * Keep the lock, so that we get deadlock (and 'locking against                   * Keep the lock, so that we get deadlock (and 'locking against
Line 1461  ata_kill_pending(struct ata_drive_datas 
Line 1473  ata_kill_pending(struct ata_drive_datas 
                  * data corruption, if the hook tries to call back into                   * data corruption, if the hook tries to call back into
                  * middle layer for inactive xfer.                   * middle layer for inactive xfer.
                  */                   */
                 (*xfer->c_kill_xfer)(chp, xfer, KILL_GONE_INACTIVE);                  xfer->ops->c_kill_xfer(chp, xfer, KILL_GONE_INACTIVE);
         }          }
   
         /* Wait until all active transfers on the drive finish */          /* Wait until all active transfers on the drive finish */
Line 1506  ata_channel_freeze(struct ata_channel *c
Line 1518  ata_channel_freeze(struct ata_channel *c
         ata_channel_unlock(chp);          ata_channel_unlock(chp);
 }  }
   
 static void  void
 ata_channel_thaw_locked(struct ata_channel *chp)  ata_channel_thaw_locked(struct ata_channel *chp)
 {  {
         KASSERT(mutex_owned(&chp->ch_lock));          KASSERT(mutex_owned(&chp->ch_lock));
Line 1518  ata_channel_thaw_locked(struct ata_chann
Line 1530  ata_channel_thaw_locked(struct ata_chann
             chp->ch_queue->queue_freeze), DEBUG_FUNCS | DEBUG_XFERS);              chp->ch_queue->queue_freeze), DEBUG_FUNCS | DEBUG_XFERS);
 }  }
   
 void  
 ata_channel_thaw(struct ata_channel *chp)  
 {  
         ata_channel_lock(chp);  
         ata_channel_thaw_locked(chp);  
         ata_channel_unlock(chp);  
 }  
   
 /*  /*
  * ata_reset_channel:   * ata_thread_run:
  *   *
  *      Reset and ATA channel.   *      Reset and ATA channel. Channel lock must be held. arg is type-specific.
  *  
  *      MUST BE CALLED AT splbio()!  
  */   */
 void  void
 ata_reset_channel(struct ata_channel *chp, int flags)  ata_thread_run(struct ata_channel *chp, int flags, int type, int arg)
 {  {
         struct atac_softc *atac = chp->ch_atac;          struct atac_softc *atac = chp->ch_atac;
         int drive;  
         bool threset = false;          bool threset = false;
           struct ata_drive_datas *drvp;
   
 #ifdef ATA_DEBUG          ata_channel_lock_owned(chp);
         int spl1, spl2;  
   
         spl1 = splbio();  
         spl2 = splbio();  
         if (spl2 != spl1) {  
                 printf("ata_reset_channel: not at splbio()\n");  
                 panic("ata_reset_channel");  
         }  
         splx(spl2);  
         splx(spl1);  
 #endif /* ATA_DEBUG */  
   
         ata_channel_lock(chp);  
   
         /*          /*
          * If we can poll or wait it's OK, otherwise wake up the           * If we can poll or wait it's OK, otherwise wake up the
          * kernel thread to do it for us.           * kernel thread to do it for us.
          */           */
         ATADEBUG_PRINT(("ata_reset_channel flags 0x%x ch_flags 0x%x\n",          ATADEBUG_PRINT(("%s flags 0x%x ch_flags 0x%x\n",
             flags, chp->ch_flags), DEBUG_FUNCS | DEBUG_XFERS);              __func__, flags, chp->ch_flags), DEBUG_FUNCS | DEBUG_XFERS);
         if ((flags & (AT_POLL | AT_WAIT)) == 0) {          if ((flags & (AT_POLL | AT_WAIT)) == 0) {
                 if (chp->ch_flags & ATACH_TH_RESET) {                  switch (type) {
                         /* No need to schedule a reset more than one time. */                  case ATACH_TH_RESET:
                         ata_channel_unlock(chp);                          if (chp->ch_flags & ATACH_TH_RESET) {
                         return;                                  /* No need to schedule another reset */
                                   return;
                           }
                           break;
                   case ATACH_TH_DRIVE_RESET:
                       {
                           int drive = arg;
   
                           KASSERT(drive <= chp->ch_ndrives);
                           drvp = &chp->ch_drive[drive];
   
                           if (drvp->drive_flags & ATA_DRIVE_TH_RESET) {
                                   /* No need to schedule another reset */
                                   return;
                           }
                           drvp->drive_flags |= ATA_DRIVE_TH_RESET;
                           break;
                       }
                   case ATACH_TH_RECOVERY:
                       {
                           uint32_t tfd = (uint32_t)arg;
   
                           KASSERT((chp->ch_flags & ATACH_RECOVERING) == 0);
                           chp->recovery_tfd = tfd;
                           break;
                       }
                   default:
                           panic("%s: unknown type: %x", __func__, type);
                           /* NOTREACHED */
                 }                  }
   
                 /*                  /*
Line 1573  ata_reset_channel(struct ata_channel *ch
Line 1590  ata_reset_channel(struct ata_channel *ch
                  * to a thread.                   * to a thread.
                  */                   */
                 ata_channel_freeze_locked(chp);                  ata_channel_freeze_locked(chp);
                 chp->ch_flags |= ATACH_TH_RESET;                  chp->ch_flags |= type;
                 chp->ch_reset_flags = flags & AT_RST_EMERG;  
                 cv_signal(&chp->ch_thr_idle);                  cv_signal(&chp->ch_thr_idle);
                 ata_channel_unlock(chp);  
                 return;                  return;
         }          }
   
Line 1588  ata_reset_channel(struct ata_channel *ch
Line 1604  ata_reset_channel(struct ata_channel *ch
          * the flag now so that the thread won't try to execute it if           * the flag now so that the thread won't try to execute it if
          * we happen to sleep, and thaw one more time after the reset.           * we happen to sleep, and thaw one more time after the reset.
          */           */
         if (chp->ch_flags & ATACH_TH_RESET) {          if (chp->ch_flags & type) {
                 chp->ch_flags &= ~ATACH_TH_RESET;                  chp->ch_flags &= ~type;
                 threset = true;                  threset = true;
         }          }
   
         ata_channel_unlock(chp);          switch (type) {
           case ATACH_TH_RESET:
                   (*atac->atac_bustype_ata->ata_reset_channel)(chp, flags);
   
         (*atac->atac_bustype_ata->ata_reset_channel)(chp, flags);                  KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
                   for (int drive = 0; drive < chp->ch_ndrives; drive++)
                           chp->ch_drive[drive].state = 0;
                   break;
   
         ata_channel_lock(chp);          case ATACH_TH_DRIVE_RESET:
         KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);              {
         for (drive = 0; drive < chp->ch_ndrives; drive++)                  int drive = arg;
                 chp->ch_drive[drive].state = 0;  
                   KASSERT(drive <= chp->ch_ndrives);
                   drvp = &chp->ch_drive[drive];
                   (*atac->atac_bustype_ata->ata_reset_drive)(drvp, flags, NULL);
                   drvp->state = 0;
                   break;
               }
   
           case ATACH_TH_RECOVERY:
               {
                   uint32_t tfd = (uint32_t)arg;
   
                   KASSERT((chp->ch_flags & ATACH_RECOVERING) == 0);
                   KASSERT(atac->atac_bustype_ata->ata_recovery != NULL);
   
                   SET(chp->ch_flags, ATACH_RECOVERING);
                   (*atac->atac_bustype_ata->ata_recovery)(chp, flags, tfd);
                   CLR(chp->ch_flags, ATACH_RECOVERING);
                   break;
               }
   
           default:
                   panic("%s: unknown type: %x", __func__, type);
                   /* NOTREACHED */
           }
   
         /*          /*
          * Thaw one extra time to clear the freeze done when the reset has           * Thaw one extra time to clear the freeze done when the reset has
Line 1614  ata_reset_channel(struct ata_channel *ch
Line 1659  ata_reset_channel(struct ata_channel *ch
   
         /* Signal the thread in case there is an xfer to run */          /* Signal the thread in case there is an xfer to run */
         cv_signal(&chp->ch_thr_idle);          cv_signal(&chp->ch_thr_idle);
   
         ata_channel_unlock(chp);  
   
         if (flags & AT_RST_EMERG) {  
                 /* make sure that we can use polled commands */  
                 ata_queue_reset(chp->ch_queue);  
         } else {  
                 atastart(chp);  
         }  
 }  }
   
 int  int
Line 1731  ata_downgrade_mode(struct ata_drive_data
Line 1767  ata_downgrade_mode(struct ata_drive_data
         device_t drv_dev = drvp->drv_softc;          device_t drv_dev = drvp->drv_softc;
         int cf_flags = device_cfdata(drv_dev)->cf_flags;          int cf_flags = device_cfdata(drv_dev)->cf_flags;
   
           ata_channel_lock_owned(drvp->chnl_softc);
   
         /* if drive or controller don't know its mode, we can't do much */          /* if drive or controller don't know its mode, we can't do much */
         if ((drvp->drive_flags & ATA_DRIVE_MODE) == 0 ||          if ((drvp->drive_flags & ATA_DRIVE_MODE) == 0 ||
             (atac->atac_set_modes == NULL))              (atac->atac_set_modes == NULL))
Line 1768  ata_downgrade_mode(struct ata_drive_data
Line 1806  ata_downgrade_mode(struct ata_drive_data
         (*atac->atac_set_modes)(chp);          (*atac->atac_set_modes)(chp);
         ata_print_modes(chp);          ata_print_modes(chp);
         /* reset the channel, which will schedule all drives for setup */          /* reset the channel, which will schedule all drives for setup */
         ata_reset_channel(chp, flags);          ata_thread_run(chp, flags, ATACH_TH_RESET, ATACH_NODRIVE);
         return 1;          return 1;
 }  }
 #endif  /* NATA_DMA */  #endif  /* NATA_DMA */
Line 1855  ata_probe_caps(struct ata_drive_datas *d
Line 1893  ata_probe_caps(struct ata_drive_datas *d
                          */                           */
                         if (atac->atac_set_modes)                          if (atac->atac_set_modes)
                                 /*                                  /*
                                  * It's OK to pool here, it's fast enough                                   * It's OK to poll here, it's fast enough
                                  * to not bother waiting for interrupt                                   * to not bother waiting for interrupt
                                  */                                   */
                                 if (ata_set_mode(drvp, 0x08 | (i + 3),                                  if (ata_set_mode(drvp, 0x08 | (i + 3),
Line 1994  ata_probe_caps(struct ata_drive_datas *d
Line 2032  ata_probe_caps(struct ata_drive_datas *d
 #if NATA_DMA  #if NATA_DMA
         if ((atac->atac_cap & ATAC_CAP_DMA) == 0) {          if ((atac->atac_cap & ATAC_CAP_DMA) == 0) {
                 /* don't care about DMA modes */                  /* don't care about DMA modes */
                   if (*sep != '\0')
                           aprint_verbose("\n");
                 return;                  return;
         }          }
         if (cf_flags & ATA_CONFIG_DMA_SET) {          if (cf_flags & ATA_CONFIG_DMA_SET) {
Line 2040  ata_probe_caps(struct ata_drive_datas *d
Line 2080  ata_probe_caps(struct ata_drive_datas *d
         }          }
         ata_channel_unlock(chp);          ata_channel_unlock(chp);
   
         if (printed)          if (*sep != '\0')
                 aprint_verbose("\n");                  aprint_verbose("\n");
   
 #if NATA_UDMA  #if NATA_UDMA
Line 2108  atabusioctl(dev_t dev, u_long cmd, void 
Line 2148  atabusioctl(dev_t dev, u_long cmd, void 
         struct ata_channel *chp = sc->sc_chan;          struct ata_channel *chp = sc->sc_chan;
         int min_drive, max_drive, drive;          int min_drive, max_drive, drive;
         int error;          int error;
         int s;  
   
         /*          /*
          * Enforce write permission for ioctls that change the           * Enforce write permission for ioctls that change the
Line 2125  atabusioctl(dev_t dev, u_long cmd, void 
Line 2164  atabusioctl(dev_t dev, u_long cmd, void 
   
         switch (cmd) {          switch (cmd) {
         case ATABUSIORESET:          case ATABUSIORESET:
                 s = splbio();                  ata_channel_lock(chp);
                 ata_reset_channel(sc->sc_chan, AT_WAIT | AT_POLL);                  ata_thread_run(sc->sc_chan, AT_WAIT | AT_POLL,
                 splx(s);                      ATACH_TH_RESET, ATACH_NODRIVE);
                   ata_channel_unlock(chp);
                 return 0;                  return 0;
         case ATABUSIOSCAN:          case ATABUSIOSCAN:
         {          {
Line 2205  atabus_resume(device_t dv, const pmf_qua
Line 2245  atabus_resume(device_t dv, const pmf_qua
         /* unfreeze the queue and reset drives */          /* unfreeze the queue and reset drives */
         ata_channel_thaw_locked(chp);          ata_channel_thaw_locked(chp);
   
         ata_channel_unlock(chp);  
   
         /* reset channel only if there are drives attached */          /* reset channel only if there are drives attached */
         if (chp->ch_ndrives > 0)          if (chp->ch_ndrives > 0)
                 ata_reset_channel(chp, AT_WAIT);                  ata_thread_run(chp, AT_WAIT, ATACH_TH_RESET, ATACH_NODRIVE);
   
           ata_channel_unlock(chp);
   
 out:  out:
         return true;          return true;
Line 2240  atabus_rescan(device_t self, const char 
Line 2280  atabus_rescan(device_t self, const char 
                 }                  }
         }          }
   
         initq = malloc(sizeof(*initq), M_DEVBUF, M_WAITOK);          initq = kmem_zalloc(sizeof(*initq), KM_SLEEP);
         initq->atabus_sc = sc;          initq->atabus_sc = sc;
         mutex_enter(&atabus_qlock);          mutex_enter(&atabus_qlock);
         TAILQ_INSERT_TAIL(&atabus_initq_head, initq, atabus_initq);          TAILQ_INSERT_TAIL(&atabus_initq_head, initq, atabus_initq);
Line 2258  atabus_rescan(device_t self, const char 
Line 2298  atabus_rescan(device_t self, const char 
 void  void
 ata_delay(struct ata_channel *chp, int ms, const char *msg, int flags)  ata_delay(struct ata_channel *chp, int ms, const char *msg, int flags)
 {  {
           KASSERT(mutex_owned(&chp->ch_lock));
   
         if ((flags & (AT_WAIT | AT_POLL)) == AT_POLL) {          if ((flags & (AT_WAIT | AT_POLL)) == AT_POLL) {
                 /*                  /*
Line 2268  ata_delay(struct ata_channel *chp, int m
Line 2309  ata_delay(struct ata_channel *chp, int m
         } else {          } else {
                 int pause = mstohz(ms);                  int pause = mstohz(ms);
   
                 KASSERT(mutex_owned(&chp->ch_lock));  
                 kpause(msg, false, pause > 0 ? pause : 1, &chp->ch_lock);                  kpause(msg, false, pause > 0 ? pause : 1, &chp->ch_lock);
         }          }
 }  }
Line 2304  atacmd_toncq(struct ata_xfer *xfer, uint
Line 2344  atacmd_toncq(struct ata_xfer *xfer, uint
 }  }
   
 void  void
 ata_wait_xfer(struct ata_channel *chp, struct ata_xfer *xfer)  ata_wait_cmd(struct ata_channel *chp, struct ata_xfer *xfer)
 {  {
         KASSERT(mutex_owned(&chp->ch_lock));          struct ata_queue *chq = chp->ch_queue;
           struct ata_command *ata_c = &xfer->c_ata_c;
   
         cv_wait(&xfer->c_finish, &chp->ch_lock);          ata_channel_lock(chp);
 }  
   
 void          while ((ata_c->flags & AT_DONE) == 0)
 ata_wake_xfer(struct ata_channel *chp, struct ata_xfer *xfer)                  cv_wait(&chq->c_cmd_finish, &chp->ch_lock);
 {  
         KASSERT(mutex_owned(&chp->ch_lock));          ata_channel_unlock(chp);
   
         cv_signal(&xfer->c_finish);          KASSERT((ata_c->flags & AT_DONE) != 0);
 }  }

Legend:
Removed from v.1.141  
changed lines
  Added in v.1.141.4.2

CVSweb <webmaster@jp.NetBSD.org>