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

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

Diff for /src/sys/dev/ic/ahcisata_core.c between version 1.62 and 1.62.2.9

version 1.62, 2018/07/09 10:44:44 version 1.62.2.9, 2018/10/11 20:57:51
Line 59  static void ahci_setup_channel(struct at
Line 59  static void ahci_setup_channel(struct at
   
 static int  ahci_ata_bio(struct ata_drive_datas *, struct ata_xfer *);  static int  ahci_ata_bio(struct ata_drive_datas *, struct ata_xfer *);
 static int  ahci_do_reset_drive(struct ata_channel *, int, int, uint32_t *,  static int  ahci_do_reset_drive(struct ata_channel *, int, int, uint32_t *,
         struct ata_xfer *xfer);          uint8_t);
 static void ahci_reset_drive(struct ata_drive_datas *, int, uint32_t *);  static void ahci_reset_drive(struct ata_drive_datas *, int, uint32_t *);
 static void ahci_reset_channel(struct ata_channel *, int);  static void ahci_reset_channel(struct ata_channel *, int);
 static int  ahci_exec_command(struct ata_drive_datas *, struct ata_xfer *);  static int  ahci_exec_command(struct ata_drive_datas *, struct ata_xfer *);
Line 569  ahci_intr_port(struct ahci_softc *sc, st
Line 569  ahci_intr_port(struct ahci_softc *sc, st
         struct ata_xfer *xfer;          struct ata_xfer *xfer;
         int slot = -1;          int slot = -1;
         bool recover = false;          bool recover = false;
           uint32_t aslots;
   
         is = AHCI_READ(sc, AHCI_P_IS(chp->ch_channel));          is = AHCI_READ(sc, AHCI_P_IS(chp->ch_channel));
         AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), is);          AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), is);
Line 622  ahci_intr_port(struct ahci_softc *sc, st
Line 623  ahci_intr_port(struct ahci_softc *sc, st
                             DEBUG_INTR);                              DEBUG_INTR);
                 }                  }
   
                 if (!achp->ahcic_recovering)                  if (!ISSET(chp->ch_flags, ATACH_RECOVERING))
                         recover = true;                          recover = true;
         } else if (is & (AHCI_P_IX_DHRS|AHCI_P_IX_SDBS)) {          } else if (is & (AHCI_P_IX_DHRS|AHCI_P_IX_SDBS)) {
                 tfd = AHCI_READ(sc, AHCI_P_TFD(chp->ch_channel));                  tfd = AHCI_READ(sc, AHCI_P_TFD(chp->ch_channel));
   
                 /* D2H Register FIS or Set Device Bits */                  /* D2H Register FIS or Set Device Bits */
                 if ((tfd & WDCS_ERR) != 0) {                  if ((tfd & WDCS_ERR) != 0) {
                         if (!achp->ahcic_recovering)                          if (!ISSET(chp->ch_flags, ATACH_RECOVERING))
                                 recover = true;                                  recover = true;
   
                         AHCIDEBUG_PRINT(("%s port %d: transfer aborted 0x%x\n",                          AHCIDEBUG_PRINT(("%s port %d: transfer aborted 0x%x\n",
Line 643  ahci_intr_port(struct ahci_softc *sc, st
Line 644  ahci_intr_port(struct ahci_softc *sc, st
         if (__predict_false(recover))          if (__predict_false(recover))
                 ata_channel_freeze(chp);                  ata_channel_freeze(chp);
   
           aslots = ata_queue_active(chp);
   
         if (slot >= 0) {          if (slot >= 0) {
                 if ((achp->ahcic_cmds_active & __BIT(slot)) != 0 &&                  if ((aslots & __BIT(slot)) != 0 &&
                     (sact & __BIT(slot)) == 0) {                      (sact & __BIT(slot)) == 0) {
                         xfer = ata_queue_hwslot_to_xfer(chp, slot);                          xfer = ata_queue_hwslot_to_xfer(chp, slot);
                         xfer->c_intr(chp, xfer, tfd);                          xfer->ops->c_intr(chp, xfer, tfd);
                 }                  }
         } else {          } else {
                 /*                  /*
Line 659  ahci_intr_port(struct ahci_softc *sc, st
Line 662  ahci_intr_port(struct ahci_softc *sc, st
                  * can activate another command(s), so must only process                   * can activate another command(s), so must only process
                  * commands active before we start processing.                   * commands active before we start processing.
                  */                   */
                 uint32_t aslots = achp->ahcic_cmds_active;  
   
                 for (slot=0; slot < sc->sc_ncmds; slot++) {                  for (slot=0; slot < sc->sc_ncmds; slot++) {
                         if ((aslots & __BIT(slot)) != 0 &&                          if ((aslots & __BIT(slot)) != 0 &&
                             (sact & __BIT(slot)) == 0) {                              (sact & __BIT(slot)) == 0) {
                                 xfer = ata_queue_hwslot_to_xfer(chp, slot);                                  xfer = ata_queue_hwslot_to_xfer(chp, slot);
                                 xfer->c_intr(chp, xfer, tfd);                                  xfer->ops->c_intr(chp, xfer, tfd);
                         }                          }
                 }                  }
         }          }
Line 681  ahci_reset_drive(struct ata_drive_datas 
Line 683  ahci_reset_drive(struct ata_drive_datas 
 {  {
         struct ata_channel *chp = drvp->chnl_softc;          struct ata_channel *chp = drvp->chnl_softc;
         struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;          struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
         struct ata_xfer *xfer;          uint8_t c_slot;
   
         xfer = ata_get_xfer_ext(chp, C_RECOVERY, 0);          ata_channel_lock_owned(chp);
   
         ata_channel_lock(chp);          /* get a slot for running the command on */
           if (!ata_queue_alloc_slot(chp, &c_slot, ATA_MAX_OPENINGS)) {
                   panic("%s: %s: failed to get xfer for reset, port %d\n",
                       device_xname(sc->sc_atac.atac_dev),
                       __func__, chp->ch_channel);
                   /* NOTREACHED */
           }
   
         AHCI_WRITE(sc, AHCI_GHC,          AHCI_WRITE(sc, AHCI_GHC,
             AHCI_READ(sc, AHCI_GHC) & ~AHCI_GHC_IE);              AHCI_READ(sc, AHCI_GHC) & ~AHCI_GHC_IE);
         ahci_channel_stop(sc, chp, flags);          ahci_channel_stop(sc, chp, flags);
         if (ahci_do_reset_drive(chp, drvp->drive, flags, sigp, xfer) != 0)          ahci_do_reset_drive(chp, drvp->drive, flags, sigp, c_slot);
                 ata_reset_channel(chp, flags);  
         AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE);          AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE);
   
         ata_channel_unlock(chp);          ata_queue_free_slot(chp, c_slot);
   
         ata_free_xfer(chp, xfer);  
   
         return;  
 }  }
   
 /* return error code from ata_bio */  /* return error code from ata_bio */
Line 755  ahci_exec_fis(struct ata_channel *chp, i
Line 758  ahci_exec_fis(struct ata_channel *chp, i
   
 static int  static int
 ahci_do_reset_drive(struct ata_channel *chp, int drive, int flags,  ahci_do_reset_drive(struct ata_channel *chp, int drive, int flags,
     uint32_t *sigp, struct ata_xfer *xfer)      uint32_t *sigp, uint8_t c_slot)
 {  {
         struct ahci_channel *achp = (struct ahci_channel *)chp;          struct ahci_channel *achp = (struct ahci_channel *)chp;
         struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;          struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
Line 790  again:
Line 793  again:
   
         /* polled command, assume interrupts are disabled */          /* polled command, assume interrupts are disabled */
   
         cmd_h = &achp->ahcic_cmdh[xfer->c_slot];          cmd_h = &achp->ahcic_cmdh[c_slot];
         cmd_tbl = achp->ahcic_cmd_tbl[xfer->c_slot];          cmd_tbl = achp->ahcic_cmd_tbl[c_slot];
         cmd_h->cmdh_flags = htole16(AHCI_CMDH_F_RST | AHCI_CMDH_F_CBSY |          cmd_h->cmdh_flags = htole16(AHCI_CMDH_F_RST | AHCI_CMDH_F_CBSY |
             RHD_FISLEN / 4 | (drive << AHCI_CMDH_F_PMP_SHIFT));              RHD_FISLEN / 4 | (drive << AHCI_CMDH_F_PMP_SHIFT));
         cmd_h->cmdh_prdbc = 0;          cmd_h->cmdh_prdbc = 0;
Line 799  again:
Line 802  again:
         cmd_tbl->cmdt_cfis[fis_type] = RHD_FISTYPE;          cmd_tbl->cmdt_cfis[fis_type] = RHD_FISTYPE;
         cmd_tbl->cmdt_cfis[rhd_c] = drive;          cmd_tbl->cmdt_cfis[rhd_c] = drive;
         cmd_tbl->cmdt_cfis[rhd_control] = WDCTL_RST;          cmd_tbl->cmdt_cfis[rhd_control] = WDCTL_RST;
         switch(ahci_exec_fis(chp, 100, flags, xfer->c_slot)) {          switch(ahci_exec_fis(chp, 100, flags, c_slot)) {
         case ERR_DF:          case ERR_DF:
         case TIMEOUT:          case TIMEOUT:
                 aprint_error("%s channel %d: setting WDCTL_RST failed "                  aprint_error("%s channel %d: setting WDCTL_RST failed "
Line 817  again:
Line 820  again:
         cmd_tbl->cmdt_cfis[fis_type] = RHD_FISTYPE;          cmd_tbl->cmdt_cfis[fis_type] = RHD_FISTYPE;
         cmd_tbl->cmdt_cfis[rhd_c] = drive;          cmd_tbl->cmdt_cfis[rhd_c] = drive;
         cmd_tbl->cmdt_cfis[rhd_control] = 0;          cmd_tbl->cmdt_cfis[rhd_control] = 0;
         switch(ahci_exec_fis(chp, 310, flags, xfer->c_slot)) {          switch(ahci_exec_fis(chp, 310, flags, c_slot)) {
         case ERR_DF:          case ERR_DF:
         case TIMEOUT:          case TIMEOUT:
                 if ((sc->sc_ahci_quirks & AHCI_QUIRK_BADPMPRESET) != 0 &&                  if ((sc->sc_ahci_quirks & AHCI_QUIRK_BADPMPRESET) != 0 &&
Line 884  ahci_reset_channel(struct ata_channel *c
Line 887  ahci_reset_channel(struct ata_channel *c
         struct ahci_channel *achp = (struct ahci_channel *)chp;          struct ahci_channel *achp = (struct ahci_channel *)chp;
         int i, tfd;          int i, tfd;
   
         ata_channel_lock(chp);          ata_channel_lock_owned(chp);
   
         ahci_channel_stop(sc, chp, flags);          ahci_channel_stop(sc, chp, flags);
         if (sata_reset_interface(chp, sc->sc_ahcit, achp->ahcic_scontrol,          if (sata_reset_interface(chp, sc->sc_ahcit, achp->ahcic_scontrol,
Line 914  ahci_reset_channel(struct ata_channel *c
Line 917  ahci_reset_channel(struct ata_channel *c
         /* clear port interrupt register */          /* clear port interrupt register */
         AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);          AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);
   
         ata_channel_unlock(chp);  
   
         return;          return;
 }  }
   
Line 943  ahci_probe_drive(struct ata_channel *chp
Line 944  ahci_probe_drive(struct ata_channel *chp
         struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;          struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
         struct ahci_channel *achp = (struct ahci_channel *)chp;          struct ahci_channel *achp = (struct ahci_channel *)chp;
         uint32_t sig;          uint32_t sig;
         struct ata_xfer *xfer;          uint8_t c_slot;
   
           ata_channel_lock(chp);
   
         xfer = ata_get_xfer_ext(chp, 0, 0);          /* get a slot for running the command on */
         if (xfer == NULL) {          if (!ata_queue_alloc_slot(chp, &c_slot, ATA_MAX_OPENINGS)) {
                 aprint_error_dev(sc->sc_atac.atac_dev,                  aprint_error_dev(sc->sc_atac.atac_dev,
                     "%s: failed to get xfer port %d\n",                      "%s: failed to get xfer port %d\n",
                     __func__, chp->ch_channel);                      __func__, chp->ch_channel);
                   ata_channel_unlock(chp);
                 return;                  return;
         }          }
   
         ata_channel_lock(chp);  
   
         /* bring interface up, accept FISs, power up and spin up device */          /* bring interface up, accept FISs, power up and spin up device */
         AHCI_WRITE(sc, AHCI_P_CMD(chp->ch_channel),          AHCI_WRITE(sc, AHCI_P_CMD(chp->ch_channel),
Line 966  ahci_probe_drive(struct ata_channel *chp
Line 968  ahci_probe_drive(struct ata_channel *chp
                 ata_delay(chp, 500, "ahcidv", AT_WAIT);                  ata_delay(chp, 500, "ahcidv", AT_WAIT);
                 if (sc->sc_ahci_cap & AHCI_CAP_SPM) {                  if (sc->sc_ahci_cap & AHCI_CAP_SPM) {
                         ahci_do_reset_drive(chp, PMP_PORT_CTL, AT_WAIT, &sig,                          ahci_do_reset_drive(chp, PMP_PORT_CTL, AT_WAIT, &sig,
                             xfer);                              c_slot);
                 } else {                  } else {
                         ahci_do_reset_drive(chp, 0, AT_WAIT, &sig, xfer);                          ahci_do_reset_drive(chp, 0, AT_WAIT, &sig, c_slot);
                 }                  }
                 sata_interpret_sig(chp, 0, sig);                  sata_interpret_sig(chp, 0, sig);
                 /* if we have a PMP attached, inform the controller */                  /* if we have a PMP attached, inform the controller */
Line 980  ahci_probe_drive(struct ata_channel *chp
Line 982  ahci_probe_drive(struct ata_channel *chp
                 }                  }
                 /* clear port interrupt register */                  /* clear port interrupt register */
                 AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);                  AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);
   
                 /* and enable interrupts */                  /* and enable interrupts */
                 AHCI_WRITE(sc, AHCI_P_IE(chp->ch_channel),                  AHCI_WRITE(sc, AHCI_P_IE(chp->ch_channel),
                     AHCI_P_IX_TFES | AHCI_P_IX_HBFS | AHCI_P_IX_HBDS |                      AHCI_P_IX_TFES | AHCI_P_IX_HBFS | AHCI_P_IX_HBDS |
Line 994  ahci_probe_drive(struct ata_channel *chp
Line 996  ahci_probe_drive(struct ata_channel *chp
         default:          default:
                 break;                  break;
         }          }
   
           ata_queue_free_slot(chp, c_slot);
   
         ata_channel_unlock(chp);          ata_channel_unlock(chp);
 }  }
   
Line 1003  ahci_setup_channel(struct ata_channel *c
Line 1008  ahci_setup_channel(struct ata_channel *c
         return;          return;
 }  }
   
   static const struct ata_xfer_ops ahci_cmd_xfer_ops = {
           .c_start = ahci_cmd_start,
           .c_poll = ahci_cmd_poll,
           .c_abort = ahci_cmd_abort,
           .c_intr = ahci_cmd_complete,
           .c_kill_xfer = ahci_cmd_kill_xfer,
   };
   
 static int  static int
 ahci_exec_command(struct ata_drive_datas *drvp, struct ata_xfer *xfer)  ahci_exec_command(struct ata_drive_datas *drvp, struct ata_xfer *xfer)
 {  {
Line 1022  ahci_exec_command(struct ata_drive_datas
Line 1035  ahci_exec_command(struct ata_drive_datas
         xfer->c_drive = drvp->drive;          xfer->c_drive = drvp->drive;
         xfer->c_databuf = ata_c->data;          xfer->c_databuf = ata_c->data;
         xfer->c_bcount = ata_c->bcount;          xfer->c_bcount = ata_c->bcount;
         xfer->c_start = ahci_cmd_start;          xfer->ops = &ahci_cmd_xfer_ops;
         xfer->c_poll = ahci_cmd_poll;  
         xfer->c_abort = ahci_cmd_abort;  
         xfer->c_intr = ahci_cmd_complete;  
         xfer->c_kill_xfer = ahci_cmd_kill_xfer;  
         s = splbio();          s = splbio();
         ata_exec_xfer(chp, xfer);          ata_exec_xfer(chp, xfer);
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
Line 1038  ahci_exec_command(struct ata_drive_datas
Line 1047  ahci_exec_command(struct ata_drive_datas
                 ret = ATACMD_COMPLETE;                  ret = ATACMD_COMPLETE;
         } else {          } else {
                 if (ata_c->flags & AT_WAIT) {                  if (ata_c->flags & AT_WAIT) {
                         ata_channel_lock(chp);                          ata_wait_cmd(chp, xfer);
                         if ((ata_c->flags & AT_DONE) == 0) {  
                                 ata_wait_xfer(chp, xfer);  
                                 KASSERT((ata_c->flags & AT_DONE) != 0);  
                         }  
                         ata_channel_unlock(chp);  
                         ret = ATACMD_COMPLETE;                          ret = ATACMD_COMPLETE;
                 } else {                  } else {
                         ret = ATACMD_QUEUED;                          ret = ATACMD_QUEUED;
Line 1069  ahci_cmd_start(struct ata_channel *chp, 
Line 1073  ahci_cmd_start(struct ata_channel *chp, 
             DEBUG_XFERS);              DEBUG_XFERS);
   
         ata_channel_lock_owned(chp);          ata_channel_lock_owned(chp);
         KASSERT((achp->ahcic_cmds_active & (1U << slot)) == 0);  
   
         cmd_tbl = achp->ahcic_cmd_tbl[slot];          cmd_tbl = achp->ahcic_cmd_tbl[slot];
         AHCIDEBUG_PRINT(("%s port %d tbl %p\n", AHCINAME(sc), chp->ch_channel,          AHCIDEBUG_PRINT(("%s port %d tbl %p\n", AHCINAME(sc), chp->ch_channel,
Line 1103  ahci_cmd_start(struct ata_channel *chp, 
Line 1106  ahci_cmd_start(struct ata_channel *chp, 
         }          }
         /* start command */          /* start command */
         AHCI_WRITE(sc, AHCI_P_CI(chp->ch_channel), 1U << slot);          AHCI_WRITE(sc, AHCI_P_CI(chp->ch_channel), 1U << slot);
         /* and says we started this command */  
         achp->ahcic_cmds_active |= 1U << slot;  
   
         if ((ata_c->flags & AT_POLL) == 0) {          if ((ata_c->flags & AT_POLL) == 0) {
                 callout_reset(&xfer->c_timo_callout, mstohz(ata_c->timeout),                  callout_reset(&chp->c_timo_callout, mstohz(ata_c->timeout),
                     ata_timeout, xfer);                      ata_timeout, chp);
                 return ATASTART_STARTED;                  return ATASTART_STARTED;
         } else          } else
                 return ATASTART_POLL;                  return ATASTART_POLL;
Line 1147  ahci_cmd_poll(struct ata_channel *chp, s
Line 1148  ahci_cmd_poll(struct ata_channel *chp, s
   
         if ((xfer->c_ata_c.flags & AT_DONE) == 0) {          if ((xfer->c_ata_c.flags & AT_DONE) == 0) {
                 xfer->c_ata_c.flags |= AT_TIMEOU;                  xfer->c_ata_c.flags |= AT_TIMEOU;
                 xfer->c_intr(chp, xfer, 0);                  xfer->ops->c_intr(chp, xfer, 0);
         }          }
         /* reenable interrupts */          /* reenable interrupts */
         AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE);          AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE);
Line 1162  ahci_cmd_abort(struct ata_channel *chp, 
Line 1163  ahci_cmd_abort(struct ata_channel *chp, 
 static void  static void
 ahci_cmd_kill_xfer(struct ata_channel *chp, struct ata_xfer *xfer, int reason)  ahci_cmd_kill_xfer(struct ata_channel *chp, struct ata_xfer *xfer, int reason)
 {  {
         struct ahci_channel *achp = (struct ahci_channel *)chp;  
         struct ata_command *ata_c = &xfer->c_ata_c;          struct ata_command *ata_c = &xfer->c_ata_c;
         bool deactivate = true;          bool deactivate = true;
   
Line 1187  ahci_cmd_kill_xfer(struct ata_channel *c
Line 1187  ahci_cmd_kill_xfer(struct ata_channel *c
                 panic("ahci_cmd_kill_xfer");                  panic("ahci_cmd_kill_xfer");
         }          }
   
         if (deactivate) {  
                 KASSERT((achp->ahcic_cmds_active & (1U << xfer->c_slot)) != 0);  
                 achp->ahcic_cmds_active &= ~(1U << xfer->c_slot);  
                 ata_deactivate_xfer(chp, xfer);  
         }  
   
         ahci_cmd_done_end(chp, xfer);          ahci_cmd_done_end(chp, xfer);
   
           if (deactivate)
                   ata_deactivate_xfer(chp, xfer);
 }  }
   
 static int  static int
Line 1211  ahci_cmd_complete(struct ata_channel *ch
Line 1208  ahci_cmd_complete(struct ata_channel *ch
         if (ata_waitdrain_xfer_check(chp, xfer))          if (ata_waitdrain_xfer_check(chp, xfer))
                 return 0;                  return 0;
   
         KASSERT((achp->ahcic_cmds_active & (1U << xfer->c_slot)) != 0);  
         achp->ahcic_cmds_active &= ~(1U << xfer->c_slot);  
         ata_deactivate_xfer(chp, xfer);  
   
         if (xfer->c_flags & C_TIMEOU) {          if (xfer->c_flags & C_TIMEOU) {
                 ata_c->flags |= AT_TIMEOU;                  ata_c->flags |= AT_TIMEOU;
         }          }
Line 1230  ahci_cmd_complete(struct ata_channel *ch
Line 1223  ahci_cmd_complete(struct ata_channel *ch
                 satafis_rdh_cmd_readreg(ata_c, achp->ahcic_rfis->rfis_rfis);                  satafis_rdh_cmd_readreg(ata_c, achp->ahcic_rfis->rfis_rfis);
   
         ahci_cmd_done(chp, xfer);          ahci_cmd_done(chp, xfer);
   
           ata_deactivate_xfer(chp, xfer);
   
           if ((ata_c->flags & (AT_TIMEOU|AT_ERROR)) == 0)
                   atastart(chp);
   
         return 0;          return 0;
 }  }
   
Line 1240  ahci_cmd_done(struct ata_channel *chp, s
Line 1239  ahci_cmd_done(struct ata_channel *chp, s
         struct ahci_channel *achp = (struct ahci_channel *)chp;          struct ahci_channel *achp = (struct ahci_channel *)chp;
         struct ata_command *ata_c = &xfer->c_ata_c;          struct ata_command *ata_c = &xfer->c_ata_c;
         uint16_t *idwordbuf;          uint16_t *idwordbuf;
         int flags = ata_c->flags;  
         int i;          int i;
   
         AHCIDEBUG_PRINT(("ahci_cmd_done channel %d flags %#x/%#x\n",          AHCIDEBUG_PRINT(("ahci_cmd_done channel %d flags %#x/%#x\n",
Line 1268  ahci_cmd_done(struct ata_channel *chp, s
Line 1266  ahci_cmd_done(struct ata_channel *chp, s
   
         if (achp->ahcic_cmdh[xfer->c_slot].cmdh_prdbc)          if (achp->ahcic_cmdh[xfer->c_slot].cmdh_prdbc)
                 ata_c->flags |= AT_XFDONE;                  ata_c->flags |= AT_XFDONE;
   
         ahci_cmd_done_end(chp, xfer);          ahci_cmd_done_end(chp, xfer);
         if ((flags & (AT_TIMEOU|AT_ERROR)) == 0)  
                 atastart(chp);  
 }  }
   
 static void  static void
Line 1278  ahci_cmd_done_end(struct ata_channel *ch
Line 1275  ahci_cmd_done_end(struct ata_channel *ch
 {  {
         struct ata_command *ata_c = &xfer->c_ata_c;          struct ata_command *ata_c = &xfer->c_ata_c;
   
         ata_channel_lock(chp);  
   
         ata_c->flags |= AT_DONE;          ata_c->flags |= AT_DONE;
   
         if (ata_c->flags & AT_WAIT)  
                 ata_wake_xfer(chp, xfer);  
   
         ata_channel_unlock(chp);  
         return;  
 }  }
   
   static const struct ata_xfer_ops ahci_bio_xfer_ops = {
           .c_start = ahci_bio_start,
           .c_poll = ahci_bio_poll,
           .c_abort = ahci_bio_abort,
           .c_intr = ahci_bio_complete,
           .c_kill_xfer = ahci_bio_kill_xfer,
   };
   
 static int  static int
 ahci_ata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer)  ahci_ata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer)
 {  {
Line 1304  ahci_ata_bio(struct ata_drive_datas *drv
Line 1301  ahci_ata_bio(struct ata_drive_datas *drv
         xfer->c_drive = drvp->drive;          xfer->c_drive = drvp->drive;
         xfer->c_databuf = ata_bio->databuf;          xfer->c_databuf = ata_bio->databuf;
         xfer->c_bcount = ata_bio->bcount;          xfer->c_bcount = ata_bio->bcount;
         xfer->c_start = ahci_bio_start;          xfer->ops = &ahci_bio_xfer_ops;
         xfer->c_poll = ahci_bio_poll;  
         xfer->c_abort = ahci_bio_abort;  
         xfer->c_intr = ahci_bio_complete;  
         xfer->c_kill_xfer = ahci_bio_kill_xfer;  
         ata_exec_xfer(chp, xfer);          ata_exec_xfer(chp, xfer);
         return (ata_bio->flags & ATA_ITSDONE) ? ATACMD_COMPLETE : ATACMD_QUEUED;          return (ata_bio->flags & ATA_ITSDONE) ? ATACMD_COMPLETE : ATACMD_QUEUED;
 }  }
Line 1359  ahci_bio_start(struct ata_channel *chp, 
Line 1352  ahci_bio_start(struct ata_channel *chp, 
                 AHCI_WRITE(sc, AHCI_P_SACT(chp->ch_channel), 1U << xfer->c_slot);                  AHCI_WRITE(sc, AHCI_P_SACT(chp->ch_channel), 1U << xfer->c_slot);
         /* start command */          /* start command */
         AHCI_WRITE(sc, AHCI_P_CI(chp->ch_channel), 1U << xfer->c_slot);          AHCI_WRITE(sc, AHCI_P_CI(chp->ch_channel), 1U << xfer->c_slot);
         /* and says we started this command */  
         achp->ahcic_cmds_active |= 1U << xfer->c_slot;  
   
         if ((xfer->c_flags & C_POLL) == 0) {          if ((xfer->c_flags & C_POLL) == 0) {
                 callout_reset(&xfer->c_timo_callout, mstohz(ATA_DELAY),                  callout_reset(&chp->c_timo_callout, mstohz(ATA_DELAY),
                     ata_timeout, xfer);                      ata_timeout, chp);
                 return ATASTART_STARTED;                  return ATASTART_STARTED;
         } else          } else
                 return ATASTART_POLL;                  return ATASTART_POLL;
Line 1396  ahci_bio_poll(struct ata_channel *chp, s
Line 1387  ahci_bio_poll(struct ata_channel *chp, s
             DEBUG_XFERS);              DEBUG_XFERS);
         if ((xfer->c_bio.flags & ATA_ITSDONE) == 0) {          if ((xfer->c_bio.flags & ATA_ITSDONE) == 0) {
                 xfer->c_bio.error = TIMEOUT;                  xfer->c_bio.error = TIMEOUT;
                 xfer->c_intr(chp, xfer, 0);                  xfer->ops->c_intr(chp, xfer, 0);
         }          }
         /* reenable interrupts */          /* reenable interrupts */
         AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE);          AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE);
Line 1413  ahci_bio_kill_xfer(struct ata_channel *c
Line 1404  ahci_bio_kill_xfer(struct ata_channel *c
 {  {
         int drive = xfer->c_drive;          int drive = xfer->c_drive;
         struct ata_bio *ata_bio = &xfer->c_bio;          struct ata_bio *ata_bio = &xfer->c_bio;
         struct ahci_channel *achp = (struct ahci_channel *)chp;  
         bool deactivate = true;          bool deactivate = true;
   
         AHCIDEBUG_PRINT(("ahci_bio_kill_xfer channel %d\n", chp->ch_channel),          AHCIDEBUG_PRINT(("ahci_bio_kill_xfer channel %d\n", chp->ch_channel),
Line 1439  ahci_bio_kill_xfer(struct ata_channel *c
Line 1429  ahci_bio_kill_xfer(struct ata_channel *c
         }          }
         ata_bio->r_error = WDCE_ABRT;          ata_bio->r_error = WDCE_ABRT;
   
         if (deactivate) {          if (deactivate)
                 KASSERT((achp->ahcic_cmds_active & (1U << xfer->c_slot)) != 0);  
                 achp->ahcic_cmds_active &= ~(1U << xfer->c_slot);  
                 ata_deactivate_xfer(chp, xfer);                  ata_deactivate_xfer(chp, xfer);
         }  
   
         (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);          (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
 }  }
Line 1462  ahci_bio_complete(struct ata_channel *ch
Line 1449  ahci_bio_complete(struct ata_channel *ch
         if (ata_waitdrain_xfer_check(chp, xfer))          if (ata_waitdrain_xfer_check(chp, xfer))
                 return 0;                  return 0;
   
         KASSERT((achp->ahcic_cmds_active & (1U << xfer->c_slot)) != 0);  
         achp->ahcic_cmds_active &= ~(1U << xfer->c_slot);  
         ata_deactivate_xfer(chp, xfer);  
   
         if (xfer->c_flags & C_TIMEOU) {          if (xfer->c_flags & C_TIMEOU) {
                 ata_bio->error = TIMEOUT;                  ata_bio->error = TIMEOUT;
         }          }
Line 1506  ahci_bio_complete(struct ata_channel *ch
Line 1489  ahci_bio_complete(struct ata_channel *ch
                             le32toh(achp->ahcic_cmdh[xfer->c_slot].cmdh_prdbc);                              le32toh(achp->ahcic_cmdh[xfer->c_slot].cmdh_prdbc);
         }          }
         AHCIDEBUG_PRINT((" now %ld\n", ata_bio->bcount), DEBUG_XFERS);          AHCIDEBUG_PRINT((" now %ld\n", ata_bio->bcount), DEBUG_XFERS);
   
           ata_deactivate_xfer(chp, xfer);
   
         (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);          (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
         if ((AHCI_TFD_ST(tfd) & WDCS_ERR) == 0)          if ((AHCI_TFD_ST(tfd) & WDCS_ERR) == 0)
                 atastart(chp);                  atastart(chp);
Line 1578  ahci_channel_start(struct ahci_softc *sc
Line 1564  ahci_channel_start(struct ahci_softc *sc
         AHCI_WRITE(sc, AHCI_P_CMD(chp->ch_channel), p_cmd);          AHCI_WRITE(sc, AHCI_P_CMD(chp->ch_channel), p_cmd);
 }  }
   
 static void  
 ahci_hold(struct ahci_channel *achp)  
 {  
         achp->ahcic_cmds_hold |= achp->ahcic_cmds_active;  
         achp->ahcic_cmds_active = 0;  
 }  
   
 static void  
 ahci_unhold(struct ahci_channel *achp)  
 {  
         achp->ahcic_cmds_active = achp->ahcic_cmds_hold;  
         achp->ahcic_cmds_hold = 0;  
 }  
   
 /* Recover channel after command failure */  /* Recover channel after command failure */
 void  void
 ahci_channel_recover(struct ahci_softc *sc, struct ata_channel *chp, int tfd)  ahci_channel_recover(struct ahci_softc *sc, struct ata_channel *chp, int tfd)
 {  {
         struct ahci_channel *achp = (struct ahci_channel *)chp;          int drive = ATACH_NODRIVE;
         struct ata_drive_datas *drvp;  
         uint8_t slot, eslot, st, err;  
         int drive = -1, error;  
         struct ata_xfer *xfer;  
         bool reset = false;          bool reset = false;
   
         KASSERT(!achp->ahcic_recovering);          ata_channel_lock(chp);
           KASSERT(!ISSET(chp->ch_flags, ATACH_RECOVERING));
         achp->ahcic_recovering = true;          SET(chp->ch_flags, ATACH_RECOVERING);
           ata_channel_unlock(chp);
   
         /*          /*
          * Read FBS to get the drive which caused the error, if PM is in use.           * Read FBS to get the drive which caused the error, if PM is in use.
Line 1636  ahci_channel_recover(struct ahci_softc *
Line 1605  ahci_channel_recover(struct ahci_softc *
                         }                          }
                         if ((fbs & AHCI_P_FBS_DEC) != 0) {                          if ((fbs & AHCI_P_FBS_DEC) != 0) {
                                 /* follow non-device specific recovery */                                  /* follow non-device specific recovery */
                                 drive = -1;                                  drive = ATACH_NODRIVE;
                                 reset = true;                                  reset = true;
                         }                          }
                 } else {                  } else {
                         /* not device specific, reset channel */                          /* not device specific, reset channel */
                         drive = -1;                          drive = ATACH_NODRIVE;
                         reset = true;                          reset = true;
                 }                  }
         } else          } else
                 drive = 0;                  drive = 0;
   
         drvp = &chp->ch_drive[drive];  
   
         /*          /*
          * If BSY or DRQ bits are set, must execute COMRESET to return           * If BSY or DRQ bits are set, must execute COMRESET to return
          * device to idle state. If drive is idle, it's enough to just           * device to idle state. If drive is idle, it's enough to just
Line 1656  ahci_channel_recover(struct ahci_softc *
Line 1623  ahci_channel_recover(struct ahci_softc *
          * After resetting CMD.ST, need to execute READ LOG EXT for NCQ           * After resetting CMD.ST, need to execute READ LOG EXT for NCQ
          * to unblock device processing if COMRESET was not done.           * to unblock device processing if COMRESET was not done.
          */           */
         if (reset || (AHCI_TFD_ST(tfd) & (WDCS_BSY|WDCS_DRQ)) != 0)          if (reset || (AHCI_TFD_ST(tfd) & (WDCS_BSY|WDCS_DRQ)) != 0) {
                 goto reset;                  ata_channel_lock(chp);
   
         KASSERT(drive >= 0);  
         ahci_channel_stop(sc, chp, AT_POLL);  
         ahci_channel_start(sc, chp, AT_POLL,  
             (sc->sc_ahci_cap & AHCI_CAP_CLO) ? 1 : 0);  
   
         ahci_hold(achp);  
   
         /*  
          * When running NCQ commands, READ LOG EXT is necessary to clear the  
          * error condition and unblock the device.  
          */  
         error = ata_read_log_ext_ncq(drvp, AT_POLL, &eslot, &st, &err);  
   
         ahci_unhold(achp);  
   
         switch (error) {  
         case 0:  
                 /* Error out the particular NCQ xfer, then requeue the others */  
                 if ((achp->ahcic_cmds_active & (1U << eslot)) != 0) {  
                         xfer = ata_queue_hwslot_to_xfer(chp, eslot);  
                         xfer->c_flags |= C_RECOVERED;  
                         xfer->c_intr(chp, xfer,  
                             (err << AHCI_P_TFD_ERR_SHIFT) | st);  
                 }  
                 break;  
   
         case EOPNOTSUPP:  
                 /*  
                  * Non-NCQ command error, just find the slot and end with  
                  * the error.  
                  */  
                 for (slot = 0; slot < sc->sc_ncmds; slot++) {  
                         if ((achp->ahcic_cmds_active & (1U << slot)) != 0) {  
                                 xfer = ata_queue_hwslot_to_xfer(chp, slot);  
                                 xfer->c_intr(chp, xfer, tfd);  
                         }  
                 }  
                 break;  
   
         case EAGAIN:  
                 /*  
                  * Failed to get resources to run the recovery command, must  
                  * reset the drive. This will also kill all still outstanding  
                  * transfers.  
                  */  
 reset:  
                 ahci_reset_channel(chp, AT_POLL);                  ahci_reset_channel(chp, AT_POLL);
                   ata_channel_unlock(chp);
                 goto out;                  goto out;
                 /* NOTREACHED */  
   
         default:  
                 /*  
                  * The command to get the slot failed. Kill outstanding  
                  * commands for the same drive only. No need to reset  
                  * the drive, it's unblocked nevertheless.  
                  */  
                 break;  
         }          }
   
         /* Requeue all unfinished commands for same drive as failed command */          KASSERT(drive != ATACH_NODRIVE && drive >= 0);
         for (slot = 0; slot < sc->sc_ncmds; slot++) {          ahci_channel_stop(sc, chp, AT_POLL);
                 if ((achp->ahcic_cmds_active & (1U << slot)) == 0)          ahci_channel_start(sc, chp, AT_POLL,
                         continue;              (sc->sc_ahci_cap & AHCI_CAP_CLO) ? 1 : 0);
   
                 xfer = ata_queue_hwslot_to_xfer(chp, slot);  
                 if (drive != xfer->c_drive)  
                         continue;  
   
                 xfer->c_kill_xfer(chp, xfer,          ata_recovery_resume(chp, drive, tfd, AT_POLL);
                     (error == 0) ? KILL_REQUEUE : KILL_RESET);  
         }  
   
 out:  out:
         /* Drive unblocked, back to normal operation */          /* Drive unblocked, back to normal operation */
         achp->ahcic_recovering = false;          ata_channel_lock(chp);
           CLR(chp->ch_flags, ATACH_RECOVERING);
           ata_channel_unlock(chp);
   
         atastart(chp);          atastart(chp);
 }  }
   
Line 1836  ahci_atapi_kill_pending(struct scsipi_pe
Line 1745  ahci_atapi_kill_pending(struct scsipi_pe
         ata_kill_pending(&chp->ch_drive[periph->periph_target]);          ata_kill_pending(&chp->ch_drive[periph->periph_target]);
 }  }
   
   static const struct ata_xfer_ops ahci_atapi_xfer_ops = {
           .c_start = ahci_atapi_start,
           .c_poll = ahci_atapi_poll,
           .c_abort = ahci_atapi_abort,
           .c_intr = ahci_atapi_complete,
           .c_kill_xfer = ahci_atapi_kill_xfer,
   };
   
 static void  static void
 ahci_atapi_scsipi_request(struct scsipi_channel *chan,  ahci_atapi_scsipi_request(struct scsipi_channel *chan,
     scsipi_adapter_req_t req, void *arg)      scsipi_adapter_req_t req, void *arg)
Line 1859  ahci_atapi_scsipi_request(struct scsipi_
Line 1776  ahci_atapi_scsipi_request(struct scsipi_
                         scsipi_done(sc_xfer);                          scsipi_done(sc_xfer);
                         return;                          return;
                 }                  }
                 xfer = ata_get_xfer_ext(atac->atac_channels[channel], 0, 0);                  xfer = ata_get_xfer(atac->atac_channels[channel], false);
                 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 1870  ahci_atapi_scsipi_request(struct scsipi_
Line 1787  ahci_atapi_scsipi_request(struct scsipi_
                         xfer->c_flags |= C_POLL;                          xfer->c_flags |= C_POLL;
                 xfer->c_drive = drive;                  xfer->c_drive = drive;
                 xfer->c_flags |= C_ATAPI;                  xfer->c_flags |= C_ATAPI;
                 xfer->c_scsipi = sc_xfer;  
                 xfer->c_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 = ahci_atapi_start;                  xfer->ops = &ahci_atapi_xfer_ops;
                 xfer->c_poll = ahci_atapi_poll;                  xfer->c_scsipi = sc_xfer;
                 xfer->c_abort = ahci_atapi_abort;                  xfer->c_atapi.c_dscpoll = 0;
                 xfer->c_intr = ahci_atapi_complete;  
                 xfer->c_kill_xfer = ahci_atapi_kill_xfer;  
                 xfer->c_dscpoll = 0;  
                 s = splbio();                  s = splbio();
                 ata_exec_xfer(atac->atac_channels[channel], xfer);                  ata_exec_xfer(atac->atac_channels[channel], xfer);
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
Line 1944  ahci_atapi_start(struct ata_channel *chp
Line 1857  ahci_atapi_start(struct ata_channel *chp
         }          }
         /* start command */          /* start command */
         AHCI_WRITE(sc, AHCI_P_CI(chp->ch_channel), 1U << xfer->c_slot);          AHCI_WRITE(sc, AHCI_P_CI(chp->ch_channel), 1U << xfer->c_slot);
         /* and says we started this command */  
         achp->ahcic_cmds_active |= 1U << xfer->c_slot;  
   
         if ((xfer->c_flags & C_POLL) == 0) {          if ((xfer->c_flags & C_POLL) == 0) {
                 callout_reset(&xfer->c_timo_callout, mstohz(sc_xfer->timeout),                  callout_reset(&chp->c_timo_callout, mstohz(sc_xfer->timeout),
                     ata_timeout, xfer);                      ata_timeout, chp);
                 return ATASTART_STARTED;                  return ATASTART_STARTED;
         } else          } else
                 return ATASTART_POLL;                  return ATASTART_POLL;
Line 1981  ahci_atapi_poll(struct ata_channel *chp,
Line 1892  ahci_atapi_poll(struct ata_channel *chp,
             DEBUG_XFERS);              DEBUG_XFERS);
         if ((xfer->c_scsipi->xs_status & XS_STS_DONE) == 0) {          if ((xfer->c_scsipi->xs_status & XS_STS_DONE) == 0) {
                 xfer->c_scsipi->error = XS_TIMEOUT;                  xfer->c_scsipi->error = XS_TIMEOUT;
                 xfer->c_intr(chp, xfer, 0);                  xfer->ops->c_intr(chp, xfer, 0);
         }          }
         /* reenable interrupts */          /* reenable interrupts */
         AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE);          AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE);
Line 2006  ahci_atapi_complete(struct ata_channel *
Line 1917  ahci_atapi_complete(struct ata_channel *
         if (ata_waitdrain_xfer_check(chp, xfer))          if (ata_waitdrain_xfer_check(chp, xfer))
                 return 0;                  return 0;
   
         KASSERT((achp->ahcic_cmds_active & (1U << xfer->c_slot)) != 0);  
         achp->ahcic_cmds_active &= ~(1U << xfer->c_slot);  
         ata_deactivate_xfer(chp, xfer);  
   
         if (xfer->c_flags & C_TIMEOU) {          if (xfer->c_flags & C_TIMEOU) {
                 sc_xfer->error = XS_TIMEOUT;                  sc_xfer->error = XS_TIMEOUT;
         }          }
Line 2039  ahci_atapi_complete(struct ata_channel *
Line 1946  ahci_atapi_complete(struct ata_channel *
                         sc_xfer->error = XS_BUSY;                          sc_xfer->error = XS_BUSY;
                         sc_xfer->status = SCSI_CHECK;                          sc_xfer->status = SCSI_CHECK;
                 }                  }
         }          }
   
           ata_deactivate_xfer(chp, xfer);
   
         ata_free_xfer(chp, xfer);          ata_free_xfer(chp, xfer);
         scsipi_done(sc_xfer);          scsipi_done(sc_xfer);
         if ((AHCI_TFD_ST(tfd) & WDCS_ERR) == 0)          if ((AHCI_TFD_ST(tfd) & WDCS_ERR) == 0)
Line 2051  static void
Line 1961  static void
 ahci_atapi_kill_xfer(struct ata_channel *chp, struct ata_xfer *xfer, int reason)  ahci_atapi_kill_xfer(struct ata_channel *chp, struct ata_xfer *xfer, int reason)
 {  {
         struct scsipi_xfer *sc_xfer = xfer->c_scsipi;          struct scsipi_xfer *sc_xfer = xfer->c_scsipi;
         struct ahci_channel *achp = (struct ahci_channel *)chp;  
         bool deactivate = true;          bool deactivate = true;
   
         /* remove this command from xfer queue */          /* remove this command from xfer queue */
Line 2073  ahci_atapi_kill_xfer(struct ata_channel 
Line 1982  ahci_atapi_kill_xfer(struct ata_channel 
                 panic("ahci_ata_atapi_kill_xfer");                  panic("ahci_ata_atapi_kill_xfer");
         }          }
   
         if (deactivate) {          if (deactivate)
                 KASSERT((achp->ahcic_cmds_active & (1U << xfer->c_slot)) != 0);  
                 achp->ahcic_cmds_active &= ~(1U << xfer->c_slot);  
                 ata_deactivate_xfer(chp, xfer);                  ata_deactivate_xfer(chp, xfer);
         }  
   
         ata_free_xfer(chp, xfer);          ata_free_xfer(chp, xfer);
         scsipi_done(sc_xfer);          scsipi_done(sc_xfer);

Legend:
Removed from v.1.62  
changed lines
  Added in v.1.62.2.9

CVSweb <webmaster@jp.NetBSD.org>