Print this page
MFV: illumos-gate@fd6d41c5025e9fb45a115fc82d86e9983d1e9fd6
9815 Want basic AHCI enclosure services
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Rob Johnston <rob.johnston@joyent.com>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
Approved by: Dan McDonald <danmcd@joyent.com>
Author: Robert Mustacchi <rm@joyent.com>
Conflicts:
        usr/src/cmd/Makefile
9772 Panic in ahci when the failed slot spkt is NULL
Reviewed by: Andy Stormont <astormont@racktopsystems.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Robert Mustacchi <rm@joyent.com>
NEX-17502 Slow crash dumps, significantly slower than live core
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
re #12164 Marvell 88SE9128: Appliance hard hangs on boot probing duplicated ahci device

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/io/sata/adapters/ahci/ahci.c
          +++ new/usr/src/uts/common/io/sata/adapters/ahci/ahci.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  24      - * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
       24 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
       25 + * Copyright (c) 2018, Joyent, Inc.
       26 + * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
  25   27   */
  26   28  
  27   29  /*
  28   30   * AHCI (Advanced Host Controller Interface) SATA HBA Driver
  29   31   *
  30   32   * Power Management Support
  31   33   * ------------------------
  32   34   *
  33   35   * At the moment, the ahci driver only implements suspend/resume to
  34   36   * support Suspend to RAM on X86 feature. Device power management isn't
  35   37   * implemented, link power management is disabled, and hot plug isn't
  36   38   * allowed during the period from suspend to resume.
  37   39   *
  38   40   * For s/r support, the ahci driver only need to implement DDI_SUSPEND
  39   41   * and DDI_RESUME entries, and don't need to take care of new requests
  40   42   * sent down after suspend because the target driver (sd) has already
  41   43   * handled these conditions, and blocked these requests. For the detailed
  42   44   * information, please check with sdopen, sdclose and sdioctl routines.
  43   45   *
       46 + *
       47 + * Enclosure Management Support
       48 + * ----------------------------
       49 + *
       50 + * The ahci driver has basic support for AHCI Enclosure Management (EM)
       51 + * services. The AHCI specification provides an area in the primary ahci BAR for
       52 + * posting data to send out to the enclosure management and provides a register
       53 + * that provides both information and control about this. While the
       54 + * specification allows for multiple forms of enclosure management, the only
       55 + * supported, and commonly found form, is the AHCI specified LED format. The LED
       56 + * format is often implemented as a one-way communication mechanism. Software
       57 + * can write out what it cares about into the aforementioned data buffer and
       58 + * then we wait for the transmission to be sent.
       59 + *
       60 + * This has some drawbacks. It means that we cannot know whether or not it has
       61 + * succeeded. This means we cannot ask hardware what it thinks the LEDs are
       62 + * set to. There's also the added unfortunate reality that firmware on the
       63 + * microcontroller driving this will often not show the LEDs if no drive is
       64 + * present and that actions taken may potentially cause this to get out of sync
       65 + * with what we expect it to be. For example, the specification does not
       66 + * describe what should happen if a drive is removed from the enclosure while
       67 + * this is set and what should happen when it returns. We can only infer that it
       68 + * should be the same.
       69 + *
       70 + * Because only a single command can be sent at any time and we don't want to
       71 + * interfere with controller I/O, we create a taskq dedicated to this that has a
       72 + * single thread. Both resets (which occur on attach and resume) and normal
       73 + * changes to the LED state will be driven through this taskq. Because the taskq
       74 + * has a single thread, this guarantees serial processing.
       75 + *
       76 + * Each userland-submitted task (basically not resets) has a reference counted
       77 + * task structure. This allows the thread that called it to be cancelled and
       78 + * have the system clean itself up. The user thread in ioctl blocks on a CV that
       79 + * can receive signals as it waits for completion.  Note, there is no guarantee
       80 + * provided by the kernel that the first thread to enter the kernel will be the
       81 + * first one to change state.
  44   82   */
  45   83  
  46   84  #include <sys/note.h>
  47   85  #include <sys/scsi/scsi.h>
  48   86  #include <sys/pci.h>
  49   87  #include <sys/disp.h>
  50   88  #include <sys/sata/sata_hba.h>
  51   89  #include <sys/sata/adapters/ahci/ahcireg.h>
  52   90  #include <sys/sata/adapters/ahci/ahcivar.h>
  53   91  
  54   92  /*
  55   93   * FMA header files
  56   94   */
  57   95  #include <sys/ddifm.h>
  58   96  #include <sys/fm/protocol.h>
  59   97  #include <sys/fm/util.h>
  60   98  #include <sys/fm/io/ddi.h>
  61   99  
  62  100  /*
      101 + * EM Control header files
      102 + */
      103 +#include <sys/types.h>
      104 +#include <sys/file.h>
      105 +#include <sys/errno.h>
      106 +#include <sys/open.h>
      107 +#include <sys/cred.h>
      108 +#include <sys/ddi.h>
      109 +#include <sys/sunddi.h>
      110 +
      111 +/*
  63  112   * This is the string displayed by modinfo, etc.
  64  113   */
  65  114  static char ahci_ident[] = "ahci driver";
  66  115  
  67  116  /*
  68  117   * Function prototypes for driver entry points
  69  118   */
  70  119  static  int ahci_attach(dev_info_t *, ddi_attach_cmd_t);
  71  120  static  int ahci_detach(dev_info_t *, ddi_detach_cmd_t);
  72  121  static  int ahci_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
↓ open down ↓ 141 lines elided ↑ open up ↑
 214  263  
 215  264  static  void ahci_get_ahci_addr(ahci_ctl_t *, sata_device_t *, ahci_addr_t *);
 216  265  static  int ahci_get_num_implemented_ports(uint32_t);
 217  266  static  void ahci_log_fatal_error_message(ahci_ctl_t *, uint8_t, uint32_t);
 218  267  static  void ahci_dump_commands(ahci_ctl_t *, uint8_t, uint32_t);
 219  268  static  void ahci_log_serror_message(ahci_ctl_t *, uint8_t, uint32_t, int);
 220  269  #if AHCI_DEBUG
 221  270  static  void ahci_log(ahci_ctl_t *, uint_t, char *, ...);
 222  271  #endif
 223  272  
      273 +static  boolean_t ahci_em_init(ahci_ctl_t *);
      274 +static  void ahci_em_fini(ahci_ctl_t *);
      275 +static  void ahci_em_suspend(ahci_ctl_t *);
      276 +static  void ahci_em_resume(ahci_ctl_t *);
      277 +static  int ahci_em_ioctl(dev_info_t *, int, intptr_t);
 224  278  
      279 +
 225  280  /*
 226  281   * DMA attributes for the data buffer
 227  282   *
 228  283   * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
 229  284   * does not support 64-bit addressing
 230  285   */
 231  286  static ddi_dma_attr_t buffer_dma_attr = {
 232  287          DMA_ATTR_V0,            /* dma_attr_version */
 233  288          0x0ull,                 /* dma_attr_addr_lo: lowest bus address */
 234  289          0xffffffffffffffffull,  /* dma_attr_addr_hi: highest bus address */
↓ open down ↓ 73 lines elided ↑ open up ↑
 308  363  
 309  364  
 310  365  /* Device access attributes */
 311  366  static ddi_device_acc_attr_t accattr = {
 312  367          DDI_DEVICE_ATTR_V1,
 313  368          DDI_STRUCTURE_LE_ACC,
 314  369          DDI_STRICTORDER_ACC,
 315  370          DDI_DEFAULT_ACC
 316  371  };
 317  372  
 318      -
 319  373  static struct dev_ops ahcictl_dev_ops = {
 320  374          DEVO_REV,               /* devo_rev */
 321  375          0,                      /* refcnt  */
 322  376          ahci_getinfo,           /* info */
 323  377          nulldev,                /* identify */
 324  378          nulldev,                /* probe */
 325  379          ahci_attach,            /* attach */
 326  380          ahci_detach,            /* detach */
 327  381          nodev,                  /* no reset */
 328      -        (struct cb_ops *)0,     /* driver operations */
      382 +        NULL,                   /* driver operations */
 329  383          NULL,                   /* bus operations */
 330  384          NULL,                   /* power */
 331  385          ahci_quiesce,           /* quiesce */
 332  386  };
 333  387  
 334  388  static sata_tran_hotplug_ops_t ahci_tran_hotplug_ops = {
 335  389          SATA_TRAN_HOTPLUG_OPS_REV_1,
 336  390          ahci_tran_hotplug_port_activate,
 337  391          ahci_tran_hotplug_port_deactivate
 338  392  };
↓ open down ↓ 64 lines elided ↑ open up ↑
 403  457   */
 404  458  boolean_t sb600_buf_64bit_dma_disable = B_TRUE;
 405  459  
 406  460  /*
 407  461   * By default, 64-bit dma for command buffer will be disabled for AMD/ATI
 408  462   * SB600/700/710/750/800. If the users want to have a try with 64-bit dma,
 409  463   * please change the below value to enable it.
 410  464   */
 411  465  boolean_t sbxxx_commu_64bit_dma_disable = B_TRUE;
 412  466  
      467 +/*
      468 + * These values control the default delay and default number of times to wait
      469 + * for an enclosure message to complete.
      470 + */
      471 +uint_t  ahci_em_reset_delay_ms = 1;
      472 +uint_t  ahci_em_reset_delay_count = 1000;
      473 +uint_t  ahci_em_tx_delay_ms = 1;
      474 +uint_t  ahci_em_tx_delay_count = 1000;
 413  475  
      476 +
 414  477  /*
 415  478   * End of global tunable variable definition
 416  479   */
 417  480  
 418  481  #if AHCI_DEBUG
 419  482  uint32_t ahci_debug_flags = 0;
 420  483  #else
 421  484  uint32_t ahci_debug_flags = (AHCIDBG_ERRS|AHCIDBG_TIMEOUT);
 422  485  #endif
 423  486  
↓ open down ↓ 149 lines elided ↑ open up ↑
 573  636                   * Note that so far we don't support hot-plug during
 574  637                   * suspend/resume.
 575  638                   */
 576  639                  if (ahci_initialize_controller(ahci_ctlp) != AHCI_SUCCESS) {
 577  640                          AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PM, ahci_ctlp,
 578  641                              "Failed to initialize the controller "
 579  642                              "during DDI_RESUME", NULL);
 580  643                          return (DDI_FAILURE);
 581  644                  }
 582  645  
      646 +                /*
      647 +                 * Reset the enclosure services.
      648 +                 */
      649 +                ahci_em_resume(ahci_ctlp);
      650 +
 583  651                  mutex_enter(&ahci_ctlp->ahcictl_mutex);
 584  652                  ahci_ctlp->ahcictl_flags &= ~AHCI_SUSPEND;
 585  653                  mutex_exit(&ahci_ctlp->ahcictl_mutex);
 586  654  
 587  655                  return (DDI_SUCCESS);
 588  656  
 589  657          default:
 590  658                  return (DDI_FAILURE);
 591  659          }
 592  660  
↓ open down ↓ 114 lines elided ↑ open up ↑
 707  775                  uint32_t cap2_status;
 708  776  
 709  777                  /* Get the HBA capabilities extended information */
 710  778                  cap2_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
 711  779                      (uint32_t *)AHCI_GLOBAL_CAP2(ahci_ctlp));
 712  780  
 713  781                  AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 714  782                      "hba capabilities extended = 0x%x", cap2_status);
 715  783          }
 716  784  
      785 +        if (cap_status & AHCI_HBA_CAP_EMS) {
      786 +                ahci_ctlp->ahcictl_cap |= AHCI_CAP_EMS;
      787 +                ahci_ctlp->ahcictl_em_loc =
      788 +                    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
      789 +                    (uint32_t *)AHCI_GLOBAL_EM_LOC(ahci_ctlp));
      790 +                ahci_ctlp->ahcictl_em_ctl =
      791 +                    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
      792 +                    (uint32_t *)AHCI_GLOBAL_EM_CTL(ahci_ctlp));
      793 +        }
      794 +
 717  795  #if AHCI_DEBUG
 718  796          /* Get the interface speed supported by the HBA */
 719  797          speed = (cap_status & AHCI_HBA_CAP_ISS) >> AHCI_HBA_CAP_ISS_SHIFT;
 720  798          if (speed == 0x01) {
 721  799                  AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 722  800                      "hba interface speed support: Gen 1 (1.5Gbps)", NULL);
 723  801          } else if (speed == 0x10) {
 724  802                  AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
 725  803                      "hba interface speed support: Gen 2 (3 Gbps)", NULL);
 726  804          } else if (speed == 0x11) {
↓ open down ↓ 231 lines elided ↑ open up ↑
 958 1036  
 959 1037          attach_state |= AHCI_ATTACH_STATE_HW_INIT;
 960 1038  
 961 1039          /* Start one thread to check packet timeouts */
 962 1040          ahci_ctlp->ahcictl_timeout_id = timeout(
 963 1041              (void (*)(void *))ahci_watchdog_handler,
 964 1042              (caddr_t)ahci_ctlp, ahci_watchdog_tick);
 965 1043  
 966 1044          attach_state |= AHCI_ATTACH_STATE_TIMEOUT_ENABLED;
 967 1045  
     1046 +        if (!ahci_em_init(ahci_ctlp)) {
     1047 +                cmn_err(CE_WARN, "!ahci%d: failed to initialize enclosure "
     1048 +                    "services", instance);
     1049 +                goto err_out;
     1050 +        }
     1051 +        attach_state |= AHCI_ATTACH_STATE_ENCLOSURE;
     1052 +
 968 1053          if (ahci_register_sata_hba_tran(ahci_ctlp, cap_status)) {
 969 1054                  cmn_err(CE_WARN, "!ahci%d: sata hba tran registration failed",
 970 1055                      instance);
 971 1056                  goto err_out;
 972 1057          }
 973 1058  
 974 1059          /* Check all handles at the end of the attach operation. */
 975 1060          if (ahci_check_all_handle(ahci_ctlp) != DDI_SUCCESS) {
 976 1061                  cmn_err(CE_WARN, "!ahci%d: invalid dma/acc handles",
 977 1062                      instance);
↓ open down ↓ 4 lines elided ↑ open up ↑
 982 1067  
 983 1068          AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "ahci_attach success!", NULL);
 984 1069  
 985 1070          return (DDI_SUCCESS);
 986 1071  
 987 1072  err_out:
 988 1073          /* FMA message */
 989 1074          ahci_fm_ereport(ahci_ctlp, DDI_FM_DEVICE_NO_RESPONSE);
 990 1075          ddi_fm_service_impact(ahci_ctlp->ahcictl_dip, DDI_SERVICE_LOST);
 991 1076  
     1077 +        if (attach_state & AHCI_ATTACH_STATE_ENCLOSURE) {
     1078 +                ahci_em_fini(ahci_ctlp);
     1079 +        }
     1080 +
 992 1081          if (attach_state & AHCI_ATTACH_STATE_TIMEOUT_ENABLED) {
 993 1082                  mutex_enter(&ahci_ctlp->ahcictl_mutex);
 994 1083                  (void) untimeout(ahci_ctlp->ahcictl_timeout_id);
 995 1084                  ahci_ctlp->ahcictl_timeout_id = 0;
 996 1085                  mutex_exit(&ahci_ctlp->ahcictl_mutex);
 997 1086          }
 998 1087  
 999 1088          if (attach_state & AHCI_ATTACH_STATE_HW_INIT) {
1000 1089                  ahci_uninitialize_controller(ahci_ctlp);
1001 1090          }
↓ open down ↓ 54 lines elided ↑ open up ↑
1056 1145  
1057 1146                  /* unregister from the sata framework. */
1058 1147                  ret = ahci_unregister_sata_hba_tran(ahci_ctlp);
1059 1148                  if (ret != AHCI_SUCCESS) {
1060 1149                          mutex_enter(&ahci_ctlp->ahcictl_mutex);
1061 1150                          ahci_enable_all_intrs(ahci_ctlp);
1062 1151                          mutex_exit(&ahci_ctlp->ahcictl_mutex);
1063 1152                          return (DDI_FAILURE);
1064 1153                  }
1065 1154  
     1155 +                ahci_em_fini(ahci_ctlp);
     1156 +
1066 1157                  mutex_enter(&ahci_ctlp->ahcictl_mutex);
1067 1158  
1068 1159                  /* stop the watchdog handler */
1069 1160                  (void) untimeout(ahci_ctlp->ahcictl_timeout_id);
1070 1161                  ahci_ctlp->ahcictl_timeout_id = 0;
1071 1162  
1072 1163                  mutex_exit(&ahci_ctlp->ahcictl_mutex);
1073 1164  
1074 1165                  /* uninitialize the controller */
1075 1166                  ahci_uninitialize_controller(ahci_ctlp);
↓ open down ↓ 29 lines elided ↑ open up ↑
1105 1196                   * will not generate interrupts or modify or access memory.
1106 1197                   */
1107 1198                  mutex_enter(&ahci_ctlp->ahcictl_mutex);
1108 1199                  if (ahci_ctlp->ahcictl_flags & AHCI_SUSPEND) {
1109 1200                          mutex_exit(&ahci_ctlp->ahcictl_mutex);
1110 1201                          return (DDI_SUCCESS);
1111 1202                  }
1112 1203  
1113 1204                  ahci_ctlp->ahcictl_flags |= AHCI_SUSPEND;
1114 1205  
     1206 +                ahci_em_suspend(ahci_ctlp);
     1207 +
1115 1208                  /* stop the watchdog handler */
1116 1209                  if (ahci_ctlp->ahcictl_timeout_id) {
1117 1210                          (void) untimeout(ahci_ctlp->ahcictl_timeout_id);
1118 1211                          ahci_ctlp->ahcictl_timeout_id = 0;
1119 1212                  }
1120 1213  
1121 1214                  mutex_exit(&ahci_ctlp->ahcictl_mutex);
1122 1215  
1123 1216                  /*
1124 1217                   * drain the taskq
↓ open down ↓ 11 lines elided ↑ open up ↑
1136 1229                  return (DDI_FAILURE);
1137 1230          }
1138 1231  }
1139 1232  
1140 1233  /*
1141 1234   * The info entry point for dev_ops.
1142 1235   *
1143 1236   */
1144 1237  static int
1145 1238  ahci_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
1146      -                    void *arg, void **result)
     1239 +    void *arg, void **result)
1147 1240  {
1148 1241  #ifndef __lock_lint
1149 1242          _NOTE(ARGUNUSED(dip))
1150 1243  #endif /* __lock_lint */
1151 1244  
1152 1245          ahci_ctl_t *ahci_ctlp;
1153 1246          int instance;
1154 1247          dev_t dev;
1155 1248  
1156 1249          dev = (dev_t)arg;
↓ open down ↓ 18 lines elided ↑ open up ↑
1175 1268  
1176 1269          return (DDI_SUCCESS);
1177 1270  }
1178 1271  
1179 1272  /*
1180 1273   * Registers the ahci with sata framework.
1181 1274   */
1182 1275  static int
1183 1276  ahci_register_sata_hba_tran(ahci_ctl_t *ahci_ctlp, uint32_t cap_status)
1184 1277  {
1185      -        struct  sata_hba_tran   *sata_hba_tran;
     1278 +        struct  sata_hba_tran   *sata_hba_tran;
1186 1279  
1187 1280          AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
1188 1281              "ahci_register_sata_hba_tran enter", NULL);
1189 1282  
1190 1283          mutex_enter(&ahci_ctlp->ahcictl_mutex);
1191 1284  
1192 1285          /* Allocate memory for the sata_hba_tran  */
1193 1286          sata_hba_tran = kmem_zalloc(sizeof (sata_hba_tran_t), KM_SLEEP);
1194 1287  
1195 1288          sata_hba_tran->sata_tran_hba_rev = SATA_TRAN_HBA_REV;
↓ open down ↓ 59 lines elided ↑ open up ↑
1255 1348          sata_hba_tran->sata_tran_reset_dport = ahci_tran_reset_dport;
1256 1349          sata_hba_tran->sata_tran_hotplug_ops = &ahci_tran_hotplug_ops;
1257 1350  #ifdef __lock_lint
1258 1351          sata_hba_tran->sata_tran_selftest = ahci_selftest;
1259 1352  #endif
1260 1353          /*
1261 1354           * When SATA framework adds support for pwrmgt the
1262 1355           * pwrmgt_ops needs to be updated
1263 1356           */
1264 1357          sata_hba_tran->sata_tran_pwrmgt_ops = NULL;
1265      -        sata_hba_tran->sata_tran_ioctl = NULL;
     1358 +        sata_hba_tran->sata_tran_ioctl = ahci_em_ioctl;
1266 1359  
1267 1360          ahci_ctlp->ahcictl_sata_hba_tran = sata_hba_tran;
1268 1361  
1269 1362          mutex_exit(&ahci_ctlp->ahcictl_mutex);
1270 1363  
1271 1364          /* Attach it to SATA framework */
1272 1365          if (sata_hba_attach(ahci_ctlp->ahcictl_dip, sata_hba_tran, DDI_ATTACH)
1273 1366              != DDI_SUCCESS) {
1274 1367                  kmem_free((void *)sata_hba_tran, sizeof (sata_hba_tran_t));
1275 1368                  mutex_enter(&ahci_ctlp->ahcictl_mutex);
↓ open down ↓ 532 lines elided ↑ open up ↑
1808 1901                  if ((rval = ahci_deliver_satapkt(ahci_ctlp, ahci_portp,
1809 1902                      addrp, spkt)) == AHCI_FAILURE) {
1810 1903                          ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_POLLING;
1811 1904                          return (rval);
1812 1905                  }
1813 1906  
1814 1907                  pkt_timeout_ticks =
1815 1908                      drv_usectohz((clock_t)spkt->satapkt_time * 1000000);
1816 1909  
1817 1910                  while (spkt->satapkt_reason == SATA_PKT_BUSY) {
1818      -                        mutex_exit(&ahci_portp->ahciport_mutex);
1819      -
1820 1911                          /* Simulate the interrupt */
     1912 +                        mutex_exit(&ahci_portp->ahciport_mutex);
1821 1913                          ahci_port_intr(ahci_ctlp, ahci_portp, port);
     1914 +                        mutex_enter(&ahci_portp->ahciport_mutex);
1822 1915  
1823      -                        drv_usecwait(AHCI_10MS_USECS);
     1916 +                        if (spkt->satapkt_reason != SATA_PKT_BUSY)
     1917 +                                break;
1824 1918  
     1919 +                        mutex_exit(&ahci_portp->ahciport_mutex);
     1920 +                        drv_usecwait(AHCI_1MS_USECS);
1825 1921                          mutex_enter(&ahci_portp->ahciport_mutex);
1826      -                        pkt_timeout_ticks -= AHCI_10MS_TICKS;
     1922 +
     1923 +                        pkt_timeout_ticks -= AHCI_1MS_TICKS;
1827 1924                          if (pkt_timeout_ticks < 0) {
1828 1925                                  cmn_err(CE_WARN, "!ahci%d: ahci_do_sync_start "
1829 1926                                      "port %d satapkt 0x%p timed out\n",
1830 1927                                      instance, port, (void *)spkt);
1831 1928                                  timeout_tags = (0x1 << rval);
1832 1929                                  mutex_exit(&ahci_portp->ahciport_mutex);
1833 1930                                  ahci_timeout_pkts(ahci_ctlp, ahci_portp,
1834 1931                                      port, timeout_tags);
1835 1932                                  mutex_enter(&ahci_portp->ahciport_mutex);
1836 1933                          }
1837 1934                  }
     1935 +
1838 1936                  ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_POLLING;
1839 1937                  return (AHCI_SUCCESS);
1840 1938  
1841 1939          } else {
1842 1940                  if ((rval = ahci_deliver_satapkt(ahci_ctlp, ahci_portp,
1843 1941                      addrp, spkt)) == AHCI_FAILURE)
1844 1942                          return (rval);
1845 1943  
1846 1944  #if AHCI_DEBUG
1847 1945                  /*
↓ open down ↓ 24 lines elided ↑ open up ↑
1872 1970   *      4. HBA doesn't support multiple-use of command list while already a
1873 1971   *         non-queued command is oustanding
1874 1972   *      5. Queued command requested while some queued command(s) has been
1875 1973   *         outstanding on a different port multiplier port. (AHCI spec 1.2,
1876 1974   *         9.1.2)
1877 1975   *
1878 1976   * claimed slot number returned if succeeded
1879 1977   *
1880 1978   * NOTE: it will always return slot 0 for following commands to simplify the
1881 1979   * algorithm.
1882      - *      1. REQUEST SENSE or READ LOG EXT command during error recovery process
1883      - *      2. READ/WRITE PORTMULT command
     1980 + *      1. REQUEST SENSE or READ LOG EXT command during error recovery process
     1981 + *      2. READ/WRITE PORTMULT command
1884 1982   */
1885 1983  static int
1886 1984  ahci_claim_free_slot(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
1887 1985      ahci_addr_t *addrp, int command_type)
1888 1986  {
1889 1987          uint32_t port_cmd_issue;
1890 1988          uint32_t free_slots;
1891 1989          int slot;
1892 1990  
1893 1991          ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
↓ open down ↓ 135 lines elided ↑ open up ↑
2029 2127          AHCIDBG(AHCIDBG_VERBOSE, ahci_ctlp,
2030 2128              "ahci_claim_free_slot: found slot: 0x%x", slot);
2031 2129  
2032 2130          return (slot);
2033 2131  }
2034 2132  
2035 2133  /*
2036 2134   * Builds the Command Table for the sata packet and delivers it to controller.
2037 2135   *
2038 2136   * Returns:
2039      - *      slot number if we can obtain a slot successfully
     2137 + *      slot number if we can obtain a slot successfully
2040 2138   *      otherwise, return AHCI_FAILURE
2041 2139   */
2042 2140  static int
2043 2141  ahci_deliver_satapkt(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
2044 2142      ahci_addr_t *addrp, sata_pkt_t *spkt)
2045 2143  {
2046 2144          int cmd_slot;
2047 2145          sata_cmd_t *scmd;
2048 2146          ahci_fis_h2d_register_t *h2d_register_fisp;
2049 2147          ahci_cmd_table_t *cmd_table;
↓ open down ↓ 98 lines elided ↑ open up ↑
2148 2246          SET_FIS_CDMDEVCTL(h2d_register_fisp, 1);
2149 2247          SET_FIS_COMMAND(h2d_register_fisp, scmd->satacmd_cmd_reg);
2150 2248          SET_FIS_FEATURES(h2d_register_fisp, scmd->satacmd_features_reg);
2151 2249          SET_FIS_SECTOR_COUNT(h2d_register_fisp, scmd->satacmd_sec_count_lsb);
2152 2250  
2153 2251          switch (scmd->satacmd_addr_type) {
2154 2252  
2155 2253          case 0:
2156 2254                  /*
2157 2255                   * satacmd_addr_type will be 0 for the commands below:
2158      -                 *      ATAPI command
2159      -                 *      SATAC_IDLE_IM
2160      -                 *      SATAC_STANDBY_IM
2161      -                 *      SATAC_DOWNLOAD_MICROCODE
2162      -                 *      SATAC_FLUSH_CACHE
2163      -                 *      SATAC_SET_FEATURES
2164      -                 *      SATAC_SMART
2165      -                 *      SATAC_ID_PACKET_DEVICE
2166      -                 *      SATAC_ID_DEVICE
2167      -                 *      SATAC_READ_PORTMULT
2168      -                 *      SATAC_WRITE_PORTMULT
     2256 +                 *      ATAPI command
     2257 +                 *      SATAC_IDLE_IM
     2258 +                 *      SATAC_STANDBY_IM
     2259 +                 *      SATAC_DOWNLOAD_MICROCODE
     2260 +                 *      SATAC_FLUSH_CACHE
     2261 +                 *      SATAC_SET_FEATURES
     2262 +                 *      SATAC_SMART
     2263 +                 *      SATAC_ID_PACKET_DEVICE
     2264 +                 *      SATAC_ID_DEVICE
     2265 +                 *      SATAC_READ_PORTMULT
     2266 +                 *      SATAC_WRITE_PORTMULT
2169 2267                   */
2170 2268                  /* FALLTHRU */
2171 2269  
2172 2270          case ATA_ADDR_LBA:
2173 2271                  /* FALLTHRU */
2174 2272  
2175 2273          case ATA_ADDR_LBA28:
2176 2274                  /* LBA[7:0] */
2177 2275                  SET_FIS_SECTOR(h2d_register_fisp, scmd->satacmd_lba_low_lsb);
2178 2276  
↓ open down ↓ 4547 lines elided ↑ open up ↑
6726 6824   *      1. Receive one D2H Register FIS which is with 'I' bit set
6727 6825   *      2. Update PIO Setup FIS
6728 6826   *      3. Transmit a command and receive R_OK if CTBA.C is set (software reset)
6729 6827   *
6730 6828   * Process completed non-queued commands when the interrupt status bit -
6731 6829   * AHCI_INTR_STATUS_DHRS or AHCI_INTR_STATUS_PSS is set.
6732 6830   *
6733 6831   * AHCI_INTR_STATUS_DHRS means a D2H Register FIS has been received
6734 6832   * with the 'I' bit set. And the following commands will send thus
6735 6833   * FIS with 'I' bit set upon the successful completion:
6736      - *      1. Non-data commands
6737      - *      2. DMA data-in command
6738      - *      3. DMA data-out command
6739      - *      4. PIO data-out command
     6834 + *      1. Non-data commands
     6835 + *      2. DMA data-in command
     6836 + *      3. DMA data-out command
     6837 + *      4. PIO data-out command
6740 6838   *      5. PACKET non-data commands
6741 6839   *      6. PACKET PIO data-in command
6742 6840   *      7. PACKET PIO data-out command
6743 6841   *      8. PACKET DMA data-in command
6744 6842   *      9. PACKET DMA data-out command
6745 6843   *
6746 6844   * AHCI_INTR_STATUS_PSS means a PIO Setup FIS has been received
6747 6845   * with the 'I' bit set. And the following commands will send this
6748 6846   * FIS upon the successful completion:
6749      - *      1. PIO data-in command
     6847 + *      1. PIO data-in command
6750 6848   */
6751 6849  static int
6752 6850  ahci_intr_cmd_cmplt(ahci_ctl_t *ahci_ctlp,
6753 6851      ahci_port_t *ahci_portp, uint8_t port)
6754 6852  {
6755 6853          uint32_t port_cmd_issue = 0;
6756 6854          uint32_t finished_tags;
6757 6855          int finished_slot;
6758 6856          sata_pkt_t *satapkt;
6759 6857          ahci_fis_d2h_register_t *rcvd_fisp;
↓ open down ↓ 933 lines elided ↑ open up ↑
7693 7791   * has given a pointer to the HBA that doesn't exist in physical memory,
7694 7792   * a master/target abort error occurs, and PxIS.HBFS will be set. A
7695 7793   * data error such as CRC or parity occurs, the HBA aborts the transfer
7696 7794   * (if necessary) and PxIS.HBDS will be set.
7697 7795   *
7698 7796   * Interface errors are errors that occur due to electrical issues on
7699 7797   * the interface, or protocol miscommunication between the device and
7700 7798   * HBA, and the respective PxSERR register bit will be set. And PxIS.IFS
7701 7799   * (fatal) or PxIS.INFS (non-fatal) will be set. The conditions that
7702 7800   * causes PxIS.IFS/PxIS.INFS to be set are
7703      - *      1. in PxSERR.ERR, P bit is set to '1'
     7801 + *      1. in PxSERR.ERR, P bit is set to '1'
7704 7802   *      2. in PxSERR.DIAG, C or H bit is set to '1'
7705 7803   *      3. PhyRdy drop unexpectly, N bit is set to '1'
7706 7804   * If the error occurred during a non-data FIS, the FIS must be
7707 7805   * retransmitted, and the error is non-fatal and PxIS.INFS is set. If
7708 7806   * the error occurred during a data FIS, the transfer will stop, so
7709 7807   * the error is fatal and PxIS.IFS is set.
7710 7808   *
7711 7809   * When a FIS arrives that updates the taskfile, the HBA checks to see
7712 7810   * if PxTFD.STS.ERR is set. If yes, PxIS.TFES will be set and the HBA
7713 7811   * stops processing any more commands.
↓ open down ↓ 680 lines elided ↑ open up ↑
8394 8492   * First clear PxCMD.ST, and then check PxTFD. If both PxTFD.STS.BSY
8395 8493   * and PxTFD.STS.DRQ cleared to '0', it means the device is in a
8396 8494   * stable state, then set PxCMD.ST to '1' to start the port directly.
8397 8495   * If PxTFD.STS.BSY or PxTFD.STS.DRQ is set to '1', then issue a
8398 8496   * COMRESET to the device to put it in an idle state.
8399 8497   *
8400 8498   * The fifth argument returns whether the port reset is involved during
8401 8499   * the process.
8402 8500   *
8403 8501   * The routine will be called under following scenarios:
8404      - *      + To reset the HBA
     8502 + *      + To reset the HBA
8405 8503   *      + To abort the packet(s)
8406 8504   *      + To reset the port
8407 8505   *      + To activate the port
8408 8506   *      + Fatal error recovery
8409 8507   *      + To abort the timeout packet(s)
8410 8508   *
8411 8509   * NOTES!!! During this procedure, PxSERR register will be cleared, and
8412 8510   * according to the spec, the clearance of three bits will also clear
8413 8511   * three interrupt status bits.
8414 8512   *      1. PxSERR.DIAG.F will clear PxIS.UFS
↓ open down ↓ 1051 lines elided ↑ open up ↑
9466 9564              ahci_portp,
9467 9565              slot_status,
9468 9566              failed_tags, /* failed tags */
9469 9567              0, /* timeout tags */
9470 9568              0, /* aborted tags */
9471 9569              0); /* reset tags */
9472 9570  }
9473 9571  
9474 9572  /*
9475 9573   * Used to recovery a PMULT pmport fatal error under FIS-based switching.
9476      - *      1. device specific.PxFBS.SDE=1
9477      - *      2. Non-Deivce specific.
     9574 + *      1. device specific.PxFBS.SDE=1
     9575 + *      2. Non Device specific.
9478 9576   * Nothing will be done when Command-based switching is employed.
9479 9577   *
9480 9578   * Currently code is neither completed nor tested.
9481 9579   */
9482 9580  static void
9483 9581  ahci_pmult_error_recovery_handler(ahci_ctl_t *ahci_ctlp,
9484 9582      ahci_port_t *ahci_portp, uint8_t port, uint32_t intr_status)
9485 9583  {
9486 9584  #ifndef __lock_lint
9487 9585          _NOTE(ARGUNUSED(intr_status))
↓ open down ↓ 493 lines elided ↑ open up ↑
9981 10079          ahci_portp = ahci_ctlp->ahcictl_ports[port];
9982 10080          ASSERT(ahci_portp != NULL);
9983 10081  
9984 10082          while (slot_tags) {
9985 10083                  tmp_slot = ddi_ffs(slot_tags) - 1;
9986 10084                  if (tmp_slot == -1) {
9987 10085                          break;
9988 10086                  }
9989 10087  
9990 10088                  spkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
9991      -                ASSERT(spkt != NULL);
9992      -                cmd = spkt->satapkt_cmd;
     10089 +                if (spkt != NULL) {
     10090 +                        cmd = spkt->satapkt_cmd;
9993 10091  
9994      -                cmn_err(CE_WARN, "!satapkt 0x%p: cmd_reg = 0x%x "
9995      -                    "features_reg = 0x%x sec_count_msb = 0x%x "
9996      -                    "lba_low_msb = 0x%x lba_mid_msb = 0x%x "
9997      -                    "lba_high_msb = 0x%x sec_count_lsb = 0x%x "
9998      -                    "lba_low_lsb = 0x%x lba_mid_lsb = 0x%x "
9999      -                    "lba_high_lsb = 0x%x device_reg = 0x%x "
10000      -                    "addr_type = 0x%x cmd_flags = 0x%x", (void *)spkt,
10001      -                    cmd.satacmd_cmd_reg, cmd.satacmd_features_reg,
10002      -                    cmd.satacmd_sec_count_msb, cmd.satacmd_lba_low_msb,
10003      -                    cmd.satacmd_lba_mid_msb, cmd.satacmd_lba_high_msb,
10004      -                    cmd.satacmd_sec_count_lsb, cmd.satacmd_lba_low_lsb,
10005      -                    cmd.satacmd_lba_mid_lsb, cmd.satacmd_lba_high_lsb,
10006      -                    cmd.satacmd_device_reg, cmd.satacmd_addr_type,
10007      -                    *((uint32_t *)&(cmd.satacmd_flags)));
     10092 +                        cmn_err(CE_WARN, "!satapkt 0x%p: cmd_reg = 0x%x "
     10093 +                            "features_reg = 0x%x sec_count_msb = 0x%x "
     10094 +                            "lba_low_msb = 0x%x lba_mid_msb = 0x%x "
     10095 +                            "lba_high_msb = 0x%x sec_count_lsb = 0x%x "
     10096 +                            "lba_low_lsb = 0x%x lba_mid_lsb = 0x%x "
     10097 +                            "lba_high_lsb = 0x%x device_reg = 0x%x "
     10098 +                            "addr_type = 0x%x cmd_flags = 0x%x", (void *)spkt,
     10099 +                            cmd.satacmd_cmd_reg, cmd.satacmd_features_reg,
     10100 +                            cmd.satacmd_sec_count_msb, cmd.satacmd_lba_low_msb,
     10101 +                            cmd.satacmd_lba_mid_msb, cmd.satacmd_lba_high_msb,
     10102 +                            cmd.satacmd_sec_count_lsb, cmd.satacmd_lba_low_lsb,
     10103 +                            cmd.satacmd_lba_mid_lsb, cmd.satacmd_lba_high_lsb,
     10104 +                            cmd.satacmd_device_reg, cmd.satacmd_addr_type,
     10105 +                            *((uint32_t *)&(cmd.satacmd_flags)));
     10106 +                }
10008 10107  
10009 10108                  CLEAR_BIT(slot_tags, tmp_slot);
10010 10109          }
10011 10110  }
10012 10111  
10013 10112  /*
10014 10113   * Dump the serror message to the log.
10015 10114   */
10016 10115  static void
10017 10116  ahci_log_serror_message(ahci_ctl_t *ahci_ctlp, uint8_t port,
↓ open down ↓ 179 lines elided ↑ open up ↑
10197 10296  
10198 10297          mutex_exit(&ahci_log_mutex);
10199 10298  }
10200 10299  #endif
10201 10300  
10202 10301  /*
10203 10302   * quiesce(9E) entry point.
10204 10303   *
10205 10304   * This function is called when the system is single-threaded at high
10206 10305   * PIL with preemption disabled. Therefore, this function must not be
10207      - * blocked.
     10306 + * blocked. Because no taskqs are running, there is no need for us to
     10307 + * take any action for enclosure services which are running in the
     10308 + * taskq context, especially as no interrupts are generated by it nor
     10309 + * are any messages expected to come in.
10208 10310   *
10209 10311   * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
10210 10312   * DDI_FAILURE indicates an error condition and should almost never happen.
10211 10313   */
10212 10314  static int
10213 10315  ahci_quiesce(dev_info_t *dip)
10214 10316  {
10215 10317          ahci_ctl_t *ahci_ctlp;
10216 10318          ahci_port_t *ahci_portp;
10217 10319          int instance, port;
↓ open down ↓ 96 lines elided ↑ open up ↑
10314 10416                          satapkt->satapkt_hba_driver_private = NULL;
10315 10417  
10316 10418                          /* Call the callback */
10317 10419                          (*satapkt->satapkt_comp)(satapkt);
10318 10420  
10319 10421                          satapkt = next;
10320 10422                  }
10321 10423  
10322 10424                  mutex_enter(&ahci_portp->ahciport_mutex);
10323 10425          }
     10426 +}
     10427 +
     10428 +/*
     10429 + * Sets the state for the specified port on the controller to desired state.
     10430 + * This must be run in the context of the enclosure taskq which ensures that
     10431 + * only one event is outstanding at any time.
     10432 + */
     10433 +static boolean_t
     10434 +ahci_em_set_led(ahci_ctl_t *ahci_ctlp, uint8_t port, ahci_em_led_state_t desire)
     10435 +{
     10436 +        ahci_em_led_msg_t msg;
     10437 +        ahci_em_msg_hdr_t hdr;
     10438 +        uint32_t msgval, hdrval;
     10439 +        uint_t i, max_delay = ahci_em_tx_delay_count;
     10440 +
     10441 +        msg.alm_hba = port;
     10442 +        msg.alm_pminfo = 0;
     10443 +        msg.alm_value = 0;
     10444 +
     10445 +        if (desire & AHCI_EM_LED_IDENT_ENABLE) {
     10446 +                msg.alm_value |= AHCI_LED_ON << AHCI_LED_IDENT_OFF;
     10447 +        }
     10448 +
     10449 +        if (desire & AHCI_EM_LED_FAULT_ENABLE) {
     10450 +                msg.alm_value |= AHCI_LED_ON << AHCI_LED_FAULT_OFF;
     10451 +        }
     10452 +
     10453 +        if ((ahci_ctlp->ahcictl_em_ctl & AHCI_HBA_EM_CTL_ATTR_ALHD) == 0 &&
     10454 +            (desire & AHCI_EM_LED_ACTIVITY_DISABLE) == 0) {
     10455 +                msg.alm_value |= AHCI_LED_ON << AHCI_LED_ACTIVITY_OFF;
     10456 +        }
     10457 +
     10458 +        hdr.aemh_rsvd = 0;
     10459 +        hdr.aemh_mlen = sizeof (ahci_em_led_msg_t);
     10460 +        hdr.aemh_dlen = 0;
     10461 +        hdr.aemh_mtype = AHCI_EM_MSG_TYPE_LED;
     10462 +
     10463 +        bcopy(&msg, &msgval, sizeof (msgval));
     10464 +        bcopy(&hdr, &hdrval, sizeof (hdrval));
     10465 +
     10466 +        /*
     10467 +         * First, make sure we can transmit. We should not have been placed in a
     10468 +         * situation where an outstanding transmission is going on.
     10469 +         */
     10470 +        for (i = 0; i < max_delay; i++) {
     10471 +                uint32_t val;
     10472 +
     10473 +                val = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
     10474 +                    (uint32_t *)AHCI_GLOBAL_EM_CTL(ahci_ctlp));
     10475 +                if ((val & AHCI_HBA_EM_CTL_CTL_TM) == 0)
     10476 +                        break;
     10477 +
     10478 +                delay(drv_usectohz(ahci_em_tx_delay_ms * 1000));
     10479 +        }
     10480 +
     10481 +        if (i == max_delay)
     10482 +                return (B_FALSE);
     10483 +
     10484 +        ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
     10485 +            (uint32_t *)ahci_ctlp->ahcictl_em_tx_off, hdrval);
     10486 +        ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
     10487 +            (uint32_t *)(ahci_ctlp->ahcictl_em_tx_off + 4), msgval);
     10488 +        ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
     10489 +            (uint32_t *)AHCI_GLOBAL_EM_CTL(ahci_ctlp), AHCI_HBA_EM_CTL_CTL_TM);
     10490 +
     10491 +        for (i = 0; i < max_delay; i++) {
     10492 +                uint32_t val;
     10493 +
     10494 +                val = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
     10495 +                    (uint32_t *)AHCI_GLOBAL_EM_CTL(ahci_ctlp));
     10496 +                if ((val & AHCI_HBA_EM_CTL_CTL_TM) == 0)
     10497 +                        break;
     10498 +
     10499 +                delay(drv_usectohz(ahci_em_tx_delay_ms * 1000));
     10500 +        }
     10501 +
     10502 +        if (i == max_delay)
     10503 +                return (B_FALSE);
     10504 +
     10505 +        return (B_TRUE);
     10506 +}
     10507 +
     10508 +typedef struct ahci_em_led_task_arg {
     10509 +        ahci_ctl_t              *aelta_ctl;
     10510 +        uint8_t                 aelta_port;
     10511 +        uint_t                  aelta_op;
     10512 +        ahci_em_led_state_t     aelta_state;
     10513 +        uint_t                  aelta_ret;
     10514 +        kcondvar_t              aelta_cv;
     10515 +        uint_t                  aelta_ref;
     10516 +} ahci_em_led_task_arg_t;
     10517 +
     10518 +static void
     10519 +ahci_em_led_task_free(ahci_em_led_task_arg_t *task)
     10520 +{
     10521 +        ASSERT3U(task->aelta_ref, ==, 0);
     10522 +        cv_destroy(&task->aelta_cv);
     10523 +        kmem_free(task, sizeof (*task));
     10524 +}
     10525 +
     10526 +static void
     10527 +ahci_em_led_task(void *arg)
     10528 +{
     10529 +        boolean_t ret, cleanup = B_FALSE;
     10530 +        ahci_em_led_task_arg_t *led = arg;
     10531 +        ahci_em_led_state_t state;
     10532 +
     10533 +        mutex_enter(&led->aelta_ctl->ahcictl_mutex);
     10534 +        if (led->aelta_ctl->ahcictl_em_flags != AHCI_EM_USABLE) {
     10535 +                led->aelta_ret = EIO;
     10536 +                mutex_exit(&led->aelta_ctl->ahcictl_mutex);
     10537 +                return;
     10538 +        }
     10539 +
     10540 +        state = led->aelta_ctl->ahcictl_em_state[led->aelta_port];
     10541 +        mutex_exit(&led->aelta_ctl->ahcictl_mutex);
     10542 +
     10543 +        switch (led->aelta_op) {
     10544 +        case AHCI_EM_IOC_SET_OP_ADD:
     10545 +                state |= led->aelta_state;
     10546 +                break;
     10547 +        case AHCI_EM_IOC_SET_OP_REM:
     10548 +                state &= ~led->aelta_state;
     10549 +                break;
     10550 +        case AHCI_EM_IOC_SET_OP_SET:
     10551 +                state = led->aelta_state;
     10552 +                break;
     10553 +        default:
     10554 +                led->aelta_ret = ENOTSUP;
     10555 +                return;
     10556 +        }
     10557 +
     10558 +        ret = ahci_em_set_led(led->aelta_ctl, led->aelta_port, state);
     10559 +
     10560 +        mutex_enter(&led->aelta_ctl->ahcictl_mutex);
     10561 +        if (ret) {
     10562 +                led->aelta_ctl->ahcictl_em_state[led->aelta_port] =
     10563 +                    led->aelta_state;
     10564 +                led->aelta_ret = 0;
     10565 +        } else {
     10566 +                led->aelta_ret = EIO;
     10567 +                led->aelta_ctl->ahcictl_em_flags |= AHCI_EM_TIMEOUT;
     10568 +        }
     10569 +        led->aelta_ref--;
     10570 +        if (led->aelta_ref > 0) {
     10571 +                cv_signal(&led->aelta_cv);
     10572 +        } else {
     10573 +                cleanup = B_TRUE;
     10574 +        }
     10575 +        mutex_exit(&led->aelta_ctl->ahcictl_mutex);
     10576 +
     10577 +        if (cleanup) {
     10578 +                ahci_em_led_task_free(led);
     10579 +        }
     10580 +}
     10581 +
     10582 +static void
     10583 +ahci_em_reset(void *arg)
     10584 +{
     10585 +        uint_t i, max_delay = ahci_em_reset_delay_count;
     10586 +        ahci_ctl_t *ahci_ctlp = arg;
     10587 +
     10588 +        /*
     10589 +         * We've been asked to reset the device. The caller should have set the
     10590 +         * resetting flag. Make sure that we don't have a request to quiesce.
     10591 +         */
     10592 +        mutex_enter(&ahci_ctlp->ahcictl_mutex);
     10593 +        ASSERT(ahci_ctlp->ahcictl_em_flags & AHCI_EM_RESETTING);
     10594 +        if (ahci_ctlp->ahcictl_em_flags & AHCI_EM_QUIESCE) {
     10595 +                ahci_ctlp->ahcictl_em_flags &= ~AHCI_EM_RESETTING;
     10596 +                mutex_exit(&ahci_ctlp->ahcictl_mutex);
     10597 +                return;
     10598 +        }
     10599 +        mutex_exit(&ahci_ctlp->ahcictl_mutex);
     10600 +
     10601 +        ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
     10602 +            (uint32_t *)AHCI_GLOBAL_EM_CTL(ahci_ctlp), AHCI_HBA_EM_CTL_CTL_RST);
     10603 +        for (i = 0; i < max_delay; i++) {
     10604 +                uint32_t val;
     10605 +
     10606 +                val = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
     10607 +                    (uint32_t *)AHCI_GLOBAL_EM_CTL(ahci_ctlp));
     10608 +                if ((val & AHCI_HBA_EM_CTL_CTL_RST) == 0)
     10609 +                        break;
     10610 +
     10611 +                delay(drv_usectohz(ahci_em_reset_delay_ms * 1000));
     10612 +        }
     10613 +
     10614 +        if (i == max_delay) {
     10615 +                mutex_enter(&ahci_ctlp->ahcictl_mutex);
     10616 +                ahci_ctlp->ahcictl_em_flags &= ~AHCI_EM_RESETTING;
     10617 +                ahci_ctlp->ahcictl_em_flags |= AHCI_EM_TIMEOUT;
     10618 +                mutex_exit(&ahci_ctlp->ahcictl_mutex);
     10619 +                cmn_err(CE_WARN, "!ahci%d: enclosure timed out resetting",
     10620 +                    ddi_get_instance(ahci_ctlp->ahcictl_dip));
     10621 +                return;
     10622 +        }
     10623 +
     10624 +        for (i = 0; i < ahci_ctlp->ahcictl_num_ports; i++) {
     10625 +
     10626 +                if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, i))
     10627 +                        continue;
     10628 +
     10629 +                /*
     10630 +                 * Try to flush all the LEDs as part of reset. If it fails,
     10631 +                 * drive on.
     10632 +                 */
     10633 +                if (!ahci_em_set_led(ahci_ctlp, i,
     10634 +                    ahci_ctlp->ahcictl_em_state[i])) {
     10635 +                        mutex_enter(&ahci_ctlp->ahcictl_mutex);
     10636 +                        ahci_ctlp->ahcictl_em_flags &= ~AHCI_EM_RESETTING;
     10637 +                        ahci_ctlp->ahcictl_em_flags |= AHCI_EM_TIMEOUT;
     10638 +                        mutex_exit(&ahci_ctlp->ahcictl_mutex);
     10639 +                        cmn_err(CE_WARN, "!ahci%d: enclosure timed out "
     10640 +                            "setting port %u",
     10641 +                            ddi_get_instance(ahci_ctlp->ahcictl_dip), i);
     10642 +                        return;
     10643 +                }
     10644 +        }
     10645 +
     10646 +        mutex_enter(&ahci_ctlp->ahcictl_mutex);
     10647 +        ahci_ctlp->ahcictl_em_flags &= ~AHCI_EM_RESETTING;
     10648 +        ahci_ctlp->ahcictl_em_flags |= AHCI_EM_READY;
     10649 +        mutex_exit(&ahci_ctlp->ahcictl_mutex);
     10650 +}
     10651 +
     10652 +static boolean_t
     10653 +ahci_em_init(ahci_ctl_t *ahci_ctlp)
     10654 +{
     10655 +        char name[128];
     10656 +
     10657 +        /*
     10658 +         * First make sure we actually have enclosure services and if so, that
     10659 +         * we have the hardware support that we care about for this.
     10660 +         */
     10661 +        if (ahci_ctlp->ahcictl_em_loc == 0 ||
     10662 +            (ahci_ctlp->ahcictl_em_ctl & AHCI_HBA_EM_CTL_SUPP_LED) == 0)
     10663 +                return (B_TRUE);
     10664 +
     10665 +        /*
     10666 +         * Next, make sure that the buffer is large enough for us. We need two
     10667 +         * dwords or 8 bytes. The location register is stored in dwords.
     10668 +         */
     10669 +        if ((ahci_ctlp->ahcictl_em_loc & AHCI_HBA_EM_LOC_SZ_MASK) <
     10670 +            AHCI_EM_BUFFER_MIN) {
     10671 +                return (B_TRUE);
     10672 +        }
     10673 +
     10674 +        ahci_ctlp->ahcictl_em_flags |= AHCI_EM_PRESENT;
     10675 +
     10676 +        ahci_ctlp->ahcictl_em_tx_off = ((ahci_ctlp->ahcictl_em_loc &
     10677 +            AHCI_HBA_EM_LOC_OFST_MASK) >> AHCI_HBA_EM_LOC_OFST_SHIFT) * 4;
     10678 +        ahci_ctlp->ahcictl_em_tx_off += ahci_ctlp->ahcictl_ahci_addr;
     10679 +
     10680 +        bzero(ahci_ctlp->ahcictl_em_state,
     10681 +            sizeof (ahci_ctlp->ahcictl_em_state));
     10682 +
     10683 +        (void) snprintf(name, sizeof (name), "ahcti_em_taskq%d",
     10684 +            ddi_get_instance(ahci_ctlp->ahcictl_dip));
     10685 +        if ((ahci_ctlp->ahcictl_em_taskq =
     10686 +            ddi_taskq_create(ahci_ctlp->ahcictl_dip, name, 1,
     10687 +            TASKQ_DEFAULTPRI, 0)) == NULL) {
     10688 +                cmn_err(CE_WARN, "!ahci%d: ddi_tasq_create failed for em "
     10689 +                    "services", ddi_get_instance(ahci_ctlp->ahcictl_dip));
     10690 +                return (B_FALSE);
     10691 +        }
     10692 +
     10693 +        mutex_enter(&ahci_ctlp->ahcictl_mutex);
     10694 +        ahci_ctlp->ahcictl_em_flags |= AHCI_EM_RESETTING;
     10695 +        mutex_exit(&ahci_ctlp->ahcictl_mutex);
     10696 +        (void) ddi_taskq_dispatch(ahci_ctlp->ahcictl_em_taskq, ahci_em_reset,
     10697 +            ahci_ctlp, DDI_SLEEP);
     10698 +
     10699 +        return (B_TRUE);
     10700 +}
     10701 +
     10702 +static int
     10703 +ahci_em_ioctl_get(ahci_ctl_t *ahci_ctlp, intptr_t arg)
     10704 +{
     10705 +        int i;
     10706 +        ahci_ioc_em_get_t get;
     10707 +
     10708 +        bzero(&get, sizeof (get));
     10709 +        get.aiemg_nports = ahci_ctlp->ahcictl_ports_implemented;
     10710 +        if ((ahci_ctlp->ahcictl_em_ctl & AHCI_HBA_EM_CTL_ATTR_ALHD) == 0) {
     10711 +                get.aiemg_flags |= AHCI_EM_FLAG_CONTROL_ACTIVITY;
     10712 +        }
     10713 +
     10714 +        mutex_enter(&ahci_ctlp->ahcictl_mutex);
     10715 +        for (i = 0; i < ahci_ctlp->ahcictl_num_ports; i++) {
     10716 +                if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, i)) {
     10717 +                        continue;
     10718 +                }
     10719 +                get.aiemg_status[i] = ahci_ctlp->ahcictl_em_state[i];
     10720 +        }
     10721 +        mutex_exit(&ahci_ctlp->ahcictl_mutex);
     10722 +
     10723 +        if (ddi_copyout(&get, (void *)arg, sizeof (get), 0) != 0)
     10724 +                return (EFAULT);
     10725 +
     10726 +        return (0);
     10727 +}
     10728 +
     10729 +static int
     10730 +ahci_em_ioctl_set(ahci_ctl_t *ahci_ctlp, intptr_t arg)
     10731 +{
     10732 +        int ret;
     10733 +        ahci_ioc_em_set_t set;
     10734 +        ahci_em_led_task_arg_t *task;
     10735 +        boolean_t signal, cleanup;
     10736 +
     10737 +        if (ddi_copyin((void *)arg, &set, sizeof (set), 0) != 0)
     10738 +                return (EFAULT);
     10739 +
     10740 +        if (set.aiems_port > ahci_ctlp->ahcictl_num_ports)
     10741 +                return (EINVAL);
     10742 +
     10743 +        if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, set.aiems_port)) {
     10744 +                return (EINVAL);
     10745 +        }
     10746 +
     10747 +        if ((set.aiems_leds & ~(AHCI_EM_LED_IDENT_ENABLE |
     10748 +            AHCI_EM_LED_FAULT_ENABLE |
     10749 +            AHCI_EM_LED_ACTIVITY_DISABLE)) != 0) {
     10750 +                return (EINVAL);
     10751 +        }
     10752 +
     10753 +        switch (set.aiems_op) {
     10754 +        case AHCI_EM_IOC_SET_OP_ADD:
     10755 +        case AHCI_EM_IOC_SET_OP_REM:
     10756 +        case AHCI_EM_IOC_SET_OP_SET:
     10757 +                break;
     10758 +        default:
     10759 +                return (EINVAL);
     10760 +        }
     10761 +
     10762 +        if ((set.aiems_leds & AHCI_EM_LED_ACTIVITY_DISABLE) != 0 &&
     10763 +            ((ahci_ctlp->ahcictl_em_ctl & AHCI_HBA_EM_CTL_ATTR_ALHD) != 0)) {
     10764 +                return (ENOTSUP);
     10765 +        }
     10766 +
     10767 +        task = kmem_alloc(sizeof (*task), KM_NOSLEEP | KM_NORMALPRI);
     10768 +        if (task == NULL) {
     10769 +                return (ENOMEM);
     10770 +        }
     10771 +
     10772 +        task->aelta_ctl = ahci_ctlp;
     10773 +        task->aelta_port = (uint8_t)set.aiems_port;
     10774 +        task->aelta_op = set.aiems_op;
     10775 +        task->aelta_state = set.aiems_leds;
     10776 +
     10777 +        cv_init(&task->aelta_cv, NULL, CV_DRIVER, NULL);
     10778 +
     10779 +        /*
     10780 +         * Initialize the reference count to two. One for us and one for the
     10781 +         * taskq. This will be used in case we get canceled.
     10782 +         */
     10783 +        task->aelta_ref = 2;
     10784 +
     10785 +        /*
     10786 +         * Once dispatched, the task state is protected by our global mutex.
     10787 +         */
     10788 +        (void) ddi_taskq_dispatch(ahci_ctlp->ahcictl_em_taskq,
     10789 +            ahci_em_led_task, task, DDI_SLEEP);
     10790 +
     10791 +        signal = B_FALSE;
     10792 +        mutex_enter(&ahci_ctlp->ahcictl_mutex);
     10793 +        while (task->aelta_ref > 1) {
     10794 +                if (cv_wait_sig(&task->aelta_cv, &ahci_ctlp->ahcictl_mutex) ==
     10795 +                    0) {
     10796 +                        signal = B_TRUE;
     10797 +                        break;
     10798 +                }
     10799 +        }
     10800 +
     10801 +        /*
     10802 +         * Remove our reference count. If we were woken up because of a signal
     10803 +         * then the taskq may still be dispatched. In which case we shouldn't
     10804 +         * free this memory until it is done. In that case, the taskq will take
     10805 +         * care of it.
     10806 +         */
     10807 +        task->aelta_ref--;
     10808 +        cleanup = (task->aelta_ref == 0);
     10809 +        if (signal) {
     10810 +                ret = EINTR;
     10811 +        } else {
     10812 +                ret = task->aelta_ret;
     10813 +        }
     10814 +        mutex_exit(&ahci_ctlp->ahcictl_mutex);
     10815 +
     10816 +        if (cleanup) {
     10817 +                ahci_em_led_task_free(task);
     10818 +        }
     10819 +
     10820 +        return (ret);
     10821 +}
     10822 +
     10823 +static int
     10824 +ahci_em_ioctl(dev_info_t *dip, int cmd, intptr_t arg)
     10825 +{
     10826 +        int inst;
     10827 +        ahci_ctl_t *ahci_ctlp;
     10828 +
     10829 +        inst = ddi_get_instance(dip);
     10830 +        if ((ahci_ctlp = ddi_get_soft_state(ahci_statep, inst)) == NULL) {
     10831 +                return (ENXIO);
     10832 +        }
     10833 +
     10834 +        switch (cmd) {
     10835 +        case AHCI_EM_IOC_GET:
     10836 +                return (ahci_em_ioctl_get(ahci_ctlp, arg));
     10837 +        case AHCI_EM_IOC_SET:
     10838 +                return (ahci_em_ioctl_set(ahci_ctlp, arg));
     10839 +        default:
     10840 +                return (ENOTTY);
     10841 +        }
     10842 +
     10843 +}
     10844 +
     10845 +static void
     10846 +ahci_em_quiesce(ahci_ctl_t *ahci_ctlp)
     10847 +{
     10848 +        ASSERT(ahci_ctlp->ahcictl_em_flags & AHCI_EM_PRESENT);
     10849 +
     10850 +        mutex_enter(&ahci_ctlp->ahcictl_mutex);
     10851 +        ahci_ctlp->ahcictl_em_flags |= AHCI_EM_QUIESCE;
     10852 +        mutex_exit(&ahci_ctlp->ahcictl_mutex);
     10853 +
     10854 +        ddi_taskq_wait(ahci_ctlp->ahcictl_em_taskq);
     10855 +}
     10856 +
     10857 +static void
     10858 +ahci_em_suspend(ahci_ctl_t *ahci_ctlp)
     10859 +{
     10860 +        ahci_em_quiesce(ahci_ctlp);
     10861 +
     10862 +        mutex_enter(&ahci_ctlp->ahcictl_mutex);
     10863 +        ahci_ctlp->ahcictl_em_flags &= ~AHCI_EM_READY;
     10864 +        mutex_exit(&ahci_ctlp->ahcictl_mutex);
     10865 +}
     10866 +
     10867 +static void
     10868 +ahci_em_resume(ahci_ctl_t *ahci_ctlp)
     10869 +{
     10870 +        mutex_enter(&ahci_ctlp->ahcictl_mutex);
     10871 +        ahci_ctlp->ahcictl_em_flags |= AHCI_EM_RESETTING;
     10872 +        mutex_exit(&ahci_ctlp->ahcictl_mutex);
     10873 +
     10874 +        (void) ddi_taskq_dispatch(ahci_ctlp->ahcictl_em_taskq, ahci_em_reset,
     10875 +            ahci_ctlp, DDI_SLEEP);
     10876 +}
     10877 +
     10878 +static void
     10879 +ahci_em_fini(ahci_ctl_t *ahci_ctlp)
     10880 +{
     10881 +        if ((ahci_ctlp->ahcictl_em_flags & AHCI_EM_PRESENT) == 0) {
     10882 +                return;
     10883 +        }
     10884 +
     10885 +        ahci_em_quiesce(ahci_ctlp);
     10886 +        ddi_taskq_destroy(ahci_ctlp->ahcictl_em_taskq);
     10887 +        ahci_ctlp->ahcictl_em_taskq = NULL;
10324 10888  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX