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 }
|