4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
  25  * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
  26  * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  27  * Copyright (c) 2017, Joyent, Inc.
  28  */
  29 
  30 /*
  31  * Copyright (c) 2000 to 2010, LSI Corporation.
  32  * All rights reserved.
  33  *
  34  * Redistribution and use in source and binary forms of all code within
  35  * this file that is exclusively owned by LSI, with or without
  36  * modification, is permitted provided that, in addition to the CDDL 1.0
  37  * License requirements, the following conditions are met:
  38  *
  39  *    Neither the name of the author nor the names of its contributors may be
  40  *    used to endorse or promote products derived from this software without
  41  *    specific prior written permission.
  42  *
  43  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  44  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
 
 528         /*
 529          * cmd_rfm points to the reply message if a reply was given.  The reply
 530          * frame and the config page are returned from this function in the
 531          * param list.
 532          */
 533         if (cmd->cmd_rfm) {
 534                 config_flags |= MPTSAS_ADDRESS_REPLY;
 535                 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
 536                     DDI_DMA_SYNC_FORCPU);
 537                 (void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
 538                     DDI_DMA_SYNC_FORCPU);
 539                 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
 540                     - (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
 541                 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
 542                     &reply->IOCStatus);
 543                 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
 544                 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
 545                     &reply->IOCLogInfo);
 546         }
 547 
 548         if (callback(mpt, page_memp, accessp, iocstatus, iocloginfo, ap)) {
 549                 rval = DDI_FAILURE;
 550                 goto page_done;
 551         }
 552 
 553         mptsas_fma_check(mpt, cmd);
 554         /*
 555          * Check the DMA/ACC handles and then free the DMA buffer.
 556          */
 557         if ((mptsas_check_dma_handle(cmd->cmd_dmahandle) != DDI_SUCCESS) ||
 558             (mptsas_check_acc_handle(accessp) != DDI_SUCCESS)) {
 559                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
 560                 rval = DDI_FAILURE;
 561         }
 562 
 563         if (pkt->pkt_reason == CMD_TRAN_ERR) {
 564                 mptsas_log(mpt, CE_WARN, "config fma error");
 565                 rval = DDI_FAILURE;
 566                 goto page_done;
 567         }
 568         if (pkt->pkt_reason == CMD_RESET) {
 
1092         /*
1093          * In order to avoid allocating variables on the stack,
1094          * we make use of the pre-existing mptsas_cmd_t and
1095          * scsi_pkt which are included in the mptsas_t which
1096          * is passed to this routine.
1097          */
1098 
1099         pMpi2SCSITaskManagementRequest_t        task;
1100         int                                     rval = FALSE;
1101         mptsas_cmd_t                            *cmd;
1102         struct scsi_pkt                         *pkt;
1103         mptsas_slots_t                          *slots = mpt->m_active;
1104         uint64_t                                request_desc, i;
1105         pMPI2DefaultReply_t                     reply_msg;
1106 
1107         /*
1108          * Can't start another task management routine.
1109          */
1110         if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
1111                 mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
1112                     " command at a time\n");
1113                 return (FALSE);
1114         }
1115 
1116         cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
1117         pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
1118 
1119         bzero((caddr_t)cmd, sizeof (*cmd));
1120         bzero((caddr_t)pkt, scsi_pkt_size());
1121 
1122         pkt->pkt_cdbp                = (opaque_t)&cmd->cmd_cdb[0];
1123         pkt->pkt_scbp                = (opaque_t)&cmd->cmd_scb;
1124         pkt->pkt_ha_private  = (opaque_t)cmd;
1125         pkt->pkt_flags               = (FLAG_NOINTR | FLAG_HEAD);
1126         pkt->pkt_time                = 60;
1127         pkt->pkt_address.a_target = dev_handle;
1128         pkt->pkt_address.a_lun = (uchar_t)lun;
1129         cmd->cmd_pkt         = pkt;
1130         cmd->cmd_scblen              = 1;
1131         cmd->cmd_flags               = CFLAG_TM_CMD;
1132         cmd->cmd_slot                = MPTSAS_TM_SLOT(mpt);
 
1303          */
1304 
1305         ddi_dma_attr_t          flsh_dma_attrs;
1306         ddi_dma_cookie_t        flsh_cookie;
1307         ddi_dma_handle_t        flsh_dma_handle;
1308         ddi_acc_handle_t        flsh_accessp;
1309         caddr_t                 memp, flsh_memp;
1310         mptsas_cmd_t            *cmd;
1311         struct scsi_pkt         *pkt;
1312         int                     i;
1313         int                     rvalue = 0;
1314         uint64_t                request_desc;
1315 
1316         if (mpt->m_MPI25 && !mptsas_enable_mpi25_flashupdate) {
1317                 /*
1318                  * The code is there but not tested yet.
1319                  * User has to know there are risks here.
1320                  */
1321                 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): "
1322                     "Updating firmware through MPI 2.5 has not been "
1323                     "tested yet!\n"
1324                     "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
1325                 return (-1);
1326         } /* Otherwise, you pay your money and you take your chances. */
1327 
1328         if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1329                 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1330                     "failed. event ack command pool is full\n");
1331                 return (rvalue);
1332         }
1333 
1334         bzero((caddr_t)cmd, sizeof (*cmd));
1335         bzero((caddr_t)pkt, scsi_pkt_size());
1336         cmd->ioc_cmd_slot = (uint32_t)rvalue;
1337 
1338         /*
1339          * dynamically create a customized dma attribute structure
1340          * that describes the flash file.
1341          */
1342         flsh_dma_attrs = mpt->m_msg_dma_attr;
1343         flsh_dma_attrs.dma_attr_sgllen = 1;
1344 
1345         if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1346             &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1347                 mptsas_log(mpt, CE_WARN,
1348                     "(unable to allocate dma resource.");
1349                 mptsas_return_to_pool(mpt, cmd);
1350                 return (-1);
 
1690         int i, num_phys;
1691         uint32_t cpdi[MPTSAS_MAX_PHYS], *retrypage0, *readpage1;
1692         uint8_t port_flags;
1693 
1694         if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1695                 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
1696                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1697                     iocstatus, iocloginfo);
1698                 rval = DDI_FAILURE;
1699                 return (rval);
1700         }
1701         readpage1 = va_arg(ap, uint32_t *);
1702         retrypage0 = va_arg(ap, uint32_t *);
1703 
1704         sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1705 
1706         num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
1707         /*
1708          * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1709          * was initially set.  This should never change throughout the life of
1710          * the driver.
1711          */
1712         ASSERT(num_phys == mpt->m_num_phys);
1713         for (i = 0; i < num_phys; i++) {
1714                 cpdi[i] = ddi_get32(accessp,
1715                     &sasioupage0->PhyData[i].
1716                     ControllerPhyDeviceInfo);
1717                 port_flags = ddi_get8(accessp,
1718                     &sasioupage0->PhyData[i].PortFlags);
1719                 mpt->m_phy_info[i].port_num =
1720                     ddi_get8(accessp,
1721                     &sasioupage0->PhyData[i].Port);
1722                 mpt->m_phy_info[i].ctrl_devhdl =
1723                     ddi_get16(accessp, &sasioupage0->
1724                     PhyData[i].ControllerDevHandle);
1725                 mpt->m_phy_info[i].attached_devhdl =
1726                     ddi_get16(accessp, &sasioupage0->
1727                     PhyData[i].AttachedDevHandle);
1728                 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1729                 mpt->m_phy_info[i].port_flags = port_flags;
1730 
1731                 if (port_flags & DISCOVERY_IN_PROGRESS) {
1732                         *retrypage0 = *retrypage0 + 1;
 
1754 #ifndef __lock_lint
1755         _NOTE(ARGUNUSED(ap))
1756 #endif
1757         int rval = DDI_SUCCESS;
1758         pMpi2SasIOUnitPage1_t sasioupage1;
1759         int i, num_phys;
1760         uint32_t cpdi[MPTSAS_MAX_PHYS];
1761         uint8_t port_flags;
1762 
1763         if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1764                 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
1765                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1766                     iocstatus, iocloginfo);
1767                 rval = DDI_FAILURE;
1768                 return (rval);
1769         }
1770 
1771         sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1772         num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
1773         /*
1774          * ASSERT that the num_phys value in SAS IO Unit Page 1 is the same as
1775          * was initially set.  This should never change throughout the life of
1776          * the driver.
1777          */
1778         ASSERT(num_phys == mpt->m_num_phys);
1779         for (i = 0; i < num_phys; i++) {
1780                 cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
1781                     ControllerPhyDeviceInfo);
1782                 port_flags = ddi_get8(accessp,
1783                     &sasioupage1->PhyData[i].PortFlags);
1784                 mpt->m_phy_info[i].port_num =
1785                     ddi_get8(accessp,
1786                     &sasioupage1->PhyData[i].Port);
1787                 mpt->m_phy_info[i].port_flags = port_flags;
1788                 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1789         }
1790         return (rval);
1791 }
1792 
1793 /*
1794  * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1795  * page1 to update the PHY information.  This is the message passing method of
1796  * this function which should be called except during initialization.
1797  */
1798 int
 
1915         return (rval);
1916 }
1917 
1918 /*
1919  * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1920  * page1 to update the PHY information.  This is the handshaking version of
1921  * this function, which should be called during initialization only.
1922  */
1923 int
1924 mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
1925 {
1926         ddi_dma_attr_t          recv_dma_attrs, page_dma_attrs;
1927         ddi_dma_cookie_t        page_cookie;
1928         ddi_dma_handle_t        recv_dma_handle, page_dma_handle;
1929         ddi_acc_handle_t        recv_accessp, page_accessp;
1930         pMpi2ConfigReply_t      configreply;
1931         pMpi2SasIOUnitPage0_t   sasioupage0;
1932         pMpi2SasIOUnitPage1_t   sasioupage1;
1933         int                     recv_numbytes;
1934         caddr_t                 recv_memp, page_memp;
1935         int                     i, num_phys, start_phy = 0;
1936         int                     page0_size =
1937             sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1938             (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1939         int                     page1_size =
1940             sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1941             (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1942         uint32_t                flags_length;
1943         uint32_t                cpdi[MPTSAS_MAX_PHYS];
1944         uint32_t                readpage1 = 0, retrypage0 = 0;
1945         uint16_t                iocstatus;
1946         uint8_t                 port_flags, page_number, action;
1947         uint32_t                reply_size;
1948         uint_t                  state;
1949         int                     rval = DDI_FAILURE;
1950         boolean_t               free_recv = B_FALSE, free_page = B_FALSE;
1951 
1952         /*
1953          * We want to find a reply_size that's large enough for the page0 and
1954          * page1 sizes and resistant to increase in the number of phys.
1955          */
 
2095                 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2096                 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2097 
2098                 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2099                         mptsas_log(mpt, CE_WARN,
2100                             "mptsas_get_sas_io_unit_page_hndshk: IO unit "
2101                             "config failed for action %d, iocstatus = 0x%x",
2102                             action, iocstatus);
2103                         goto cleanup;
2104                 }
2105 
2106                 switch (state) {
2107                 case IOUC_READ_PAGE0:
2108                         if ((ddi_dma_sync(page_dma_handle, 0, 0,
2109                             DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2110                                 goto cleanup;
2111                         }
2112 
2113                         num_phys = ddi_get8(page_accessp,
2114                             &sasioupage0->NumPhys);
2115                         ASSERT(num_phys == mpt->m_num_phys);
2116                         if (num_phys > MPTSAS_MAX_PHYS) {
2117                                 mptsas_log(mpt, CE_WARN, "Number of phys "
2118                                     "supported by HBA (%d) is more than max "
2119                                     "supported by driver (%d).  Driver will "
2120                                     "not attach.", num_phys,
2121                                     MPTSAS_MAX_PHYS);
2122                                 rval = DDI_FAILURE;
2123                                 goto cleanup;
2124                         }
2125                         for (i = start_phy; i < num_phys; i++, start_phy = i) {
2126                                 cpdi[i] = ddi_get32(page_accessp,
2127                                     &sasioupage0->PhyData[i].
2128                                     ControllerPhyDeviceInfo);
2129                                 port_flags = ddi_get8(page_accessp,
2130                                     &sasioupage0->PhyData[i].PortFlags);
2131 
2132                                 mpt->m_phy_info[i].port_num =
2133                                     ddi_get8(page_accessp,
2134                                     &sasioupage0->PhyData[i].Port);
2135                                 mpt->m_phy_info[i].ctrl_devhdl =
2136                                     ddi_get16(page_accessp, &sasioupage0->
2137                                     PhyData[i].ControllerDevHandle);
2138                                 mpt->m_phy_info[i].attached_devhdl =
2139                                     ddi_get16(page_accessp, &sasioupage0->
2140                                     PhyData[i].AttachedDevHandle);
2141                                 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2142                                 mpt->m_phy_info[i].port_flags = port_flags;
2143 
2144                                 if (port_flags & DISCOVERY_IN_PROGRESS) {
 
2176                                 break;
2177                         }
2178 
2179                         if (readpage1 == 0) {
2180                                 state = IOUC_DONE;
2181                                 rval = DDI_SUCCESS;
2182                                 break;
2183                         }
2184 
2185                         state = IOUC_READ_PAGE1;
2186                         break;
2187 
2188                 case IOUC_READ_PAGE1:
2189                         if ((ddi_dma_sync(page_dma_handle, 0, 0,
2190                             DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2191                                 goto cleanup;
2192                         }
2193 
2194                         num_phys = ddi_get8(page_accessp,
2195                             &sasioupage1->NumPhys);
2196                         ASSERT(num_phys == mpt->m_num_phys);
2197                         if (num_phys > MPTSAS_MAX_PHYS) {
2198                                 mptsas_log(mpt, CE_WARN, "Number of phys "
2199                                     "supported by HBA (%d) is more than max "
2200                                     "supported by driver (%d).  Driver will "
2201                                     "not attach.", num_phys,
2202                                     MPTSAS_MAX_PHYS);
2203                                 rval = DDI_FAILURE;
2204                                 goto cleanup;
2205                         }
2206                         for (i = 0; i < num_phys; i++) {
2207                                 cpdi[i] = ddi_get32(page_accessp,
2208                                     &sasioupage1->PhyData[i].
2209                                     ControllerPhyDeviceInfo);
2210                                 port_flags = ddi_get8(page_accessp,
2211                                     &sasioupage1->PhyData[i].PortFlags);
2212                                 mpt->m_phy_info[i].port_num =
2213                                     ddi_get8(page_accessp,
2214                                     &sasioupage1->PhyData[i].Port);
2215                                 mpt->m_phy_info[i].port_flags = port_flags;
2216                                 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2217 
2218                         }
2219 
2220                         state = IOUC_DONE;
2221                         rval = DDI_SUCCESS;
2222                         break;
2223                 }
2224         }
2225         if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
 
2290             (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2291                 rval = DDI_FAILURE;
2292                 goto done;
2293         }
2294         /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2295         free_recv = B_TRUE;
2296 
2297         bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2298         configreply = (pMpi2ConfigReply_t)recv_memp;
2299         recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2300 
2301         /*
2302          * get config reply message
2303          */
2304         if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2305             recv_accessp)) {
2306                 rval = DDI_FAILURE;
2307                 goto done;
2308         }
2309 
2310         if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2311                 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2312                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2313                     ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2314                 goto done;
2315         }
2316 
2317         /*
2318          * dynamically create a customized dma attribute structure
2319          * that describes the MPT's config page structure.
2320          */
2321         page_dma_attrs = mpt->m_msg_dma_attr;
2322         page_dma_attrs.dma_attr_sgllen = 1;
2323         page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2324 
2325         if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2326             &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2327             &page_cookie) == FALSE) {
2328                 rval = DDI_FAILURE;
2329                 goto done;
2330         }
 
2350 
2351         if (mptsas_send_config_request_msg(mpt,
2352             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2353             MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2354             ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2355             ddi_get8(recv_accessp, &configreply->Header.PageLength),
2356             flagslength, page_cookie.dmac_laddress)) {
2357                 rval = DDI_FAILURE;
2358                 goto done;
2359         }
2360 
2361         /*
2362          * get reply view handshake
2363          */
2364         if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2365             recv_accessp)) {
2366                 rval = DDI_FAILURE;
2367                 goto done;
2368         }
2369 
2370         if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2371                 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2372                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2373                     ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2374                 goto done;
2375         }
2376 
2377         (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2378 
2379         /*
2380          * Fusion-MPT stores fields in little-endian format.  This is
2381          * why the low-order 32 bits are stored first.
2382          */
2383         mpt->un.sasaddr.m_base_wwid_lo =
2384             ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
2385         mpt->un.sasaddr.m_base_wwid_hi =
2386             ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
2387 
2388         if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
2389             "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
2390                 NDBG2(("%s%d: failed to create base-wwid property",
2391                     ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2392         }
2393 
2394         /*
2395          * Set the number of PHYs present.
2396          */
2397         mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
2398 
2399         if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
2400             "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
2401                 NDBG2(("%s%d: failed to create num-phys property",
2402                     ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2403         }
2404 
2405         mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2406             mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
2407             (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2408 
2409         if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2410             (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2411                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2412                 rval = DDI_FAILURE;
2413                 goto done;
2414         }
2415         if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2416             (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2417                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2418                 rval = DDI_FAILURE;
2419         }
2420 done:
2421         /*
2422          * free up memory
2423          */
2424         if (free_recv)
2425                 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2426         if (free_page)
 
2537 
2538 static int
2539 mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
2540     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2541     va_list ap)
2542 {
2543 #ifndef __lock_lint
2544         _NOTE(ARGUNUSED(ap))
2545 #endif
2546         pMpi2SasPhyPage1_t      sasphypage;
2547         int                     rval = DDI_SUCCESS;
2548 
2549         uint32_t                *invalid_dword_count;
2550         uint32_t                *running_disparity_error_count;
2551         uint32_t                *loss_of_dword_sync_count;
2552         uint32_t                *phy_reset_problem_count;
2553         uint32_t                page_address;
2554 
2555         if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2556             (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2557                 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page1 "
2558                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2559                     iocstatus, iocloginfo);
2560                 rval = DDI_FAILURE;
2561                 return (rval);
2562         }
2563         page_address = va_arg(ap, uint32_t);
2564         /*
2565          * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2566          * are no more pages.  If everything is OK up to this point but the
2567          * status is INVALID_PAGE, change rval to FAILURE and quit.  Also,
2568          * signal that device traversal is complete.
2569          */
2570         if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2571                 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2572                     MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2573                         mpt->m_done_traverse_smp = 1;
2574                 }
2575                 rval = DDI_FAILURE;
2576                 return (rval);
2577         }
2578 
2579         invalid_dword_count = va_arg(ap, uint32_t *);
 
2668             NULL) == FALSE) {
2669                 rval = DDI_FAILURE;
2670                 goto done;
2671         }
2672         /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2673         free_recv = B_TRUE;
2674 
2675         bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2676         configreply = (pMpi2ConfigReply_t)recv_memp;
2677         recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2678 
2679         /*
2680          * get config reply message
2681          */
2682         if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2683             recv_accessp)) {
2684                 rval = DDI_FAILURE;
2685                 goto done;
2686         }
2687 
2688         if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2689                 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2690                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2691                     ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2692                 goto done;
2693         }
2694 
2695         /*
2696          * dynamically create a customized dma attribute structure
2697          * that describes the MPT's config page structure.
2698          */
2699         page_dma_attrs = mpt->m_msg_dma_attr;
2700         page_dma_attrs.dma_attr_sgllen = 1;
2701         page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2702 
2703         if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2704             &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2705             &page_cookie) == FALSE) {
2706                 rval = DDI_FAILURE;
2707                 goto done;
2708         }
 
2726 
2727         if (mptsas_send_config_request_msg(mpt,
2728             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2729             MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2730             ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2731             ddi_get8(recv_accessp, &configreply->Header.PageLength),
2732             flagslength, page_cookie.dmac_laddress)) {
2733                 rval = DDI_FAILURE;
2734                 goto done;
2735         }
2736 
2737         /*
2738          * get reply view handshake
2739          */
2740         if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2741             recv_accessp)) {
2742                 rval = DDI_FAILURE;
2743                 goto done;
2744         }
2745 
2746         if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2747                 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2748                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2749                     ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2750                 goto done;
2751         }
2752 
2753         (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2754 
2755         /*
2756          * Fusion-MPT stores fields in little-endian format.  This is
2757          * why the low-order 32 bits are stored first.
2758          */
2759 
2760         for (i = 0; i < 16; i++) {
2761                 mpt->m_MANU_page0.ChipName[i] =
2762                     ddi_get8(page_accessp,
2763                     (uint8_t *)(void *)&m0->ChipName[i]);
2764         }
2765 
2766         for (i = 0; i < 8; i++) {
 
2873  * Request information about the SES enclosures.
2874  */
2875 int
2876 mptsas_get_enclosure_page0(mptsas_t *mpt, uint32_t page_address,
2877     mptsas_enclosure_t *mep)
2878 {
2879         int rval = DDI_SUCCESS;
2880         Mpi2SasEnclosurePage0_t encpage;
2881 
2882         ASSERT(MUTEX_HELD(&mpt->m_mutex));
2883 
2884         bzero(&encpage, sizeof (encpage));
2885         rval = mptsas_access_config_page(mpt,
2886             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2887             MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE, 0, page_address,
2888             mptsas_enclosurepage_0_cb, page_address, &encpage);
2889 
2890         if (rval == DDI_SUCCESS) {
2891                 mep->me_enchdl = encpage.EnclosureHandle;
2892                 mep->me_flags = encpage.Flags;
2893         }
2894 
2895         return (rval);
2896 }
 | 
 
 
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
  25  * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
  26  * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  27  * Copyright (c) 2017, Joyent, Inc.
  28  */
  29 
  30 /*
  31  * Copyright (c) 2000 to 2010, LSI Corporation.
  32  * All rights reserved.
  33  *
  34  * Redistribution and use in source and binary forms of all code within
  35  * this file that is exclusively owned by LSI, with or without
  36  * modification, is permitted provided that, in addition to the CDDL 1.0
  37  * License requirements, the following conditions are met:
  38  *
  39  *    Neither the name of the author nor the names of its contributors may be
  40  *    used to endorse or promote products derived from this software without
  41  *    specific prior written permission.
  42  *
  43  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  44  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
 
 528         /*
 529          * cmd_rfm points to the reply message if a reply was given.  The reply
 530          * frame and the config page are returned from this function in the
 531          * param list.
 532          */
 533         if (cmd->cmd_rfm) {
 534                 config_flags |= MPTSAS_ADDRESS_REPLY;
 535                 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
 536                     DDI_DMA_SYNC_FORCPU);
 537                 (void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
 538                     DDI_DMA_SYNC_FORCPU);
 539                 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
 540                     - (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
 541                 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
 542                     &reply->IOCStatus);
 543                 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
 544                 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
 545                     &reply->IOCLogInfo);
 546         }
 547 
 548         if (callback(mpt, page_memp, accessp, iocstatus, iocloginfo, ap)
 549             != DDI_SUCCESS) {
 550                 rval = DDI_FAILURE;
 551                 goto page_done;
 552         }
 553 
 554         mptsas_fma_check(mpt, cmd);
 555         /*
 556          * Check the DMA/ACC handles and then free the DMA buffer.
 557          */
 558         if ((mptsas_check_dma_handle(cmd->cmd_dmahandle) != DDI_SUCCESS) ||
 559             (mptsas_check_acc_handle(accessp) != DDI_SUCCESS)) {
 560                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
 561                 rval = DDI_FAILURE;
 562         }
 563 
 564         if (pkt->pkt_reason == CMD_TRAN_ERR) {
 565                 mptsas_log(mpt, CE_WARN, "config fma error");
 566                 rval = DDI_FAILURE;
 567                 goto page_done;
 568         }
 569         if (pkt->pkt_reason == CMD_RESET) {
 
1093         /*
1094          * In order to avoid allocating variables on the stack,
1095          * we make use of the pre-existing mptsas_cmd_t and
1096          * scsi_pkt which are included in the mptsas_t which
1097          * is passed to this routine.
1098          */
1099 
1100         pMpi2SCSITaskManagementRequest_t        task;
1101         int                                     rval = FALSE;
1102         mptsas_cmd_t                            *cmd;
1103         struct scsi_pkt                         *pkt;
1104         mptsas_slots_t                          *slots = mpt->m_active;
1105         uint64_t                                request_desc, i;
1106         pMPI2DefaultReply_t                     reply_msg;
1107 
1108         /*
1109          * Can't start another task management routine.
1110          */
1111         if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
1112                 mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
1113                     " command at a time");
1114                 return (FALSE);
1115         }
1116 
1117         cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
1118         pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
1119 
1120         bzero((caddr_t)cmd, sizeof (*cmd));
1121         bzero((caddr_t)pkt, scsi_pkt_size());
1122 
1123         pkt->pkt_cdbp                = (opaque_t)&cmd->cmd_cdb[0];
1124         pkt->pkt_scbp                = (opaque_t)&cmd->cmd_scb;
1125         pkt->pkt_ha_private  = (opaque_t)cmd;
1126         pkt->pkt_flags               = (FLAG_NOINTR | FLAG_HEAD);
1127         pkt->pkt_time                = 60;
1128         pkt->pkt_address.a_target = dev_handle;
1129         pkt->pkt_address.a_lun = (uchar_t)lun;
1130         cmd->cmd_pkt         = pkt;
1131         cmd->cmd_scblen              = 1;
1132         cmd->cmd_flags               = CFLAG_TM_CMD;
1133         cmd->cmd_slot                = MPTSAS_TM_SLOT(mpt);
 
1304          */
1305 
1306         ddi_dma_attr_t          flsh_dma_attrs;
1307         ddi_dma_cookie_t        flsh_cookie;
1308         ddi_dma_handle_t        flsh_dma_handle;
1309         ddi_acc_handle_t        flsh_accessp;
1310         caddr_t                 memp, flsh_memp;
1311         mptsas_cmd_t            *cmd;
1312         struct scsi_pkt         *pkt;
1313         int                     i;
1314         int                     rvalue = 0;
1315         uint64_t                request_desc;
1316 
1317         if (mpt->m_MPI25 && !mptsas_enable_mpi25_flashupdate) {
1318                 /*
1319                  * The code is there but not tested yet.
1320                  * User has to know there are risks here.
1321                  */
1322                 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): "
1323                     "Updating firmware through MPI 2.5 has not been "
1324                     "tested yet!  "
1325                     "To enable set mptsas_enable_mpi25_flashupdate to 1.");
1326                 return (-1);
1327         } /* Otherwise, you pay your money and you take your chances. */
1328 
1329         if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1330                 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1331                     "failed. event ack command pool is full");
1332                 return (rvalue);
1333         }
1334 
1335         bzero((caddr_t)cmd, sizeof (*cmd));
1336         bzero((caddr_t)pkt, scsi_pkt_size());
1337         cmd->ioc_cmd_slot = (uint32_t)rvalue;
1338 
1339         /*
1340          * dynamically create a customized dma attribute structure
1341          * that describes the flash file.
1342          */
1343         flsh_dma_attrs = mpt->m_msg_dma_attr;
1344         flsh_dma_attrs.dma_attr_sgllen = 1;
1345 
1346         if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1347             &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1348                 mptsas_log(mpt, CE_WARN,
1349                     "(unable to allocate dma resource.");
1350                 mptsas_return_to_pool(mpt, cmd);
1351                 return (-1);
 
1691         int i, num_phys;
1692         uint32_t cpdi[MPTSAS_MAX_PHYS], *retrypage0, *readpage1;
1693         uint8_t port_flags;
1694 
1695         if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1696                 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
1697                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1698                     iocstatus, iocloginfo);
1699                 rval = DDI_FAILURE;
1700                 return (rval);
1701         }
1702         readpage1 = va_arg(ap, uint32_t *);
1703         retrypage0 = va_arg(ap, uint32_t *);
1704 
1705         sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1706 
1707         num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
1708         /*
1709          * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1710          * was initially set.  This should never change throughout the life of
1711          * the driver.  Note, due to cases where we've seen page zero have more
1712          * phys than the reported manufacturing information, we limit the number
1713          * of phys here to what we got from the manufacturing information.
1714          */
1715         ASSERT3U(num_phys, >=, mpt->m_num_phys);
1716         num_phys = mpt->m_num_phys;
1717         for (i = 0; i < num_phys; i++) {
1718                 cpdi[i] = ddi_get32(accessp,
1719                     &sasioupage0->PhyData[i].
1720                     ControllerPhyDeviceInfo);
1721                 port_flags = ddi_get8(accessp,
1722                     &sasioupage0->PhyData[i].PortFlags);
1723                 mpt->m_phy_info[i].port_num =
1724                     ddi_get8(accessp,
1725                     &sasioupage0->PhyData[i].Port);
1726                 mpt->m_phy_info[i].ctrl_devhdl =
1727                     ddi_get16(accessp, &sasioupage0->
1728                     PhyData[i].ControllerDevHandle);
1729                 mpt->m_phy_info[i].attached_devhdl =
1730                     ddi_get16(accessp, &sasioupage0->
1731                     PhyData[i].AttachedDevHandle);
1732                 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1733                 mpt->m_phy_info[i].port_flags = port_flags;
1734 
1735                 if (port_flags & DISCOVERY_IN_PROGRESS) {
1736                         *retrypage0 = *retrypage0 + 1;
 
1758 #ifndef __lock_lint
1759         _NOTE(ARGUNUSED(ap))
1760 #endif
1761         int rval = DDI_SUCCESS;
1762         pMpi2SasIOUnitPage1_t sasioupage1;
1763         int i, num_phys;
1764         uint32_t cpdi[MPTSAS_MAX_PHYS];
1765         uint8_t port_flags;
1766 
1767         if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1768                 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
1769                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1770                     iocstatus, iocloginfo);
1771                 rval = DDI_FAILURE;
1772                 return (rval);
1773         }
1774 
1775         sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1776         num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
1777         /*
1778          * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1779          * was initially set.  This should never change throughout the life of
1780          * the driver.  Note, due to cases where we've seen page zero have more
1781          * phys than the reported manufacturing information, we limit the number
1782          * of phys here to what we got from the manufacturing information.
1783          */
1784         ASSERT3U(num_phys, >=, mpt->m_num_phys);
1785         num_phys = mpt->m_num_phys;
1786         for (i = 0; i < num_phys; i++) {
1787                 cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
1788                     ControllerPhyDeviceInfo);
1789                 port_flags = ddi_get8(accessp,
1790                     &sasioupage1->PhyData[i].PortFlags);
1791                 mpt->m_phy_info[i].port_num =
1792                     ddi_get8(accessp,
1793                     &sasioupage1->PhyData[i].Port);
1794                 mpt->m_phy_info[i].port_flags = port_flags;
1795                 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1796         }
1797         return (rval);
1798 }
1799 
1800 /*
1801  * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1802  * page1 to update the PHY information.  This is the message passing method of
1803  * this function which should be called except during initialization.
1804  */
1805 int
 
1922         return (rval);
1923 }
1924 
1925 /*
1926  * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1927  * page1 to update the PHY information.  This is the handshaking version of
1928  * this function, which should be called during initialization only.
1929  */
1930 int
1931 mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
1932 {
1933         ddi_dma_attr_t          recv_dma_attrs, page_dma_attrs;
1934         ddi_dma_cookie_t        page_cookie;
1935         ddi_dma_handle_t        recv_dma_handle, page_dma_handle;
1936         ddi_acc_handle_t        recv_accessp, page_accessp;
1937         pMpi2ConfigReply_t      configreply;
1938         pMpi2SasIOUnitPage0_t   sasioupage0;
1939         pMpi2SasIOUnitPage1_t   sasioupage1;
1940         int                     recv_numbytes;
1941         caddr_t                 recv_memp, page_memp;
1942         uint_t                  i, num_phys, start_phy = 0;
1943         int                     page0_size =
1944             sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1945             (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1946         int                     page1_size =
1947             sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1948             (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1949         uint32_t                flags_length;
1950         uint32_t                cpdi[MPTSAS_MAX_PHYS];
1951         uint32_t                readpage1 = 0, retrypage0 = 0;
1952         uint16_t                iocstatus;
1953         uint8_t                 port_flags, page_number, action;
1954         uint32_t                reply_size;
1955         uint_t                  state;
1956         int                     rval = DDI_FAILURE;
1957         boolean_t               free_recv = B_FALSE, free_page = B_FALSE;
1958 
1959         /*
1960          * We want to find a reply_size that's large enough for the page0 and
1961          * page1 sizes and resistant to increase in the number of phys.
1962          */
 
2102                 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2103                 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2104 
2105                 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2106                         mptsas_log(mpt, CE_WARN,
2107                             "mptsas_get_sas_io_unit_page_hndshk: IO unit "
2108                             "config failed for action %d, iocstatus = 0x%x",
2109                             action, iocstatus);
2110                         goto cleanup;
2111                 }
2112 
2113                 switch (state) {
2114                 case IOUC_READ_PAGE0:
2115                         if ((ddi_dma_sync(page_dma_handle, 0, 0,
2116                             DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2117                                 goto cleanup;
2118                         }
2119 
2120                         num_phys = ddi_get8(page_accessp,
2121                             &sasioupage0->NumPhys);
2122                         if (num_phys > MPTSAS_MAX_PHYS) {
2123                                 mptsas_log(mpt, CE_WARN, "Number of phys "
2124                                     "supported by HBA (%d) is more than max "
2125                                     "supported by driver (%d).  Driver will "
2126                                     "not attach.", num_phys,
2127                                     MPTSAS_MAX_PHYS);
2128                                 rval = DDI_FAILURE;
2129                                 goto cleanup;
2130                         }
2131                         if (num_phys > mpt->m_num_phys) {
2132                                 mptsas_log(mpt, CE_WARN, "Number of phys "
2133                                     "reported by HBA SAS IO Unit Page 0 (%u) "
2134                                     "is greater than that reported by the "
2135                                     "manufacturing information (%u). Driver "
2136                                     "phy count limited to %u. Please contact "
2137                                     "the firmware vendor about this.", num_phys,
2138                                     mpt->m_num_phys, mpt->m_num_phys);
2139                                 num_phys = mpt->m_num_phys;
2140                         } else if (num_phys < mpt->m_num_phys) {
2141                                 mptsas_log(mpt, CE_WARN, "Number of phys "
2142                                     "reported by HBA SAS IO Unit Page 0 (%u) "
2143                                     "is less than that reported by the "
2144                                     "manufacturing information (%u). Driver "
2145                                     "will not attach. Please contact the "
2146                                     "firmware vendor about this.", num_phys,
2147                                     mpt->m_num_phys);
2148                                 rval = DDI_FAILURE;
2149                                 goto cleanup;
2150                         }
2151                         for (i = start_phy; i < num_phys; i++, start_phy = i) {
2152                                 cpdi[i] = ddi_get32(page_accessp,
2153                                     &sasioupage0->PhyData[i].
2154                                     ControllerPhyDeviceInfo);
2155                                 port_flags = ddi_get8(page_accessp,
2156                                     &sasioupage0->PhyData[i].PortFlags);
2157 
2158                                 mpt->m_phy_info[i].port_num =
2159                                     ddi_get8(page_accessp,
2160                                     &sasioupage0->PhyData[i].Port);
2161                                 mpt->m_phy_info[i].ctrl_devhdl =
2162                                     ddi_get16(page_accessp, &sasioupage0->
2163                                     PhyData[i].ControllerDevHandle);
2164                                 mpt->m_phy_info[i].attached_devhdl =
2165                                     ddi_get16(page_accessp, &sasioupage0->
2166                                     PhyData[i].AttachedDevHandle);
2167                                 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2168                                 mpt->m_phy_info[i].port_flags = port_flags;
2169 
2170                                 if (port_flags & DISCOVERY_IN_PROGRESS) {
 
2202                                 break;
2203                         }
2204 
2205                         if (readpage1 == 0) {
2206                                 state = IOUC_DONE;
2207                                 rval = DDI_SUCCESS;
2208                                 break;
2209                         }
2210 
2211                         state = IOUC_READ_PAGE1;
2212                         break;
2213 
2214                 case IOUC_READ_PAGE1:
2215                         if ((ddi_dma_sync(page_dma_handle, 0, 0,
2216                             DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2217                                 goto cleanup;
2218                         }
2219 
2220                         num_phys = ddi_get8(page_accessp,
2221                             &sasioupage1->NumPhys);
2222                         if (num_phys > MPTSAS_MAX_PHYS) {
2223                                 mptsas_log(mpt, CE_WARN, "Number of phys "
2224                                     "supported by HBA (%d) is more than max "
2225                                     "supported by driver (%d).  Driver will "
2226                                     "not attach.", num_phys,
2227                                     MPTSAS_MAX_PHYS);
2228                                 rval = DDI_FAILURE;
2229                                 goto cleanup;
2230                         }
2231                         if (num_phys > mpt->m_num_phys) {
2232                                 mptsas_log(mpt, CE_WARN, "Number of phys "
2233                                     "reported by HBA SAS IO Unit Page 1 (%u) "
2234                                     "is greater than that reported by the "
2235                                     "manufacturing information (%u). Limiting "
2236                                     "phy count to %u. Please contact the "
2237                                     "firmware vendor about this.", num_phys,
2238                                     mpt->m_num_phys, mpt->m_num_phys);
2239                                 num_phys = mpt->m_num_phys;
2240                         } else if (num_phys < mpt->m_num_phys) {
2241                                 mptsas_log(mpt, CE_WARN, "Number of phys "
2242                                     "reported by HBA SAS IO Unit Page 1 (%u) "
2243                                     "is less than that reported by the "
2244                                     "manufacturing information (%u). Driver "
2245                                     "will not attach. Please contact the "
2246                                     "firmware vendor about this.", num_phys,
2247                                     mpt->m_num_phys);
2248                                 rval = DDI_FAILURE;
2249                                 goto cleanup;
2250                         }
2251                         for (i = 0; i < num_phys; i++) {
2252                                 cpdi[i] = ddi_get32(page_accessp,
2253                                     &sasioupage1->PhyData[i].
2254                                     ControllerPhyDeviceInfo);
2255                                 port_flags = ddi_get8(page_accessp,
2256                                     &sasioupage1->PhyData[i].PortFlags);
2257                                 mpt->m_phy_info[i].port_num =
2258                                     ddi_get8(page_accessp,
2259                                     &sasioupage1->PhyData[i].Port);
2260                                 mpt->m_phy_info[i].port_flags = port_flags;
2261                                 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2262 
2263                         }
2264 
2265                         state = IOUC_DONE;
2266                         rval = DDI_SUCCESS;
2267                         break;
2268                 }
2269         }
2270         if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
 
2335             (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2336                 rval = DDI_FAILURE;
2337                 goto done;
2338         }
2339         /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2340         free_recv = B_TRUE;
2341 
2342         bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2343         configreply = (pMpi2ConfigReply_t)recv_memp;
2344         recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2345 
2346         /*
2347          * get config reply message
2348          */
2349         if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2350             recv_accessp)) {
2351                 rval = DDI_FAILURE;
2352                 goto done;
2353         }
2354 
2355         if ((iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) !=
2356             0) {
2357                 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2358                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2359                     ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2360                 goto done;
2361         }
2362 
2363         /*
2364          * dynamically create a customized dma attribute structure
2365          * that describes the MPT's config page structure.
2366          */
2367         page_dma_attrs = mpt->m_msg_dma_attr;
2368         page_dma_attrs.dma_attr_sgllen = 1;
2369         page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2370 
2371         if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2372             &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2373             &page_cookie) == FALSE) {
2374                 rval = DDI_FAILURE;
2375                 goto done;
2376         }
 
2396 
2397         if (mptsas_send_config_request_msg(mpt,
2398             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2399             MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2400             ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2401             ddi_get8(recv_accessp, &configreply->Header.PageLength),
2402             flagslength, page_cookie.dmac_laddress)) {
2403                 rval = DDI_FAILURE;
2404                 goto done;
2405         }
2406 
2407         /*
2408          * get reply view handshake
2409          */
2410         if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2411             recv_accessp)) {
2412                 rval = DDI_FAILURE;
2413                 goto done;
2414         }
2415 
2416         if ((iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) !=
2417             0) {
2418                 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2419                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2420                     ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2421                 goto done;
2422         }
2423 
2424         (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2425 
2426         /*
2427          * Fusion-MPT stores fields in little-endian format.  This is
2428          * why the low-order 32 bits are stored first.
2429          */
2430         mpt->un.sasaddr.m_base_wwid_lo =
2431             ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
2432         mpt->un.sasaddr.m_base_wwid_hi =
2433             ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
2434 
2435         if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
2436             "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
2437                 NDBG2(("%s%d: failed to create base-wwid property",
2438                     ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2439         }
2440 
2441         /*
2442          * Set the number of PHYs present.
2443          */
2444         mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
2445 
2446         if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
2447             "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
2448                 NDBG2(("%s%d: failed to create num-phys property",
2449                     ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2450         }
2451 
2452         mptsas_log(mpt, CE_NOTE, "Initiator WWNs: 0x%016llx-0x%016llx",
2453             (unsigned long long)mpt->un.m_base_wwid,
2454             (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2455 
2456         if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2457             (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2458                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2459                 rval = DDI_FAILURE;
2460                 goto done;
2461         }
2462         if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2463             (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2464                 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2465                 rval = DDI_FAILURE;
2466         }
2467 done:
2468         /*
2469          * free up memory
2470          */
2471         if (free_recv)
2472                 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2473         if (free_page)
 
2584 
2585 static int
2586 mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
2587     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2588     va_list ap)
2589 {
2590 #ifndef __lock_lint
2591         _NOTE(ARGUNUSED(ap))
2592 #endif
2593         pMpi2SasPhyPage1_t      sasphypage;
2594         int                     rval = DDI_SUCCESS;
2595 
2596         uint32_t                *invalid_dword_count;
2597         uint32_t                *running_disparity_error_count;
2598         uint32_t                *loss_of_dword_sync_count;
2599         uint32_t                *phy_reset_problem_count;
2600         uint32_t                page_address;
2601 
2602         if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2603             (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2604                 mptsas_log(mpt, CE_WARN, "%s "
2605                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2606                     __func__, iocstatus, iocloginfo);
2607                 rval = DDI_FAILURE;
2608                 return (rval);
2609         }
2610         page_address = va_arg(ap, uint32_t);
2611         /*
2612          * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2613          * are no more pages.  If everything is OK up to this point but the
2614          * status is INVALID_PAGE, change rval to FAILURE and quit.  Also,
2615          * signal that device traversal is complete.
2616          */
2617         if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2618                 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2619                     MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2620                         mpt->m_done_traverse_smp = 1;
2621                 }
2622                 rval = DDI_FAILURE;
2623                 return (rval);
2624         }
2625 
2626         invalid_dword_count = va_arg(ap, uint32_t *);
 
2715             NULL) == FALSE) {
2716                 rval = DDI_FAILURE;
2717                 goto done;
2718         }
2719         /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2720         free_recv = B_TRUE;
2721 
2722         bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2723         configreply = (pMpi2ConfigReply_t)recv_memp;
2724         recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2725 
2726         /*
2727          * get config reply message
2728          */
2729         if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2730             recv_accessp)) {
2731                 rval = DDI_FAILURE;
2732                 goto done;
2733         }
2734 
2735         if ((iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) !=
2736             0) {
2737                 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2738                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2739                     ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2740                 goto done;
2741         }
2742 
2743         /*
2744          * dynamically create a customized dma attribute structure
2745          * that describes the MPT's config page structure.
2746          */
2747         page_dma_attrs = mpt->m_msg_dma_attr;
2748         page_dma_attrs.dma_attr_sgllen = 1;
2749         page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2750 
2751         if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2752             &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2753             &page_cookie) == FALSE) {
2754                 rval = DDI_FAILURE;
2755                 goto done;
2756         }
 
2774 
2775         if (mptsas_send_config_request_msg(mpt,
2776             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2777             MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2778             ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2779             ddi_get8(recv_accessp, &configreply->Header.PageLength),
2780             flagslength, page_cookie.dmac_laddress)) {
2781                 rval = DDI_FAILURE;
2782                 goto done;
2783         }
2784 
2785         /*
2786          * get reply view handshake
2787          */
2788         if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2789             recv_accessp)) {
2790                 rval = DDI_FAILURE;
2791                 goto done;
2792         }
2793 
2794         if ((iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) !=
2795             0) {
2796                 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2797                     "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2798                     ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2799                 goto done;
2800         }
2801 
2802         (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2803 
2804         /*
2805          * Fusion-MPT stores fields in little-endian format.  This is
2806          * why the low-order 32 bits are stored first.
2807          */
2808 
2809         for (i = 0; i < 16; i++) {
2810                 mpt->m_MANU_page0.ChipName[i] =
2811                     ddi_get8(page_accessp,
2812                     (uint8_t *)(void *)&m0->ChipName[i]);
2813         }
2814 
2815         for (i = 0; i < 8; i++) {
 
2922  * Request information about the SES enclosures.
2923  */
2924 int
2925 mptsas_get_enclosure_page0(mptsas_t *mpt, uint32_t page_address,
2926     mptsas_enclosure_t *mep)
2927 {
2928         int rval = DDI_SUCCESS;
2929         Mpi2SasEnclosurePage0_t encpage;
2930 
2931         ASSERT(MUTEX_HELD(&mpt->m_mutex));
2932 
2933         bzero(&encpage, sizeof (encpage));
2934         rval = mptsas_access_config_page(mpt,
2935             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2936             MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE, 0, page_address,
2937             mptsas_enclosurepage_0_cb, page_address, &encpage);
2938 
2939         if (rval == DDI_SUCCESS) {
2940                 mep->me_enchdl = encpage.EnclosureHandle;
2941                 mep->me_flags = encpage.Flags;
2942                 mep->me_nslots = encpage.NumSlots;
2943                 mep->me_fslot = encpage.StartSlot;
2944                 mep->me_slotleds = NULL;
2945         }
2946 
2947         return (rval);
2948 }
 |