1 /*
2 * CDDL HEADER START
3 *
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) 2019, Joyent, Inc.
28 * Copyright 2023 Racktop Systems, Inc.
29 */
30
31 /*
32 * Copyright (c) 2000 to 2010, LSI Corporation.
33 * All rights reserved.
34 *
35 * Redistribution and use in source and binary forms of all code within
36 * this file that is exclusively owned by LSI, with or without
37 * modification, is permitted provided that, in addition to the CDDL 1.0
38 * License requirements, the following conditions are met:
39 *
40 * Neither the name of the author nor the names of its contributors may be
41 * used to endorse or promote products derived from this software without
42 * specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
45 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
46 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
47 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
48 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
50 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
51 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
52 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
53 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
54 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
55 * DAMAGE.
56 */
57
58 /*
59 * mptsas_impl - This file contains all the basic functions for communicating
60 * to MPT based hardware.
61 */
62
63 #if defined(lint) || defined(DEBUG)
64 #define MPTSAS_DEBUG
65 #endif
66
67 /*
68 * standard header files
69 */
70 #include <sys/note.h>
71 #include <sys/scsi/scsi.h>
72 #include <sys/pci.h>
73
74 #pragma pack(1)
75 #include <sys/scsi/adapters/mpi/mpi2_type.h>
76 #include <sys/scsi/adapters/mpi/mpi2.h>
77 #include <sys/scsi/adapters/mpi/mpi2_cnfg.h>
78 #include <sys/scsi/adapters/mpi/mpi2_init.h>
79 #include <sys/scsi/adapters/mpi/mpi2_ioc.h>
80 #include <sys/scsi/adapters/mpi/mpi2_sas.h>
81 #include <sys/scsi/adapters/mpi/mpi2_tool.h>
82 #pragma pack()
83
84 /*
85 * private header files.
86 */
87 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
88 #include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
89
90 /*
91 * FMA header files.
92 */
93 #include <sys/fm/io/ddi.h>
94
95 /*
96 * prototypes
97 */
98 static void mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd);
99 static void mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd);
100 static m_event_struct_t *mptsas_ioc_event_find_by_cmd(mptsas_t *mpt,
101 struct mptsas_cmd *cmd);
102
103 /*
104 * Use to read Host interface registers. May read up to 3 times for
105 * certain IOC's due to chip bug where zero can be erroneously returned
106 * when under high i/o load.
107 */
108 uint32_t
mptsas_hirrd(mptsas_t * mpt,uint32_t * regaddr)109 mptsas_hirrd(mptsas_t *mpt, uint32_t *regaddr)
110 {
111 int i, ntries;
112 uint32_t ret;
113
114 ntries = (mpt->m_is_sea_ioc == 1) ? 3 : 1;
115 for (i = 0; i < ntries; i++) {
116 if ((ret = ddi_get32(mpt->m_datap, regaddr)) != 0)
117 break;
118 }
119 return (ret);
120 }
121
122
123 /*
124 * add ioc evnet cmd into the queue
125 */
126 static void
mptsas_ioc_event_cmdq_add(mptsas_t * mpt,m_event_struct_t * cmd)127 mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd)
128 {
129 if ((cmd->m_event_linkp = mpt->m_ioc_event_cmdq) == NULL) {
130 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
131 mpt->m_ioc_event_cmdq = cmd;
132 } else {
133 cmd->m_event_linkp = NULL;
134 *(mpt->m_ioc_event_cmdtail) = cmd;
135 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
136 }
137 }
138
139 /*
140 * remove specified cmd from the ioc event queue
141 */
142 static void
mptsas_ioc_event_cmdq_delete(mptsas_t * mpt,m_event_struct_t * cmd)143 mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd)
144 {
145 m_event_struct_t *prev = mpt->m_ioc_event_cmdq;
146 if (prev == cmd) {
147 if ((mpt->m_ioc_event_cmdq = cmd->m_event_linkp) == NULL) {
148 mpt->m_ioc_event_cmdtail = &mpt->m_ioc_event_cmdq;
149 }
150 cmd->m_event_linkp = NULL;
151 return;
152 }
153 while (prev != NULL) {
154 if (prev->m_event_linkp == cmd) {
155 prev->m_event_linkp = cmd->m_event_linkp;
156 if (cmd->m_event_linkp == NULL) {
157 mpt->m_ioc_event_cmdtail = &prev->m_event_linkp;
158 }
159
160 cmd->m_event_linkp = NULL;
161 return;
162 }
163 prev = prev->m_event_linkp;
164 }
165 }
166
167 static m_event_struct_t *
mptsas_ioc_event_find_by_cmd(mptsas_t * mpt,struct mptsas_cmd * cmd)168 mptsas_ioc_event_find_by_cmd(mptsas_t *mpt, struct mptsas_cmd *cmd)
169 {
170 m_event_struct_t *ioc_cmd = NULL;
171
172 ioc_cmd = mpt->m_ioc_event_cmdq;
173 while (ioc_cmd != NULL) {
174 if (&(ioc_cmd->m_event_cmd) == cmd) {
175 return (ioc_cmd);
176 }
177 ioc_cmd = ioc_cmd->m_event_linkp;
178 }
179 ioc_cmd = NULL;
180 return (ioc_cmd);
181 }
182
183 void
mptsas_destroy_ioc_event_cmd(mptsas_t * mpt)184 mptsas_destroy_ioc_event_cmd(mptsas_t *mpt)
185 {
186 m_event_struct_t *ioc_cmd = NULL;
187 m_event_struct_t *ioc_cmd_tmp = NULL;
188 ioc_cmd = mpt->m_ioc_event_cmdq;
189
190 /*
191 * because the IOC event queue is resource of per instance for driver,
192 * it's not only ACK event commands used it, but also some others used
193 * it. We need destroy all ACK event commands when IOC reset, but can't
194 * disturb others.So we use filter to clear the ACK event cmd in ioc
195 * event queue, and other requests should be reserved, and they would
196 * be free by its owner.
197 */
198 while (ioc_cmd != NULL) {
199 if (ioc_cmd->m_event_cmd.cmd_flags & CFLAG_CMDACK) {
200 NDBG20(("destroy!! remove Ack Flag ioc_cmd\n"));
201 if ((mpt->m_ioc_event_cmdq =
202 ioc_cmd->m_event_linkp) == NULL)
203 mpt->m_ioc_event_cmdtail =
204 &mpt->m_ioc_event_cmdq;
205 ioc_cmd_tmp = ioc_cmd;
206 ioc_cmd = ioc_cmd->m_event_linkp;
207 kmem_free(ioc_cmd_tmp, M_EVENT_STRUCT_SIZE);
208 } else {
209 /*
210 * it's not ack cmd, so continue to check next one
211 */
212
213 NDBG20(("destroy!! it's not Ack Flag, continue\n"));
214 ioc_cmd = ioc_cmd->m_event_linkp;
215 }
216
217 }
218 }
219
220 void
mptsas_start_config_page_access(mptsas_t * mpt,mptsas_cmd_t * cmd)221 mptsas_start_config_page_access(mptsas_t *mpt, mptsas_cmd_t *cmd)
222 {
223 pMpi2ConfigRequest_t request;
224 pMpi2SGESimple64_t sge;
225 struct scsi_pkt *pkt = cmd->cmd_pkt;
226 mptsas_config_request_t *config = pkt->pkt_ha_private;
227 uint8_t direction;
228 uint32_t length, flagslength;
229 uint64_t request_desc;
230
231 ASSERT(mutex_owned(&mpt->m_mutex));
232
233 /*
234 * Point to the correct message and clear it as well as the global
235 * config page memory.
236 */
237 request = (pMpi2ConfigRequest_t)(mpt->m_req_frame +
238 (mpt->m_req_frame_size * cmd->cmd_slot));
239 bzero(request, mpt->m_req_frame_size);
240
241 /*
242 * Form the request message.
243 */
244 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Function,
245 MPI2_FUNCTION_CONFIG);
246 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Action, config->action);
247 direction = MPI2_SGE_FLAGS_IOC_TO_HOST;
248 length = 0;
249 sge = (pMpi2SGESimple64_t)&request->PageBufferSGE;
250 if (config->action == MPI2_CONFIG_ACTION_PAGE_HEADER) {
251 if (config->page_type > MPI2_CONFIG_PAGETYPE_MASK) {
252 ddi_put8(mpt->m_acc_req_frame_hdl,
253 &request->Header.PageType,
254 MPI2_CONFIG_PAGETYPE_EXTENDED);
255 ddi_put8(mpt->m_acc_req_frame_hdl,
256 &request->ExtPageType, config->page_type);
257 } else {
258 ddi_put8(mpt->m_acc_req_frame_hdl,
259 &request->Header.PageType, config->page_type);
260 }
261 } else {
262 ddi_put8(mpt->m_acc_req_frame_hdl, &request->ExtPageType,
263 config->ext_page_type);
264 ddi_put16(mpt->m_acc_req_frame_hdl, &request->ExtPageLength,
265 config->ext_page_length);
266 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageType,
267 config->page_type);
268 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageLength,
269 config->page_length);
270 ddi_put8(mpt->m_acc_req_frame_hdl,
271 &request->Header.PageVersion, config->page_version);
272 if ((config->page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
273 MPI2_CONFIG_PAGETYPE_EXTENDED) {
274 length = config->ext_page_length * 4;
275 } else {
276 length = config->page_length * 4;
277 }
278
279 if (config->action == MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
280 direction = MPI2_SGE_FLAGS_HOST_TO_IOC;
281 }
282 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
283 (uint32_t)cmd->cmd_dma_addr);
284 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
285 (uint32_t)(cmd->cmd_dma_addr >> 32));
286 }
287 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageNumber,
288 config->page_number);
289 ddi_put32(mpt->m_acc_req_frame_hdl, &request->PageAddress,
290 config->page_address);
291 flagslength = ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
292 MPI2_SGE_FLAGS_END_OF_BUFFER |
293 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
294 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
295 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
296 direction |
297 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
298 flagslength |= length;
299 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
300
301 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
302 DDI_DMA_SYNC_FORDEV);
303 request_desc = (cmd->cmd_slot << 16) +
304 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
305 cmd->cmd_rfm = 0;
306 MPTSAS_START_CMD(mpt, request_desc);
307 if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
308 DDI_SUCCESS) ||
309 (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
310 DDI_SUCCESS)) {
311 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
312 }
313 }
314
315 int
mptsas_access_config_page(mptsas_t * mpt,uint8_t action,uint8_t page_type,uint8_t page_number,uint32_t page_address,int (* callback)(mptsas_t *,caddr_t,ddi_acc_handle_t,uint16_t,uint32_t,va_list),...)316 mptsas_access_config_page(mptsas_t *mpt, uint8_t action, uint8_t page_type,
317 uint8_t page_number, uint32_t page_address, int (*callback) (mptsas_t *,
318 caddr_t, ddi_acc_handle_t, uint16_t, uint32_t, va_list), ...)
319 {
320 va_list ap;
321 ddi_dma_attr_t attrs;
322 ddi_dma_cookie_t cookie;
323 ddi_acc_handle_t accessp;
324 size_t len = 0;
325 mptsas_config_request_t config;
326 int rval = DDI_SUCCESS, config_flags = 0;
327 mptsas_cmd_t *cmd;
328 struct scsi_pkt *pkt;
329 pMpi2ConfigReply_t reply;
330 uint16_t iocstatus = 0;
331 uint32_t iocloginfo;
332 caddr_t page_memp;
333 boolean_t free_dma = B_FALSE;
334
335 va_start(ap, callback);
336 ASSERT(mutex_owned(&mpt->m_mutex));
337
338 /*
339 * Get a command from the pool.
340 */
341 if ((rval = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
342 mptsas_log(mpt, CE_NOTE, "command pool is full for config "
343 "page request");
344 rval = DDI_FAILURE;
345 goto page_done;
346 }
347 config_flags |= MPTSAS_REQUEST_POOL_CMD;
348
349 bzero((caddr_t)cmd, sizeof (*cmd));
350 bzero((caddr_t)pkt, scsi_pkt_size());
351 bzero((caddr_t)&config, sizeof (config));
352
353 /*
354 * Save the data for this request to be used in the call to start the
355 * config header request.
356 */
357 config.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
358 config.page_type = page_type;
359 config.page_number = page_number;
360 config.page_address = page_address;
361
362 /*
363 * Form a blank cmd/pkt to store the acknowledgement message
364 */
365 pkt->pkt_ha_private = (opaque_t)&config;
366 pkt->pkt_flags = FLAG_HEAD;
367 pkt->pkt_time = 60;
368 cmd->cmd_pkt = pkt;
369 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_CONFIG;
370
371 /*
372 * Save the config header request message in a slot.
373 */
374 if (mptsas_save_cmd(mpt, cmd) == TRUE) {
375 cmd->cmd_flags |= CFLAG_PREPARED;
376 mptsas_start_config_page_access(mpt, cmd);
377 } else {
378 mptsas_waitq_add(mpt, cmd);
379 }
380
381 /*
382 * If this is a request for a RAID info page, or any page called during
383 * the RAID info page request, poll because these config page requests
384 * are nested. Poll to avoid data corruption due to one page's data
385 * overwriting the outer page request's data. This can happen when
386 * the mutex is released in cv_wait.
387 */
388 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
389 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
390 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
391 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
392 } else {
393 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
394 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
395 }
396 }
397
398 /*
399 * Check if the header request completed without timing out
400 */
401 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
402 config_flags |= MPTSAS_CMD_TIMEOUT;
403 mptsas_log(mpt, CE_WARN, "config header request timeout");
404 rval = DDI_FAILURE;
405 goto page_done;
406 }
407
408 /*
409 * cmd_rfm points to the reply message if a reply was given. Check the
410 * IOCStatus to make sure everything went OK with the header request.
411 */
412 if (cmd->cmd_rfm) {
413 config_flags |= MPTSAS_ADDRESS_REPLY;
414 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
415 DDI_DMA_SYNC_FORCPU);
416 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
417 - (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
418 config.page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
419 &reply->Header.PageType);
420 config.page_number = ddi_get8(mpt->m_acc_reply_frame_hdl,
421 &reply->Header.PageNumber);
422 config.page_length = ddi_get8(mpt->m_acc_reply_frame_hdl,
423 &reply->Header.PageLength);
424 config.page_version = ddi_get8(mpt->m_acc_reply_frame_hdl,
425 &reply->Header.PageVersion);
426 config.ext_page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
427 &reply->ExtPageType);
428 config.ext_page_length = ddi_get16(mpt->m_acc_reply_frame_hdl,
429 &reply->ExtPageLength);
430
431 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
432 &reply->IOCStatus);
433 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
434 &reply->IOCLogInfo);
435
436 if (iocstatus) {
437 NDBG13(("mptsas_access_config_page header: "
438 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
439 iocloginfo));
440 rval = DDI_FAILURE;
441 goto page_done;
442 }
443
444 if ((config.page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
445 MPI2_CONFIG_PAGETYPE_EXTENDED)
446 len = (config.ext_page_length * 4);
447 else
448 len = (config.page_length * 4);
449
450 }
451
452 if (pkt->pkt_reason == CMD_RESET) {
453 mptsas_log(mpt, CE_WARN, "ioc reset abort config header "
454 "request");
455 rval = DDI_FAILURE;
456 goto page_done;
457 }
458
459 /*
460 * Put the reply frame back on the free queue, increment the free
461 * index, and write the new index to the free index register. But only
462 * if this reply is an ADDRESS reply.
463 */
464 if (config_flags & MPTSAS_ADDRESS_REPLY) {
465 ddi_put32(mpt->m_acc_free_queue_hdl,
466 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
467 cmd->cmd_rfm);
468 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
469 DDI_DMA_SYNC_FORDEV);
470 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
471 mpt->m_free_index = 0;
472 }
473 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
474 mpt->m_free_index);
475 config_flags &= (~MPTSAS_ADDRESS_REPLY);
476 }
477
478 /*
479 * Allocate DMA buffer here. Store the info regarding this buffer in
480 * the cmd struct so that it can be used for this specific command and
481 * de-allocated after the command completes. The size of the reply
482 * will not be larger than the reply frame size.
483 */
484 attrs = mpt->m_msg_dma_attr;
485 attrs.dma_attr_sgllen = 1;
486 attrs.dma_attr_granular = (uint32_t)len;
487
488 if (mptsas_dma_addr_create(mpt, attrs,
489 &cmd->cmd_dmahandle, &accessp, &page_memp,
490 len, &cookie) == FALSE) {
491 rval = DDI_FAILURE;
492 mptsas_log(mpt, CE_WARN,
493 "mptsas_dma_addr_create(len=0x%x) failed", (int)len);
494 goto page_done;
495 }
496 /* NOW we can safely call mptsas_dma_addr_destroy(). */
497 free_dma = B_TRUE;
498
499 cmd->cmd_dma_addr = cookie.dmac_laddress;
500 bzero(page_memp, len);
501
502 /*
503 * Save the data for this request to be used in the call to start the
504 * config page read
505 */
506 config.action = action;
507 config.page_address = page_address;
508
509 /*
510 * Re-use the cmd that was used to get the header. Reset some of the
511 * values.
512 */
513 bzero((caddr_t)pkt, scsi_pkt_size());
514 pkt->pkt_ha_private = (opaque_t)&config;
515 pkt->pkt_flags = FLAG_HEAD;
516 pkt->pkt_time = 60;
517 cmd->cmd_flags = CFLAG_PREPARED | CFLAG_CMDIOC | CFLAG_CONFIG;
518
519 /*
520 * Send the config page request. cmd is re-used from header request.
521 */
522 mptsas_start_config_page_access(mpt, cmd);
523
524 /*
525 * If this is a request for a RAID info page, or any page called during
526 * the RAID info page request, poll because these config page requests
527 * are nested. Poll to avoid data corruption due to one page's data
528 * overwriting the outer page request's data. This can happen when
529 * the mutex is released in cv_wait.
530 */
531 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
532 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
533 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
534 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
535 } else {
536 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
537 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
538 }
539 }
540
541 /*
542 * Check if the request completed without timing out
543 */
544 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
545 config_flags |= MPTSAS_CMD_TIMEOUT;
546 mptsas_log(mpt, CE_WARN, "config page request timeout");
547 rval = DDI_FAILURE;
548 goto page_done;
549 }
550
551 /*
552 * cmd_rfm points to the reply message if a reply was given. The reply
553 * frame and the config page are returned from this function in the
554 * param list.
555 */
556 if (cmd->cmd_rfm) {
557 config_flags |= MPTSAS_ADDRESS_REPLY;
558 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
559 DDI_DMA_SYNC_FORCPU);
560 (void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
561 DDI_DMA_SYNC_FORCPU);
562 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
563 - (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
564 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
565 &reply->IOCStatus);
566 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
567 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
568 &reply->IOCLogInfo);
569 }
570
571 if (callback(mpt, page_memp, accessp, iocstatus, iocloginfo, ap)) {
572 rval = DDI_FAILURE;
573 goto page_done;
574 }
575
576 mptsas_fma_check(mpt, cmd);
577 /*
578 * Check the DMA/ACC handles and then free the DMA buffer.
579 */
580 if ((mptsas_check_dma_handle(cmd->cmd_dmahandle) != DDI_SUCCESS) ||
581 (mptsas_check_acc_handle(accessp) != DDI_SUCCESS)) {
582 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
583 rval = DDI_FAILURE;
584 }
585
586 if (pkt->pkt_reason == CMD_TRAN_ERR) {
587 mptsas_log(mpt, CE_WARN, "config fma error");
588 rval = DDI_FAILURE;
589 goto page_done;
590 }
591 if (pkt->pkt_reason == CMD_RESET) {
592 mptsas_log(mpt, CE_WARN, "ioc reset abort config request");
593 rval = DDI_FAILURE;
594 goto page_done;
595 }
596
597 page_done:
598 va_end(ap);
599 /*
600 * Put the reply frame back on the free queue, increment the free
601 * index, and write the new index to the free index register. But only
602 * if this reply is an ADDRESS reply.
603 */
604 if (config_flags & MPTSAS_ADDRESS_REPLY) {
605 ddi_put32(mpt->m_acc_free_queue_hdl,
606 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
607 cmd->cmd_rfm);
608 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
609 DDI_DMA_SYNC_FORDEV);
610 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
611 mpt->m_free_index = 0;
612 }
613 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
614 mpt->m_free_index);
615 }
616
617 if (free_dma)
618 mptsas_dma_addr_destroy(&cmd->cmd_dmahandle, &accessp);
619
620 if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
621 mptsas_remove_cmd(mpt, cmd);
622 config_flags &= (~MPTSAS_REQUEST_POOL_CMD);
623 }
624 if (config_flags & MPTSAS_REQUEST_POOL_CMD)
625 mptsas_return_to_pool(mpt, cmd);
626
627 if (config_flags & MPTSAS_CMD_TIMEOUT) {
628 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
629 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
630 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
631 }
632 }
633
634 return (rval);
635 }
636
637 int
mptsas_send_config_request_msg(mptsas_t * mpt,uint8_t action,uint8_t pagetype,uint32_t pageaddress,uint8_t pagenumber,uint8_t pageversion,uint8_t pagelength,uint32_t SGEflagslength,uint64_t SGEaddress)638 mptsas_send_config_request_msg(mptsas_t *mpt, uint8_t action, uint8_t pagetype,
639 uint32_t pageaddress, uint8_t pagenumber, uint8_t pageversion,
640 uint8_t pagelength, uint32_t SGEflagslength, uint64_t SGEaddress)
641 {
642 pMpi2ConfigRequest_t config;
643 int send_numbytes;
644
645 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
646 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
647 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
648 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
649 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
650 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType, pagetype);
651 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
652 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
653 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageLength, pagelength);
654 ddi_put32(mpt->m_hshk_acc_hdl,
655 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
656 ddi_put32(mpt->m_hshk_acc_hdl,
657 &config->PageBufferSGE.MpiSimple.u.Address64.Low, SGEaddress);
658 ddi_put32(mpt->m_hshk_acc_hdl,
659 &config->PageBufferSGE.MpiSimple.u.Address64.High,
660 SGEaddress >> 32);
661 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
662
663 /*
664 * Post message via handshake
665 */
666 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
667 mpt->m_hshk_acc_hdl)) {
668 return (-1);
669 }
670 return (0);
671 }
672
673 int
mptsas_send_extended_config_request_msg(mptsas_t * mpt,uint8_t action,uint8_t extpagetype,uint32_t pageaddress,uint8_t pagenumber,uint8_t pageversion,uint16_t extpagelength,uint32_t SGEflagslength,uint64_t SGEaddress)674 mptsas_send_extended_config_request_msg(mptsas_t *mpt, uint8_t action,
675 uint8_t extpagetype, uint32_t pageaddress, uint8_t pagenumber,
676 uint8_t pageversion, uint16_t extpagelength,
677 uint32_t SGEflagslength, uint64_t SGEaddress)
678 {
679 pMpi2ConfigRequest_t config;
680 int send_numbytes;
681
682 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
683 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
684 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
685 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
686 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
687 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType,
688 MPI2_CONFIG_PAGETYPE_EXTENDED);
689 ddi_put8(mpt->m_hshk_acc_hdl, &config->ExtPageType, extpagetype);
690 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
691 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
692 ddi_put16(mpt->m_hshk_acc_hdl, &config->ExtPageLength, extpagelength);
693 ddi_put32(mpt->m_hshk_acc_hdl,
694 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
695 ddi_put32(mpt->m_hshk_acc_hdl,
696 &config->PageBufferSGE.MpiSimple.u.Address64.Low, SGEaddress);
697 ddi_put32(mpt->m_hshk_acc_hdl,
698 &config->PageBufferSGE.MpiSimple.u.Address64.High,
699 SGEaddress >> 32);
700 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
701
702 /*
703 * Post message via handshake
704 */
705 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
706 mpt->m_hshk_acc_hdl)) {
707 return (-1);
708 }
709 return (0);
710 }
711
712 int
mptsas_ioc_wait_for_response(mptsas_t * mpt)713 mptsas_ioc_wait_for_response(mptsas_t *mpt)
714 {
715 int polls = 0;
716
717 while ((mptsas_hirrd(mpt,
718 &mpt->m_reg->HostInterruptStatus) & MPI2_HIS_IOP_DOORBELL_STATUS)) {
719 drv_usecwait(1000);
720 if (polls++ > 60000) {
721 return (-1);
722 }
723 }
724 return (0);
725 }
726
727 int
mptsas_ioc_wait_for_doorbell(mptsas_t * mpt)728 mptsas_ioc_wait_for_doorbell(mptsas_t *mpt)
729 {
730 int polls = 0;
731
732 while ((mptsas_hirrd(mpt,
733 &mpt->m_reg->HostInterruptStatus) & MPI2_HIM_DIM) == 0) {
734 drv_usecwait(1000);
735 if (polls++ > 300000) {
736 return (-1);
737 }
738 }
739 return (0);
740 }
741
742 int
mptsas_send_handshake_msg(mptsas_t * mpt,caddr_t memp,int numbytes,ddi_acc_handle_t accessp)743 mptsas_send_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
744 ddi_acc_handle_t accessp)
745 {
746 int i;
747
748 /*
749 * clean pending doorbells
750 */
751 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
752 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
753 ((MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) |
754 ((numbytes / 4) << MPI2_DOORBELL_ADD_DWORDS_SHIFT)));
755
756 if (mptsas_ioc_wait_for_doorbell(mpt)) {
757 NDBG19(("mptsas_send_handshake failed. Doorbell not ready\n"));
758 return (-1);
759 }
760
761 /*
762 * clean pending doorbells again
763 */
764 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
765
766 if (mptsas_ioc_wait_for_response(mpt)) {
767 NDBG19(("mptsas_send_handshake failed. Doorbell not "
768 "cleared\n"));
769 return (-1);
770 }
771
772 /*
773 * post handshake message
774 */
775 for (i = 0; (i < numbytes / 4); i++, memp += 4) {
776 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
777 ddi_get32(accessp, (uint32_t *)((void *)(memp))));
778 if (mptsas_ioc_wait_for_response(mpt)) {
779 NDBG19(("mptsas_send_handshake failed posting "
780 "message\n"));
781 return (-1);
782 }
783 }
784
785 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
786 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
787 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
788 return (-1);
789 }
790
791 return (0);
792 }
793
794 int
mptsas_get_handshake_msg(mptsas_t * mpt,caddr_t memp,int numbytes,ddi_acc_handle_t accessp)795 mptsas_get_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
796 ddi_acc_handle_t accessp)
797 {
798 int i, totalbytes, bytesleft;
799 uint16_t val;
800
801 /*
802 * wait for doorbell
803 */
804 if (mptsas_ioc_wait_for_doorbell(mpt)) {
805 NDBG19(("mptsas_get_handshake failed. Doorbell not ready\n"));
806 return (-1);
807 }
808
809 /*
810 * get first 2 bytes of handshake message to determine how much
811 * data we will be getting
812 */
813 for (i = 0; i < 2; i++, memp += 2) {
814 val = (mptsas_hirrd(mpt,
815 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
816 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
817 if (mptsas_ioc_wait_for_doorbell(mpt)) {
818 NDBG19(("mptsas_get_handshake failure getting initial"
819 " data\n"));
820 return (-1);
821 }
822 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
823 if (i == 1) {
824 totalbytes = (val & 0xFF) * 2;
825 }
826 }
827
828 /*
829 * If we are expecting less bytes than the message wants to send
830 * we simply save as much as we expected and then throw out the rest
831 * later
832 */
833 if (totalbytes > (numbytes / 2)) {
834 bytesleft = ((numbytes / 2) - 2);
835 } else {
836 bytesleft = (totalbytes - 2);
837 }
838
839 /*
840 * Get the rest of the data
841 */
842 for (i = 0; i < bytesleft; i++, memp += 2) {
843 val = (mptsas_hirrd(mpt,
844 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
845 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
846 if (mptsas_ioc_wait_for_doorbell(mpt)) {
847 NDBG19(("mptsas_get_handshake failure getting"
848 " main data\n"));
849 return (-1);
850 }
851 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
852 }
853
854 /*
855 * Sometimes the device will send more data than is expected
856 * This data is not used by us but needs to be cleared from
857 * ioc doorbell. So we just read the values and throw
858 * them out.
859 */
860 if (totalbytes > (numbytes / 2)) {
861 for (i = (numbytes / 2); i < totalbytes; i++) {
862 val = (mptsas_hirrd(mpt, &mpt->m_reg->Doorbell) &
863 MPI2_DOORBELL_DATA_MASK);
864 ddi_put32(mpt->m_datap,
865 &mpt->m_reg->HostInterruptStatus, 0);
866 if (mptsas_ioc_wait_for_doorbell(mpt)) {
867 NDBG19(("mptsas_get_handshake failure getting "
868 "extra garbage data\n"));
869 return (-1);
870 }
871 }
872 }
873
874 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
875
876 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
877 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
878 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
879 return (-1);
880 }
881
882 return (0);
883 }
884
885 int
mptsas_kick_start(mptsas_t * mpt)886 mptsas_kick_start(mptsas_t *mpt)
887 {
888 int polls = 0;
889 uint32_t diag_reg, ioc_state, saved_HCB_size;
890
891 /*
892 * Start a hard reset. Write magic number and wait 500 mSeconds.
893 */
894 MPTSAS_ENABLE_DRWE(mpt);
895 drv_usecwait(500000);
896
897 /*
898 * Read the current Diag Reg and save the Host Controlled Boot size.
899 */
900 diag_reg = mptsas_hirrd(mpt, &mpt->m_reg->HostDiagnostic);
901 saved_HCB_size = mptsas_hirrd(mpt, &mpt->m_reg->HCBSize);
902
903 /*
904 * Set Reset Adapter bit and wait 50 mSeconds.
905 */
906 diag_reg |= MPI2_DIAG_RESET_ADAPTER;
907 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
908 drv_usecwait(50000);
909
910 /*
911 * Poll, waiting for Reset Adapter bit to clear. 300 Seconds max
912 * (600000 * 500 = 300,000,000 uSeconds, 300 seconds).
913 * If no more adapter (all FF's), just return failure.
914 */
915 for (polls = 0; polls < 600000; polls++) {
916 diag_reg = mptsas_hirrd(mpt, &mpt->m_reg->HostDiagnostic);
917 if (diag_reg == 0xFFFFFFFF) {
918 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
919 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
920 return (DDI_FAILURE);
921 }
922 if (!(diag_reg & MPI2_DIAG_RESET_ADAPTER)) {
923 break;
924 }
925 drv_usecwait(500);
926 }
927 if (polls == 600000) {
928 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
929 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
930 return (DDI_FAILURE);
931 }
932
933 /*
934 * Check if adapter is in Host Boot Mode. If so, restart adapter
935 * assuming the HCB points to good FW.
936 * Set BootDeviceSel to HCDW (Host Code and Data Window).
937 */
938 if (diag_reg & MPI2_DIAG_HCB_MODE) {
939 diag_reg &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
940 diag_reg |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
941 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
942
943 /*
944 * Re-enable the HCDW.
945 */
946 ddi_put32(mpt->m_datap, &mpt->m_reg->HCBSize,
947 (saved_HCB_size | MPI2_HCB_SIZE_HCB_ENABLE));
948 }
949
950 /*
951 * Restart the adapter.
952 */
953 diag_reg &= ~MPI2_DIAG_HOLD_IOC_RESET;
954 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
955
956 /*
957 * Disable writes to the Host Diag register.
958 */
959 ddi_put32(mpt->m_datap, &mpt->m_reg->WriteSequence,
960 MPI2_WRSEQ_FLUSH_KEY_VALUE);
961
962 /*
963 * Wait 60 seconds max for FW to come to ready state.
964 */
965 for (polls = 0; polls < 60000; polls++) {
966 ioc_state = mptsas_hirrd(mpt, &mpt->m_reg->Doorbell);
967 if (ioc_state == 0xFFFFFFFF) {
968 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
969 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
970 return (DDI_FAILURE);
971 }
972 if ((ioc_state & MPI2_IOC_STATE_MASK) ==
973 MPI2_IOC_STATE_READY) {
974 break;
975 }
976 drv_usecwait(1000);
977 }
978 if (polls == 60000) {
979 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
980 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
981 return (DDI_FAILURE);
982 }
983
984 /*
985 * Clear the ioc ack events queue.
986 */
987 mptsas_destroy_ioc_event_cmd(mpt);
988
989 return (DDI_SUCCESS);
990 }
991
992 int
mptsas_ioc_reset(mptsas_t * mpt,int first_time)993 mptsas_ioc_reset(mptsas_t *mpt, int first_time)
994 {
995 int polls = 0;
996 uint32_t reset_msg;
997 uint32_t ioc_state;
998
999 ioc_state = mptsas_hirrd(mpt, &mpt->m_reg->Doorbell);
1000 /*
1001 * If chip is already in ready state then there is nothing to do.
1002 */
1003 if (ioc_state == MPI2_IOC_STATE_READY) {
1004 return (MPTSAS_NO_RESET);
1005 }
1006 /*
1007 * If the chip is already operational, we just need to send
1008 * it a message unit reset to put it back in the ready state
1009 */
1010 if (ioc_state & MPI2_IOC_STATE_OPERATIONAL) {
1011 /*
1012 * If the first time, try MUR anyway, because we haven't even
1013 * queried the card for m_event_replay and other capabilities.
1014 * Other platforms do it this way, we can still do a hard
1015 * reset if we need to, MUR takes less time than a full
1016 * adapter reset, and there are reports that some HW
1017 * combinations will lock up when receiving a hard reset.
1018 */
1019 if ((first_time || mpt->m_event_replay) &&
1020 (mpt->m_softstate & MPTSAS_SS_MSG_UNIT_RESET)) {
1021 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1022 reset_msg = MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET;
1023 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
1024 (reset_msg << MPI2_DOORBELL_FUNCTION_SHIFT));
1025 if (mptsas_ioc_wait_for_response(mpt)) {
1026 NDBG19(("mptsas_ioc_reset failure sending "
1027 "message_unit_reset\n"));
1028 goto hard_reset;
1029 }
1030
1031 /*
1032 * Wait no more than 60 seconds for chip to become
1033 * ready.
1034 */
1035 while ((mptsas_hirrd(mpt, &mpt->m_reg->Doorbell) &
1036 MPI2_IOC_STATE_READY) == 0x0) {
1037 drv_usecwait(1000);
1038 if (polls++ > 60000) {
1039 goto hard_reset;
1040 }
1041 }
1042
1043 /*
1044 * Save the last reset mode done on IOC which will be
1045 * helpful while resuming from suspension.
1046 */
1047 mpt->m_softstate |= MPTSAS_DID_MSG_UNIT_RESET;
1048
1049 /*
1050 * the message unit reset would do reset operations
1051 * clear reply and request queue, so we should clear
1052 * ACK event cmd.
1053 */
1054 mptsas_destroy_ioc_event_cmd(mpt);
1055 return (MPTSAS_SUCCESS_MUR);
1056 }
1057 }
1058 hard_reset:
1059 mpt->m_softstate &= ~MPTSAS_DID_MSG_UNIT_RESET;
1060 if (mptsas_kick_start(mpt) == DDI_FAILURE) {
1061 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
1062 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
1063 return (MPTSAS_RESET_FAIL);
1064 }
1065 return (MPTSAS_SUCCESS_HARDRESET);
1066 }
1067
1068
1069 int
mptsas_request_from_pool(mptsas_t * mpt,mptsas_cmd_t ** cmd,struct scsi_pkt ** pkt)1070 mptsas_request_from_pool(mptsas_t *mpt, mptsas_cmd_t **cmd,
1071 struct scsi_pkt **pkt)
1072 {
1073 m_event_struct_t *ioc_cmd = NULL;
1074
1075 ioc_cmd = kmem_zalloc(M_EVENT_STRUCT_SIZE, KM_SLEEP);
1076 if (ioc_cmd == NULL) {
1077 return (DDI_FAILURE);
1078 }
1079 ioc_cmd->m_event_linkp = NULL;
1080 mptsas_ioc_event_cmdq_add(mpt, ioc_cmd);
1081 *cmd = &(ioc_cmd->m_event_cmd);
1082 *pkt = &(ioc_cmd->m_event_pkt);
1083
1084 return (DDI_SUCCESS);
1085 }
1086
1087 void
mptsas_return_to_pool(mptsas_t * mpt,mptsas_cmd_t * cmd)1088 mptsas_return_to_pool(mptsas_t *mpt, mptsas_cmd_t *cmd)
1089 {
1090 m_event_struct_t *ioc_cmd = NULL;
1091
1092 ioc_cmd = mptsas_ioc_event_find_by_cmd(mpt, cmd);
1093 if (ioc_cmd == NULL) {
1094 return;
1095 }
1096
1097 mptsas_ioc_event_cmdq_delete(mpt, ioc_cmd);
1098 kmem_free(ioc_cmd, M_EVENT_STRUCT_SIZE);
1099 ioc_cmd = NULL;
1100 }
1101
1102 /*
1103 * NOTE: We should be able to queue TM requests in the controller to make this
1104 * a lot faster. If resetting all targets, for example, we can load the hi
1105 * priority queue with its limit and the controller will reply as they are
1106 * completed. This way, we don't have to poll for one reply at a time.
1107 * Think about enhancing this later.
1108 */
1109 int
mptsas_ioc_task_management(mptsas_t * mpt,int task_type,uint16_t dev_handle,int lun,uint8_t * reply,uint32_t reply_size,int mode)1110 mptsas_ioc_task_management(mptsas_t *mpt, int task_type, uint16_t dev_handle,
1111 int lun, uint8_t *reply, uint32_t reply_size, int mode)
1112 {
1113 /*
1114 * In order to avoid allocating variables on the stack,
1115 * we make use of the pre-existing mptsas_cmd_t and
1116 * scsi_pkt which are included in the mptsas_t which
1117 * is passed to this routine.
1118 */
1119
1120 pMpi2SCSITaskManagementRequest_t task;
1121 int rval = FALSE;
1122 mptsas_cmd_t *cmd;
1123 struct scsi_pkt *pkt;
1124 mptsas_slots_t *slots = mpt->m_active;
1125 uint64_t request_desc, i;
1126 pMPI2DefaultReply_t reply_msg;
1127
1128 /*
1129 * Can't start another task management routine.
1130 */
1131 if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
1132 mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
1133 " command at a time\n");
1134 return (FALSE);
1135 }
1136
1137 cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
1138 pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
1139
1140 bzero((caddr_t)cmd, sizeof (*cmd));
1141 bzero((caddr_t)pkt, scsi_pkt_size());
1142
1143 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1144 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1145 pkt->pkt_ha_private = (opaque_t)cmd;
1146 pkt->pkt_flags = (FLAG_NOINTR | FLAG_HEAD);
1147 pkt->pkt_time = 60;
1148 pkt->pkt_address.a_target = dev_handle;
1149 pkt->pkt_address.a_lun = (uchar_t)lun;
1150 cmd->cmd_pkt = pkt;
1151 cmd->cmd_scblen = 1;
1152 cmd->cmd_flags = CFLAG_TM_CMD;
1153 cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
1154
1155 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
1156
1157 /*
1158 * Store the TM message in memory location corresponding to the TM slot
1159 * number.
1160 */
1161 task = (pMpi2SCSITaskManagementRequest_t)(mpt->m_req_frame +
1162 (mpt->m_req_frame_size * cmd->cmd_slot));
1163 bzero(task, mpt->m_req_frame_size);
1164
1165 /*
1166 * form message for requested task
1167 */
1168 mptsas_init_std_hdr(mpt->m_acc_req_frame_hdl, task, dev_handle, lun, 0,
1169 MPI2_FUNCTION_SCSI_TASK_MGMT);
1170
1171 /*
1172 * Set the task type
1173 */
1174 ddi_put8(mpt->m_acc_req_frame_hdl, &task->TaskType, task_type);
1175
1176 /*
1177 * Send TM request using High Priority Queue.
1178 */
1179 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1180 DDI_DMA_SYNC_FORDEV);
1181 request_desc = (cmd->cmd_slot << 16) +
1182 MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1183 MPTSAS_START_CMD(mpt, request_desc);
1184 rval = mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
1185
1186 if (pkt->pkt_reason == CMD_INCOMPLETE)
1187 rval = FALSE;
1188
1189 /*
1190 * If a reply frame was used and there is a reply buffer to copy the
1191 * reply data into, copy it. If this fails, log a message, but don't
1192 * fail the TM request.
1193 */
1194 if (cmd->cmd_rfm && reply) {
1195 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
1196 DDI_DMA_SYNC_FORCPU);
1197 reply_msg = (pMPI2DefaultReply_t)
1198 (mpt->m_reply_frame + (cmd->cmd_rfm -
1199 (mpt->m_reply_frame_dma_addr & 0xffffffffu)));
1200 if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
1201 reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
1202 }
1203 mutex_exit(&mpt->m_mutex);
1204 for (i = 0; i < reply_size; i++) {
1205 if (ddi_copyout((uint8_t *)reply_msg + i, reply + i, 1,
1206 mode)) {
1207 mptsas_log(mpt, CE_WARN, "failed to copy out "
1208 "reply data for TM request");
1209 break;
1210 }
1211 }
1212 mutex_enter(&mpt->m_mutex);
1213 }
1214
1215 /*
1216 * clear the TM slot before returning
1217 */
1218 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
1219
1220 /*
1221 * If we lost our task management command
1222 * we need to reset the ioc
1223 */
1224 if (rval == FALSE) {
1225 mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
1226 "try to reset ioc to recovery!");
1227 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1228 if (mptsas_restart_ioc(mpt)) {
1229 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1230 rval = FAILED;
1231 }
1232 }
1233
1234 return (rval);
1235 }
1236
1237 /*
1238 * Complete firmware download frame for v2.0 cards.
1239 */
1240 static void
mptsas_uflash2(pMpi2FWDownloadRequest fwdownload,ddi_acc_handle_t acc_hdl,uint32_t size,uint8_t type,ddi_dma_cookie_t flsh_cookie)1241 mptsas_uflash2(pMpi2FWDownloadRequest fwdownload,
1242 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1243 ddi_dma_cookie_t flsh_cookie)
1244 {
1245 pMpi2FWDownloadTCSGE_t tcsge;
1246 pMpi2SGESimple64_t sge;
1247 uint32_t flagslength;
1248
1249 ddi_put8(acc_hdl, &fwdownload->Function,
1250 MPI2_FUNCTION_FW_DOWNLOAD);
1251 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1252 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1253 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1254 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1255
1256 tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
1257 ddi_put8(acc_hdl, &tcsge->ContextSize, 0);
1258 ddi_put8(acc_hdl, &tcsge->DetailsLength, 12);
1259 ddi_put8(acc_hdl, &tcsge->Flags, 0);
1260 ddi_put32(acc_hdl, &tcsge->ImageOffset, 0);
1261 ddi_put32(acc_hdl, &tcsge->ImageSize, size);
1262
1263 sge = (pMpi2SGESimple64_t)(tcsge + 1);
1264 flagslength = size;
1265 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
1266 MPI2_SGE_FLAGS_END_OF_BUFFER |
1267 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1268 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1269 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
1270 MPI2_SGE_FLAGS_HOST_TO_IOC |
1271 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
1272 ddi_put32(acc_hdl, &sge->FlagsLength, flagslength);
1273 ddi_put32(acc_hdl, &sge->Address.Low,
1274 flsh_cookie.dmac_address);
1275 ddi_put32(acc_hdl, &sge->Address.High,
1276 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1277 }
1278
1279 /*
1280 * Complete firmware download frame for v2.5 cards.
1281 */
1282 static void
mptsas_uflash25(pMpi25FWDownloadRequest fwdownload,ddi_acc_handle_t acc_hdl,uint32_t size,uint8_t type,ddi_dma_cookie_t flsh_cookie)1283 mptsas_uflash25(pMpi25FWDownloadRequest fwdownload,
1284 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1285 ddi_dma_cookie_t flsh_cookie)
1286 {
1287 pMpi2IeeeSgeSimple64_t sge;
1288 uint8_t flags;
1289
1290 ddi_put8(acc_hdl, &fwdownload->Function,
1291 MPI2_FUNCTION_FW_DOWNLOAD);
1292 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1293 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1294 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1295 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1296
1297 ddi_put32(acc_hdl, &fwdownload->ImageOffset, 0);
1298 ddi_put32(acc_hdl, &fwdownload->ImageSize, size);
1299
1300 sge = (pMpi2IeeeSgeSimple64_t)&fwdownload->SGL;
1301 flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
1302 MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
1303 MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
1304 ddi_put8(acc_hdl, &sge->Flags, flags);
1305 ddi_put32(acc_hdl, &sge->Length, size);
1306 ddi_put32(acc_hdl, &sge->Address.Low,
1307 flsh_cookie.dmac_address);
1308 ddi_put32(acc_hdl, &sge->Address.High,
1309 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1310 }
1311
1312 static int mptsas_enable_mpi25_flashupdate = 0;
1313
1314 int
mptsas_update_flash(mptsas_t * mpt,caddr_t ptrbuffer,uint32_t size,uint8_t type,int mode)1315 mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
1316 uint8_t type, int mode)
1317 {
1318
1319 /*
1320 * In order to avoid allocating variables on the stack,
1321 * we make use of the pre-existing mptsas_cmd_t and
1322 * scsi_pkt which are included in the mptsas_t which
1323 * is passed to this routine.
1324 */
1325
1326 ddi_dma_attr_t flsh_dma_attrs;
1327 ddi_dma_cookie_t flsh_cookie;
1328 ddi_dma_handle_t flsh_dma_handle;
1329 ddi_acc_handle_t flsh_accessp;
1330 caddr_t memp, flsh_memp;
1331 mptsas_cmd_t *cmd;
1332 struct scsi_pkt *pkt;
1333 int i;
1334 int rvalue = 0;
1335 uint64_t request_desc;
1336
1337 if (mpt->m_MPI25 && !mptsas_enable_mpi25_flashupdate) {
1338 /*
1339 * The code is there but not tested yet.
1340 * User has to know there are risks here.
1341 */
1342 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): "
1343 "Updating firmware through MPI 2.5 has not been "
1344 "tested yet!\n"
1345 "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
1346 return (-1);
1347 } /* Otherwise, you pay your money and you take your chances. */
1348
1349 if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1350 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1351 "failed. event ack command pool is full\n");
1352 return (rvalue);
1353 }
1354
1355 bzero((caddr_t)cmd, sizeof (*cmd));
1356 bzero((caddr_t)pkt, scsi_pkt_size());
1357 cmd->ioc_cmd_slot = (uint32_t)rvalue;
1358
1359 /*
1360 * dynamically create a customized dma attribute structure
1361 * that describes the flash file.
1362 */
1363 flsh_dma_attrs = mpt->m_msg_dma_attr;
1364 flsh_dma_attrs.dma_attr_sgllen = 1;
1365
1366 if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1367 &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1368 mptsas_log(mpt, CE_WARN,
1369 "(unable to allocate dma resource.");
1370 mptsas_return_to_pool(mpt, cmd);
1371 return (-1);
1372 }
1373
1374 bzero(flsh_memp, size);
1375
1376 for (i = 0; i < size; i++) {
1377 (void) ddi_copyin(ptrbuffer + i, flsh_memp + i, 1, mode);
1378 }
1379 (void) ddi_dma_sync(flsh_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
1380
1381 /*
1382 * form a cmd/pkt to store the fw download message
1383 */
1384 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1385 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1386 pkt->pkt_ha_private = (opaque_t)cmd;
1387 pkt->pkt_flags = FLAG_HEAD;
1388 pkt->pkt_time = 60;
1389 cmd->cmd_pkt = pkt;
1390 cmd->cmd_scblen = 1;
1391 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_FW_CMD;
1392
1393 /*
1394 * Save the command in a slot
1395 */
1396 if (mptsas_save_cmd(mpt, cmd) == FALSE) {
1397 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1398 mptsas_return_to_pool(mpt, cmd);
1399 return (-1);
1400 }
1401
1402 /*
1403 * Fill in fw download message
1404 */
1405 ASSERT(cmd->cmd_slot != 0);
1406 memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
1407 bzero(memp, mpt->m_req_frame_size);
1408
1409 if (mpt->m_MPI25)
1410 mptsas_uflash25((pMpi25FWDownloadRequest)memp,
1411 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1412 else
1413 mptsas_uflash2((pMpi2FWDownloadRequest)memp,
1414 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1415
1416 /*
1417 * Start command
1418 */
1419 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1420 DDI_DMA_SYNC_FORDEV);
1421 request_desc = (cmd->cmd_slot << 16) +
1422 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1423 cmd->cmd_rfm = 0;
1424 MPTSAS_START_CMD(mpt, request_desc);
1425
1426 rvalue = 0;
1427 (void) cv_reltimedwait(&mpt->m_fw_cv, &mpt->m_mutex,
1428 drv_usectohz(60 * MICROSEC), TR_CLOCK_TICK);
1429 if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
1430 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1431 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
1432 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1433 }
1434 rvalue = -1;
1435 }
1436 mptsas_remove_cmd(mpt, cmd);
1437 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1438
1439 return (rvalue);
1440 }
1441
1442 static int
mptsas_sasdevpage_0_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)1443 mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1444 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1445 va_list ap)
1446 {
1447 #ifndef __lock_lint
1448 _NOTE(ARGUNUSED(ap))
1449 #endif
1450 pMpi2SasDevicePage0_t sasdevpage;
1451 int rval = DDI_SUCCESS, i;
1452 uint8_t *sas_addr = NULL;
1453 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1454 uint16_t *devhdl, *bay_num, *enclosure;
1455 uint64_t *sas_wwn;
1456 uint32_t *dev_info;
1457 uint8_t *physport, *phynum;
1458 uint16_t *pdevhdl, *io_flags;
1459 uint32_t page_address;
1460
1461 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1462 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1463 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_device_page0 "
1464 "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
1465 iocstatus, iocloginfo);
1466 rval = DDI_FAILURE;
1467 return (rval);
1468 }
1469 page_address = va_arg(ap, uint32_t);
1470 /*
1471 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1472 * are no more pages. If everything is OK up to this point but the
1473 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1474 * signal that device traversal is complete.
1475 */
1476 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1477 if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
1478 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
1479 mpt->m_done_traverse_dev = 1;
1480 }
1481 rval = DDI_FAILURE;
1482 return (rval);
1483 }
1484 devhdl = va_arg(ap, uint16_t *);
1485 sas_wwn = va_arg(ap, uint64_t *);
1486 dev_info = va_arg(ap, uint32_t *);
1487 physport = va_arg(ap, uint8_t *);
1488 phynum = va_arg(ap, uint8_t *);
1489 pdevhdl = va_arg(ap, uint16_t *);
1490 bay_num = va_arg(ap, uint16_t *);
1491 enclosure = va_arg(ap, uint16_t *);
1492 io_flags = va_arg(ap, uint16_t *);
1493
1494 sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
1495
1496 *dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
1497 *devhdl = ddi_get16(accessp, &sasdevpage->DevHandle);
1498 sas_addr = (uint8_t *)(&sasdevpage->SASAddress);
1499 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1500 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1501 }
1502 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1503 *sas_wwn = LE_64(*sas_wwn);
1504 *physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
1505 *phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
1506 *pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
1507 *bay_num = ddi_get16(accessp, &sasdevpage->Slot);
1508 *enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
1509 *io_flags = ddi_get16(accessp, &sasdevpage->Flags);
1510
1511 if (*io_flags & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
1512 /*
1513 * Leave a messages about FP cabability in the log.
1514 */
1515 mptsas_log(mpt, CE_CONT,
1516 "!w%016"PRIx64" FastPath Capable%s", *sas_wwn,
1517 (*io_flags &
1518 MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)?
1519 " and Enabled":" but Disabled");
1520 }
1521
1522 return (rval);
1523 }
1524
1525 /*
1526 * Request MPI configuration page SAS device page 0 to get DevHandle, device
1527 * info and SAS address.
1528 */
1529 int
mptsas_get_sas_device_page0(mptsas_t * mpt,uint32_t page_address,uint16_t * dev_handle,uint64_t * sas_wwn,uint32_t * dev_info,uint8_t * physport,uint8_t * phynum,uint16_t * pdev_handle,uint16_t * bay_num,uint16_t * enclosure,uint16_t * io_flags)1530 mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
1531 uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
1532 uint8_t *physport, uint8_t *phynum, uint16_t *pdev_handle,
1533 uint16_t *bay_num, uint16_t *enclosure, uint16_t *io_flags)
1534 {
1535 int rval = DDI_SUCCESS;
1536
1537 ASSERT(mutex_owned(&mpt->m_mutex));
1538
1539 /*
1540 * Get the header and config page. reply contains the reply frame,
1541 * which holds status info for the request.
1542 */
1543 rval = mptsas_access_config_page(mpt,
1544 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1545 MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
1546 mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
1547 dev_info, physport, phynum, pdev_handle,
1548 bay_num, enclosure, io_flags);
1549
1550 return (rval);
1551 }
1552
1553 static int
mptsas_sasexpdpage_0_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)1554 mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1555 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1556 va_list ap)
1557 {
1558 #ifndef __lock_lint
1559 _NOTE(ARGUNUSED(ap))
1560 #endif
1561 pMpi2ExpanderPage0_t expddevpage;
1562 int rval = DDI_SUCCESS, i;
1563 uint8_t *sas_addr = NULL;
1564 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1565 uint16_t *devhdl;
1566 uint64_t *sas_wwn;
1567 uint8_t physport;
1568 mptsas_phymask_t *phymask;
1569 uint16_t *pdevhdl;
1570 uint32_t page_address;
1571
1572 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1573 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1574 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
1575 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1576 iocstatus, iocloginfo);
1577 rval = DDI_FAILURE;
1578 return (rval);
1579 }
1580 page_address = va_arg(ap, uint32_t);
1581 /*
1582 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1583 * are no more pages. If everything is OK up to this point but the
1584 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1585 * signal that device traversal is complete.
1586 */
1587 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1588 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
1589 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
1590 mpt->m_done_traverse_smp = 1;
1591 }
1592 rval = DDI_FAILURE;
1593 return (rval);
1594 }
1595 devhdl = va_arg(ap, uint16_t *);
1596 sas_wwn = va_arg(ap, uint64_t *);
1597 phymask = va_arg(ap, mptsas_phymask_t *);
1598 pdevhdl = va_arg(ap, uint16_t *);
1599
1600 expddevpage = (pMpi2ExpanderPage0_t)page_memp;
1601
1602 *devhdl = ddi_get16(accessp, &expddevpage->DevHandle);
1603 physport = ddi_get8(accessp, &expddevpage->PhysicalPort);
1604 *phymask = mptsas_physport_to_phymask(mpt, physport);
1605 *pdevhdl = ddi_get16(accessp, &expddevpage->ParentDevHandle);
1606 sas_addr = (uint8_t *)(&expddevpage->SASAddress);
1607 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1608 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1609 }
1610 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1611 *sas_wwn = LE_64(*sas_wwn);
1612
1613 return (rval);
1614 }
1615
1616 /*
1617 * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
1618 * and SAS address.
1619 */
1620 int
mptsas_get_sas_expander_page0(mptsas_t * mpt,uint32_t page_address,mptsas_smp_t * info)1621 mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
1622 mptsas_smp_t *info)
1623 {
1624 int rval = DDI_SUCCESS;
1625
1626 ASSERT(mutex_owned(&mpt->m_mutex));
1627
1628 /*
1629 * Get the header and config page. reply contains the reply frame,
1630 * which holds status info for the request.
1631 */
1632 rval = mptsas_access_config_page(mpt,
1633 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1634 MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
1635 mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
1636 &info->m_addr.mta_wwn, &info->m_addr.mta_phymask, &info->m_pdevhdl);
1637
1638 return (rval);
1639 }
1640
1641 static int
mptsas_sasportpage_0_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)1642 mptsas_sasportpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1643 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1644 va_list ap)
1645 {
1646 #ifndef __lock_lint
1647 _NOTE(ARGUNUSED(ap))
1648 #endif
1649 int rval = DDI_SUCCESS, i;
1650 uint8_t *sas_addr = NULL;
1651 uint64_t *sas_wwn;
1652 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1653 uint8_t *portwidth;
1654 pMpi2SasPortPage0_t sasportpage;
1655
1656 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1657 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_port_page0 "
1658 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1659 iocstatus, iocloginfo);
1660 rval = DDI_FAILURE;
1661 return (rval);
1662 }
1663 sas_wwn = va_arg(ap, uint64_t *);
1664 portwidth = va_arg(ap, uint8_t *);
1665
1666 sasportpage = (pMpi2SasPortPage0_t)page_memp;
1667 sas_addr = (uint8_t *)(&sasportpage->SASAddress);
1668 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1669 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1670 }
1671 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1672 *sas_wwn = LE_64(*sas_wwn);
1673 *portwidth = ddi_get8(accessp, &sasportpage->PortWidth);
1674 return (rval);
1675 }
1676
1677 /*
1678 * Request MPI configuration page SAS port page 0 to get initiator SAS address
1679 * and port width.
1680 */
1681 int
mptsas_get_sas_port_page0(mptsas_t * mpt,uint32_t page_address,uint64_t * sas_wwn,uint8_t * portwidth)1682 mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
1683 uint64_t *sas_wwn, uint8_t *portwidth)
1684 {
1685 int rval = DDI_SUCCESS;
1686
1687 ASSERT(mutex_owned(&mpt->m_mutex));
1688
1689 /*
1690 * Get the header and config page. reply contains the reply frame,
1691 * which holds status info for the request.
1692 */
1693 rval = mptsas_access_config_page(mpt,
1694 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1695 MPI2_CONFIG_EXTPAGETYPE_SAS_PORT, 0, page_address,
1696 mptsas_sasportpage_0_cb, sas_wwn, portwidth);
1697
1698 return (rval);
1699 }
1700
1701 static int
mptsas_sasiou_page_0_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)1702 mptsas_sasiou_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
1703 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1704 va_list ap)
1705 {
1706 #ifndef __lock_lint
1707 _NOTE(ARGUNUSED(ap))
1708 #endif
1709 int rval = DDI_SUCCESS;
1710 pMpi2SasIOUnitPage0_t sasioupage0;
1711 int i, num_phys;
1712 uint32_t cpdi[MPTSAS_MAX_PHYS], *retrypage0, *readpage1;
1713 uint8_t port_flags;
1714
1715 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1716 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
1717 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1718 iocstatus, iocloginfo);
1719 rval = DDI_FAILURE;
1720 return (rval);
1721 }
1722 readpage1 = va_arg(ap, uint32_t *);
1723 retrypage0 = va_arg(ap, uint32_t *);
1724
1725 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1726
1727 num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
1728 /*
1729 * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1730 * was initially set. This should never change throughout the life of
1731 * the driver. Note, due to cases where we've seen page zero have more
1732 * phys than the reported manufacturing information, we limit the number
1733 * of phys here to what we got from the manufacturing information.
1734 */
1735 ASSERT3U(num_phys, >=, mpt->m_num_phys);
1736 num_phys = mpt->m_num_phys;
1737 for (i = 0; i < num_phys; i++) {
1738 cpdi[i] = ddi_get32(accessp,
1739 &sasioupage0->PhyData[i].
1740 ControllerPhyDeviceInfo);
1741 port_flags = ddi_get8(accessp,
1742 &sasioupage0->PhyData[i].PortFlags);
1743 mpt->m_phy_info[i].port_num =
1744 ddi_get8(accessp,
1745 &sasioupage0->PhyData[i].Port);
1746 mpt->m_phy_info[i].ctrl_devhdl =
1747 ddi_get16(accessp, &sasioupage0->
1748 PhyData[i].ControllerDevHandle);
1749 mpt->m_phy_info[i].attached_devhdl =
1750 ddi_get16(accessp, &sasioupage0->
1751 PhyData[i].AttachedDevHandle);
1752 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1753 mpt->m_phy_info[i].port_flags = port_flags;
1754
1755 if (port_flags & DISCOVERY_IN_PROGRESS) {
1756 *retrypage0 = *retrypage0 + 1;
1757 break;
1758 } else {
1759 *retrypage0 = 0;
1760 }
1761 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
1762 /*
1763 * some PHY configuration described in
1764 * SAS IO Unit Page1
1765 */
1766 *readpage1 = 1;
1767 }
1768 }
1769
1770 return (rval);
1771 }
1772
1773 static int
mptsas_sasiou_page_1_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)1774 mptsas_sasiou_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
1775 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1776 va_list ap)
1777 {
1778 #ifndef __lock_lint
1779 _NOTE(ARGUNUSED(ap))
1780 #endif
1781 int rval = DDI_SUCCESS;
1782 pMpi2SasIOUnitPage1_t sasioupage1;
1783 int i, num_phys;
1784 uint32_t cpdi[MPTSAS_MAX_PHYS];
1785 uint8_t port_flags;
1786
1787 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1788 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
1789 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1790 iocstatus, iocloginfo);
1791 rval = DDI_FAILURE;
1792 return (rval);
1793 }
1794
1795 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1796 num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
1797 /*
1798 * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1799 * was initially set. This should never change throughout the life of
1800 * the driver. Note, due to cases where we've seen page zero have more
1801 * phys than the reported manufacturing information, we limit the number
1802 * of phys here to what we got from the manufacturing information.
1803 */
1804 ASSERT3U(num_phys, >=, mpt->m_num_phys);
1805 num_phys = mpt->m_num_phys;
1806 for (i = 0; i < num_phys; i++) {
1807 cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
1808 ControllerPhyDeviceInfo);
1809 port_flags = ddi_get8(accessp,
1810 &sasioupage1->PhyData[i].PortFlags);
1811 mpt->m_phy_info[i].port_num =
1812 ddi_get8(accessp,
1813 &sasioupage1->PhyData[i].Port);
1814 mpt->m_phy_info[i].port_flags = port_flags;
1815 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1816 }
1817 return (rval);
1818 }
1819
1820 /*
1821 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1822 * page1 to update the PHY information. This is the message passing method of
1823 * this function which should be called except during initialization.
1824 */
1825 int
mptsas_get_sas_io_unit_page(mptsas_t * mpt)1826 mptsas_get_sas_io_unit_page(mptsas_t *mpt)
1827 {
1828 int rval = DDI_SUCCESS, state;
1829 uint32_t readpage1 = 0, retrypage0 = 0;
1830
1831 ASSERT(mutex_owned(&mpt->m_mutex));
1832
1833 /*
1834 * Now we cycle through the state machine. Here's what happens:
1835 * 1. Read IO unit page 0 and set phy information
1836 * 2. See if Read IO unit page1 is needed because of port configuration
1837 * 3. Read IO unit page 1 and update phy information.
1838 */
1839 state = IOUC_READ_PAGE0;
1840 while (state != IOUC_DONE) {
1841 if (state == IOUC_READ_PAGE0) {
1842 rval = mptsas_access_config_page(mpt,
1843 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1844 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
1845 mptsas_sasiou_page_0_cb, &readpage1,
1846 &retrypage0);
1847 } else if (state == IOUC_READ_PAGE1) {
1848 rval = mptsas_access_config_page(mpt,
1849 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1850 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0,
1851 mptsas_sasiou_page_1_cb);
1852 }
1853
1854 if (rval == DDI_SUCCESS) {
1855 switch (state) {
1856 case IOUC_READ_PAGE0:
1857 /*
1858 * retry 30 times if discovery is in process
1859 */
1860 if (retrypage0 && (retrypage0 < 30)) {
1861 drv_usecwait(1000 * 100);
1862 state = IOUC_READ_PAGE0;
1863 break;
1864 } else if (retrypage0 == 30) {
1865 mptsas_log(mpt, CE_WARN,
1866 "!Discovery in progress, can't "
1867 "verify IO unit config, then "
1868 "after 30 times retry, give "
1869 "up!");
1870 state = IOUC_DONE;
1871 rval = DDI_FAILURE;
1872 break;
1873 }
1874
1875 if (readpage1 == 0) {
1876 state = IOUC_DONE;
1877 rval = DDI_SUCCESS;
1878 break;
1879 }
1880
1881 state = IOUC_READ_PAGE1;
1882 break;
1883
1884 case IOUC_READ_PAGE1:
1885 state = IOUC_DONE;
1886 rval = DDI_SUCCESS;
1887 break;
1888 }
1889 } else {
1890 return (rval);
1891 }
1892 }
1893
1894 return (rval);
1895 }
1896
1897 static int
mptsas_biospage_3_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)1898 mptsas_biospage_3_cb(mptsas_t *mpt, caddr_t page_memp,
1899 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1900 va_list ap)
1901 {
1902 #ifndef __lock_lint
1903 _NOTE(ARGUNUSED(ap))
1904 #endif
1905 pMpi2BiosPage3_t sasbiospage;
1906 int rval = DDI_SUCCESS;
1907 uint32_t *bios_version;
1908
1909 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1910 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1911 mptsas_log(mpt, CE_WARN, "mptsas_get_bios_page3 header: "
1912 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, iocloginfo);
1913 rval = DDI_FAILURE;
1914 return (rval);
1915 }
1916 bios_version = va_arg(ap, uint32_t *);
1917 sasbiospage = (pMpi2BiosPage3_t)page_memp;
1918 *bios_version = ddi_get32(accessp, &sasbiospage->BiosVersion);
1919
1920 return (rval);
1921 }
1922
1923 /*
1924 * Request MPI configuration page BIOS page 3 to get BIOS version. Since all
1925 * other information in this page is not needed, just ignore it.
1926 */
1927 int
mptsas_get_bios_page3(mptsas_t * mpt,uint32_t * bios_version)1928 mptsas_get_bios_page3(mptsas_t *mpt, uint32_t *bios_version)
1929 {
1930 int rval = DDI_SUCCESS;
1931
1932 ASSERT(mutex_owned(&mpt->m_mutex));
1933
1934 /*
1935 * Get the header and config page. reply contains the reply frame,
1936 * which holds status info for the request.
1937 */
1938 rval = mptsas_access_config_page(mpt,
1939 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, MPI2_CONFIG_PAGETYPE_BIOS, 3,
1940 0, mptsas_biospage_3_cb, bios_version);
1941
1942 return (rval);
1943 }
1944
1945 /*
1946 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1947 * page1 to update the PHY information. This is the handshaking version of
1948 * this function, which should be called during initialization only.
1949 */
1950 int
mptsas_get_sas_io_unit_page_hndshk(mptsas_t * mpt)1951 mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
1952 {
1953 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
1954 ddi_dma_cookie_t page_cookie;
1955 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
1956 ddi_acc_handle_t recv_accessp, page_accessp;
1957 pMpi2ConfigReply_t configreply;
1958 pMpi2SasIOUnitPage0_t sasioupage0;
1959 pMpi2SasIOUnitPage1_t sasioupage1;
1960 int recv_numbytes;
1961 caddr_t recv_memp, page_memp;
1962 uint_t i, num_phys, start_phy = 0;
1963 int page0_size =
1964 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1965 (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1966 int page1_size =
1967 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1968 (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1969 uint32_t flags_length;
1970 uint32_t cpdi[MPTSAS_MAX_PHYS];
1971 uint32_t readpage1 = 0, retrypage0 = 0;
1972 uint16_t iocstatus;
1973 uint8_t port_flags, page_number, action;
1974 uint32_t reply_size;
1975 uint_t state;
1976 int rval = DDI_FAILURE;
1977 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
1978
1979 /*
1980 * We want to find a reply_size that's large enough for the page0 and
1981 * page1 sizes and resistant to increase in the number of phys.
1982 */
1983 reply_size = MAX(page0_size, page1_size);
1984 if (P2ROUNDUP(reply_size, 256) <= reply_size) {
1985 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page_hndsk: "
1986 "cannot size reply size");
1987 goto cleanup;
1988 }
1989
1990 /*
1991 * Initialize our "state machine". This is a bit convoluted,
1992 * but it keeps us from having to do the ddi allocations numerous
1993 * times.
1994 */
1995
1996 NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
1997 ASSERT(mutex_owned(&mpt->m_mutex));
1998 state = IOUC_READ_PAGE0;
1999
2000 /*
2001 * dynamically create a customized dma attribute structure
2002 * that describes mpt's config reply page request structure.
2003 */
2004 recv_dma_attrs = mpt->m_msg_dma_attr;
2005 recv_dma_attrs.dma_attr_sgllen = 1;
2006 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2007
2008 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
2009 &recv_dma_handle, &recv_accessp, &recv_memp,
2010 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2011 mptsas_log(mpt, CE_WARN,
2012 "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
2013 goto cleanup;
2014 }
2015 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2016 free_recv = B_TRUE;
2017
2018 page_dma_attrs = mpt->m_msg_dma_attr;
2019 page_dma_attrs.dma_attr_sgllen = 1;
2020 page_dma_attrs.dma_attr_granular = reply_size;
2021
2022 if (mptsas_dma_addr_create(mpt, page_dma_attrs,
2023 &page_dma_handle, &page_accessp, &page_memp,
2024 reply_size, &page_cookie) == FALSE) {
2025 mptsas_log(mpt, CE_WARN,
2026 "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
2027 goto cleanup;
2028 }
2029 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2030 free_page = B_TRUE;
2031
2032 /*
2033 * Now we cycle through the state machine. Here's what happens:
2034 * 1. Read IO unit page 0 and set phy information
2035 * 2. See if Read IO unit page1 is needed because of port configuration
2036 * 3. Read IO unit page 1 and update phy information.
2037 */
2038
2039 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
2040 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
2041
2042 while (state != IOUC_DONE) {
2043 switch (state) {
2044 case IOUC_READ_PAGE0:
2045 page_number = 0;
2046 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2047 flags_length = (uint32_t)page0_size;
2048 flags_length |= ((uint32_t)(
2049 MPI2_SGE_FLAGS_LAST_ELEMENT |
2050 MPI2_SGE_FLAGS_END_OF_BUFFER |
2051 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2052 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2053 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2054 MPI2_SGE_FLAGS_IOC_TO_HOST |
2055 MPI2_SGE_FLAGS_END_OF_LIST) <<
2056 MPI2_SGE_FLAGS_SHIFT);
2057
2058 break;
2059
2060 case IOUC_READ_PAGE1:
2061 page_number = 1;
2062 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2063 flags_length = (uint32_t)page1_size;
2064 flags_length |= ((uint32_t)(
2065 MPI2_SGE_FLAGS_LAST_ELEMENT |
2066 MPI2_SGE_FLAGS_END_OF_BUFFER |
2067 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2068 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2069 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2070 MPI2_SGE_FLAGS_IOC_TO_HOST |
2071 MPI2_SGE_FLAGS_END_OF_LIST) <<
2072 MPI2_SGE_FLAGS_SHIFT);
2073
2074 break;
2075 default:
2076 break;
2077 }
2078
2079 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2080 configreply = (pMpi2ConfigReply_t)recv_memp;
2081 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2082
2083 if (mptsas_send_extended_config_request_msg(mpt,
2084 MPI2_CONFIG_ACTION_PAGE_HEADER,
2085 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
2086 0, page_number, 0, 0, 0, 0)) {
2087 goto cleanup;
2088 }
2089
2090 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2091 recv_accessp)) {
2092 goto cleanup;
2093 }
2094
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: read page "
2101 "header iocstatus = 0x%x", iocstatus);
2102 goto cleanup;
2103 }
2104
2105 if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
2106 bzero(page_memp, reply_size);
2107 }
2108
2109 if (mptsas_send_extended_config_request_msg(mpt, action,
2110 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
2111 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2112 ddi_get16(recv_accessp, &configreply->ExtPageLength),
2113 flags_length, page_cookie.dmac_laddress)) {
2114 goto cleanup;
2115 }
2116
2117 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2118 recv_accessp)) {
2119 goto cleanup;
2120 }
2121
2122 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2123 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2124
2125 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2126 mptsas_log(mpt, CE_WARN,
2127 "mptsas_get_sas_io_unit_page_hndshk: IO unit "
2128 "config failed for action %d, iocstatus = 0x%x",
2129 action, iocstatus);
2130 goto cleanup;
2131 }
2132
2133 switch (state) {
2134 case IOUC_READ_PAGE0:
2135 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2136 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2137 goto cleanup;
2138 }
2139
2140 num_phys = ddi_get8(page_accessp,
2141 &sasioupage0->NumPhys);
2142 if (num_phys > MPTSAS_MAX_PHYS) {
2143 mptsas_log(mpt, CE_WARN, "Number of phys "
2144 "supported by HBA (%d) is more than max "
2145 "supported by driver (%d). Driver will "
2146 "not attach.", num_phys,
2147 MPTSAS_MAX_PHYS);
2148 rval = DDI_FAILURE;
2149 goto cleanup;
2150 }
2151 if (num_phys > mpt->m_num_phys) {
2152 mptsas_log(mpt, CE_WARN, "Number of phys "
2153 "reported by HBA SAS IO Unit Page 0 (%u) "
2154 "is greater than that reported by the "
2155 "manufacturing information (%u). Driver "
2156 "phy count limited to %u. Please contact "
2157 "the firmware vendor about this.", num_phys,
2158 mpt->m_num_phys, mpt->m_num_phys);
2159 num_phys = mpt->m_num_phys;
2160 } else if (num_phys < mpt->m_num_phys) {
2161 mptsas_log(mpt, CE_WARN, "Number of phys "
2162 "reported by HBA SAS IO Unit Page 0 (%u) "
2163 "is less than that reported by the "
2164 "manufacturing information (%u). Driver "
2165 "will not attach. Please contact the "
2166 "firmware vendor about this.", num_phys,
2167 mpt->m_num_phys);
2168 rval = DDI_FAILURE;
2169 goto cleanup;
2170 }
2171 for (i = start_phy; i < num_phys; i++, start_phy = i) {
2172 cpdi[i] = ddi_get32(page_accessp,
2173 &sasioupage0->PhyData[i].
2174 ControllerPhyDeviceInfo);
2175 port_flags = ddi_get8(page_accessp,
2176 &sasioupage0->PhyData[i].PortFlags);
2177
2178 mpt->m_phy_info[i].port_num =
2179 ddi_get8(page_accessp,
2180 &sasioupage0->PhyData[i].Port);
2181 mpt->m_phy_info[i].ctrl_devhdl =
2182 ddi_get16(page_accessp, &sasioupage0->
2183 PhyData[i].ControllerDevHandle);
2184 mpt->m_phy_info[i].attached_devhdl =
2185 ddi_get16(page_accessp, &sasioupage0->
2186 PhyData[i].AttachedDevHandle);
2187 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2188 mpt->m_phy_info[i].port_flags = port_flags;
2189
2190 if (port_flags & DISCOVERY_IN_PROGRESS) {
2191 retrypage0++;
2192 NDBG20(("Discovery in progress, can't "
2193 "verify IO unit config, then NO.%d"
2194 " times retry", retrypage0));
2195 break;
2196 } else {
2197 retrypage0 = 0;
2198 }
2199 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
2200 /*
2201 * some PHY configuration described in
2202 * SAS IO Unit Page1
2203 */
2204 readpage1 = 1;
2205 }
2206 }
2207
2208 /*
2209 * retry 30 times if discovery is in process
2210 */
2211 if (retrypage0 && (retrypage0 < 30)) {
2212 drv_usecwait(1000 * 100);
2213 state = IOUC_READ_PAGE0;
2214 break;
2215 } else if (retrypage0 == 30) {
2216 mptsas_log(mpt, CE_WARN,
2217 "!Discovery in progress, can't "
2218 "verify IO unit config, then after"
2219 " 30 times retry, give up!");
2220 state = IOUC_DONE;
2221 rval = DDI_FAILURE;
2222 break;
2223 }
2224
2225 if (readpage1 == 0) {
2226 state = IOUC_DONE;
2227 rval = DDI_SUCCESS;
2228 break;
2229 }
2230
2231 state = IOUC_READ_PAGE1;
2232 break;
2233
2234 case IOUC_READ_PAGE1:
2235 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2236 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2237 goto cleanup;
2238 }
2239
2240 num_phys = ddi_get8(page_accessp,
2241 &sasioupage1->NumPhys);
2242 if (num_phys > MPTSAS_MAX_PHYS) {
2243 mptsas_log(mpt, CE_WARN, "Number of phys "
2244 "supported by HBA (%d) is more than max "
2245 "supported by driver (%d). Driver will "
2246 "not attach.", num_phys,
2247 MPTSAS_MAX_PHYS);
2248 rval = DDI_FAILURE;
2249 goto cleanup;
2250 }
2251 if (num_phys > mpt->m_num_phys) {
2252 mptsas_log(mpt, CE_WARN, "Number of phys "
2253 "reported by HBA SAS IO Unit Page 1 (%u) "
2254 "is greater than that reported by the "
2255 "manufacturing information (%u). Limiting "
2256 "phy count to %u. Please contact the "
2257 "firmware vendor about this.", num_phys,
2258 mpt->m_num_phys, mpt->m_num_phys);
2259 num_phys = mpt->m_num_phys;
2260 } else if (num_phys < mpt->m_num_phys) {
2261 mptsas_log(mpt, CE_WARN, "Number of phys "
2262 "reported by HBA SAS IO Unit Page 1 (%u) "
2263 "is less than that reported by the "
2264 "manufacturing information (%u). Driver "
2265 "will not attach. Please contact the "
2266 "firmware vendor about this.", num_phys,
2267 mpt->m_num_phys);
2268 rval = DDI_FAILURE;
2269 goto cleanup;
2270 }
2271 for (i = 0; i < num_phys; i++) {
2272 cpdi[i] = ddi_get32(page_accessp,
2273 &sasioupage1->PhyData[i].
2274 ControllerPhyDeviceInfo);
2275 port_flags = ddi_get8(page_accessp,
2276 &sasioupage1->PhyData[i].PortFlags);
2277 mpt->m_phy_info[i].port_num =
2278 ddi_get8(page_accessp,
2279 &sasioupage1->PhyData[i].Port);
2280 mpt->m_phy_info[i].port_flags = port_flags;
2281 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2282
2283 }
2284
2285 state = IOUC_DONE;
2286 rval = DDI_SUCCESS;
2287 break;
2288 }
2289 }
2290 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2291 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2292 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2293 rval = DDI_FAILURE;
2294 goto cleanup;
2295 }
2296 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2297 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2298 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2299 rval = DDI_FAILURE;
2300 goto cleanup;
2301 }
2302
2303 cleanup:
2304 if (free_recv)
2305 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2306 if (free_page)
2307 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2308 if (rval != DDI_SUCCESS) {
2309 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
2310 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
2311 }
2312 return (rval);
2313 }
2314
2315 /*
2316 * mptsas_get_manufacture_page5
2317 *
2318 * This function will retrieve the base WWID from the adapter. Since this
2319 * function is only called during the initialization process, use handshaking.
2320 */
2321 int
mptsas_get_manufacture_page5(mptsas_t * mpt)2322 mptsas_get_manufacture_page5(mptsas_t *mpt)
2323 {
2324 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2325 ddi_dma_cookie_t page_cookie;
2326 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2327 ddi_acc_handle_t recv_accessp, page_accessp;
2328 pMpi2ConfigReply_t configreply;
2329 caddr_t recv_memp, page_memp;
2330 int recv_numbytes;
2331 pMpi2ManufacturingPage5_t m5;
2332 uint32_t flagslength;
2333 int rval = DDI_SUCCESS;
2334 uint_t iocstatus;
2335 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2336
2337 MPTSAS_DISABLE_INTR(mpt);
2338
2339 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2340 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
2341 rval = DDI_FAILURE;
2342 goto done;
2343 }
2344
2345 /*
2346 * dynamically create a customized dma attribute structure
2347 * that describes the MPT's config reply page request structure.
2348 */
2349 recv_dma_attrs = mpt->m_msg_dma_attr;
2350 recv_dma_attrs.dma_attr_sgllen = 1;
2351 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2352
2353 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
2354 &recv_dma_handle, &recv_accessp, &recv_memp,
2355 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2356 rval = DDI_FAILURE;
2357 goto done;
2358 }
2359 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2360 free_recv = B_TRUE;
2361
2362 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2363 configreply = (pMpi2ConfigReply_t)recv_memp;
2364 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2365
2366 /*
2367 * get config reply message
2368 */
2369 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2370 recv_accessp)) {
2371 rval = DDI_FAILURE;
2372 goto done;
2373 }
2374
2375 if ((iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) !=
2376 0) {
2377 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2378 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2379 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2380 goto done;
2381 }
2382
2383 /*
2384 * dynamically create a customized dma attribute structure
2385 * that describes the MPT's config page structure.
2386 */
2387 page_dma_attrs = mpt->m_msg_dma_attr;
2388 page_dma_attrs.dma_attr_sgllen = 1;
2389 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2390
2391 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2392 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2393 &page_cookie) == FALSE) {
2394 rval = DDI_FAILURE;
2395 goto done;
2396 }
2397 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2398 free_page = B_TRUE;
2399
2400 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
2401 m5 = (pMpi2ManufacturingPage5_t)page_memp;
2402 NDBG20(("mptsas_get_manufacture_page5: paddr 0x%p",
2403 (void *)(uintptr_t)page_cookie.dmac_laddress));
2404
2405 /*
2406 * Give reply address to IOC to store config page in and send
2407 * config request out.
2408 */
2409
2410 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
2411 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2412 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2413 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2414 MPI2_SGE_FLAGS_IOC_TO_HOST |
2415 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2416
2417 if (mptsas_send_config_request_msg(mpt,
2418 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2419 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2420 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2421 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2422 flagslength, page_cookie.dmac_laddress)) {
2423 rval = DDI_FAILURE;
2424 goto done;
2425 }
2426
2427 /*
2428 * get reply view handshake
2429 */
2430 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2431 recv_accessp)) {
2432 rval = DDI_FAILURE;
2433 goto done;
2434 }
2435
2436 if ((iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) !=
2437 0) {
2438 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2439 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2440 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2441 goto done;
2442 }
2443
2444 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2445
2446 /*
2447 * Fusion-MPT stores fields in little-endian format. This is
2448 * why the low-order 32 bits are stored first.
2449 */
2450 mpt->un.sasaddr.m_base_wwid_lo =
2451 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
2452 mpt->un.sasaddr.m_base_wwid_hi =
2453 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
2454
2455 if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
2456 "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
2457 NDBG2(("%s%d: failed to create base-wwid property",
2458 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2459 }
2460
2461 /*
2462 * Set the number of PHYs present.
2463 */
2464 mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
2465
2466 if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
2467 "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
2468 NDBG2(("%s%d: failed to create num-phys property",
2469 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2470 }
2471
2472 mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2473 mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
2474 (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2475
2476 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2477 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2478 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2479 rval = DDI_FAILURE;
2480 goto done;
2481 }
2482 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2483 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2484 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2485 rval = DDI_FAILURE;
2486 }
2487 done:
2488 /*
2489 * free up memory
2490 */
2491 if (free_recv)
2492 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2493 if (free_page)
2494 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2495 MPTSAS_ENABLE_INTR(mpt);
2496
2497 return (rval);
2498 }
2499
2500 static int
mptsas_sasphypage_0_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)2501 mptsas_sasphypage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2502 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2503 va_list ap)
2504 {
2505 #ifndef __lock_lint
2506 _NOTE(ARGUNUSED(ap))
2507 #endif
2508 pMpi2SasPhyPage0_t sasphypage;
2509 int rval = DDI_SUCCESS;
2510 uint16_t *owner_devhdl, *attached_devhdl;
2511 uint8_t *attached_phy_identify;
2512 uint32_t *attached_phy_info;
2513 uint8_t *programmed_link_rate;
2514 uint8_t *hw_link_rate;
2515 uint8_t *change_count;
2516 uint32_t *phy_info;
2517 uint8_t *negotiated_link_rate;
2518 uint32_t page_address;
2519
2520 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2521 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2522 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
2523 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2524 iocstatus, iocloginfo);
2525 rval = DDI_FAILURE;
2526 return (rval);
2527 }
2528 page_address = va_arg(ap, uint32_t);
2529 /*
2530 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2531 * are no more pages. If everything is OK up to this point but the
2532 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2533 * signal that device traversal is complete.
2534 */
2535 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2536 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2537 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2538 mpt->m_done_traverse_smp = 1;
2539 }
2540 rval = DDI_FAILURE;
2541 return (rval);
2542 }
2543 owner_devhdl = va_arg(ap, uint16_t *);
2544 attached_devhdl = va_arg(ap, uint16_t *);
2545 attached_phy_identify = va_arg(ap, uint8_t *);
2546 attached_phy_info = va_arg(ap, uint32_t *);
2547 programmed_link_rate = va_arg(ap, uint8_t *);
2548 hw_link_rate = va_arg(ap, uint8_t *);
2549 change_count = va_arg(ap, uint8_t *);
2550 phy_info = va_arg(ap, uint32_t *);
2551 negotiated_link_rate = va_arg(ap, uint8_t *);
2552
2553 sasphypage = (pMpi2SasPhyPage0_t)page_memp;
2554
2555 *owner_devhdl =
2556 ddi_get16(accessp, &sasphypage->OwnerDevHandle);
2557 *attached_devhdl =
2558 ddi_get16(accessp, &sasphypage->AttachedDevHandle);
2559 *attached_phy_identify =
2560 ddi_get8(accessp, &sasphypage->AttachedPhyIdentifier);
2561 *attached_phy_info =
2562 ddi_get32(accessp, &sasphypage->AttachedPhyInfo);
2563 *programmed_link_rate =
2564 ddi_get8(accessp, &sasphypage->ProgrammedLinkRate);
2565 *hw_link_rate =
2566 ddi_get8(accessp, &sasphypage->HwLinkRate);
2567 *change_count =
2568 ddi_get8(accessp, &sasphypage->ChangeCount);
2569 *phy_info =
2570 ddi_get32(accessp, &sasphypage->PhyInfo);
2571 *negotiated_link_rate =
2572 ddi_get8(accessp, &sasphypage->NegotiatedLinkRate);
2573
2574 return (rval);
2575 }
2576
2577 /*
2578 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2579 * and SAS address.
2580 */
2581 int
mptsas_get_sas_phy_page0(mptsas_t * mpt,uint32_t page_address,smhba_info_t * info)2582 mptsas_get_sas_phy_page0(mptsas_t *mpt, uint32_t page_address,
2583 smhba_info_t *info)
2584 {
2585 int rval = DDI_SUCCESS;
2586
2587 ASSERT(mutex_owned(&mpt->m_mutex));
2588
2589 /*
2590 * Get the header and config page. reply contains the reply frame,
2591 * which holds status info for the request.
2592 */
2593 rval = mptsas_access_config_page(mpt,
2594 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2595 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 0, page_address,
2596 mptsas_sasphypage_0_cb, page_address, &info->owner_devhdl,
2597 &info->attached_devhdl, &info->attached_phy_identify,
2598 &info->attached_phy_info, &info->programmed_link_rate,
2599 &info->hw_link_rate, &info->change_count,
2600 &info->phy_info, &info->negotiated_link_rate);
2601
2602 return (rval);
2603 }
2604
2605 static int
mptsas_sasphypage_1_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)2606 mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
2607 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2608 va_list ap)
2609 {
2610 #ifndef __lock_lint
2611 _NOTE(ARGUNUSED(ap))
2612 #endif
2613 pMpi2SasPhyPage1_t sasphypage;
2614 int rval = DDI_SUCCESS;
2615
2616 uint32_t *invalid_dword_count;
2617 uint32_t *running_disparity_error_count;
2618 uint32_t *loss_of_dword_sync_count;
2619 uint32_t *phy_reset_problem_count;
2620 uint32_t page_address;
2621
2622 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2623 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2624 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page1 "
2625 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2626 iocstatus, iocloginfo);
2627 rval = DDI_FAILURE;
2628 return (rval);
2629 }
2630 page_address = va_arg(ap, uint32_t);
2631 /*
2632 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2633 * are no more pages. If everything is OK up to this point but the
2634 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2635 * signal that device traversal is complete.
2636 */
2637 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2638 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2639 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2640 mpt->m_done_traverse_smp = 1;
2641 }
2642 rval = DDI_FAILURE;
2643 return (rval);
2644 }
2645
2646 invalid_dword_count = va_arg(ap, uint32_t *);
2647 running_disparity_error_count = va_arg(ap, uint32_t *);
2648 loss_of_dword_sync_count = va_arg(ap, uint32_t *);
2649 phy_reset_problem_count = va_arg(ap, uint32_t *);
2650
2651 sasphypage = (pMpi2SasPhyPage1_t)page_memp;
2652
2653 *invalid_dword_count =
2654 ddi_get32(accessp, &sasphypage->InvalidDwordCount);
2655 *running_disparity_error_count =
2656 ddi_get32(accessp, &sasphypage->RunningDisparityErrorCount);
2657 *loss_of_dword_sync_count =
2658 ddi_get32(accessp, &sasphypage->LossDwordSynchCount);
2659 *phy_reset_problem_count =
2660 ddi_get32(accessp, &sasphypage->PhyResetProblemCount);
2661
2662 return (rval);
2663 }
2664
2665 /*
2666 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2667 * and SAS address.
2668 */
2669 int
mptsas_get_sas_phy_page1(mptsas_t * mpt,uint32_t page_address,smhba_info_t * info)2670 mptsas_get_sas_phy_page1(mptsas_t *mpt, uint32_t page_address,
2671 smhba_info_t *info)
2672 {
2673 int rval = DDI_SUCCESS;
2674
2675 ASSERT(mutex_owned(&mpt->m_mutex));
2676
2677 /*
2678 * Get the header and config page. reply contains the reply frame,
2679 * which holds status info for the request.
2680 */
2681 rval = mptsas_access_config_page(mpt,
2682 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2683 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 1, page_address,
2684 mptsas_sasphypage_1_cb, page_address,
2685 &info->invalid_dword_count,
2686 &info->running_disparity_error_count,
2687 &info->loss_of_dword_sync_count,
2688 &info->phy_reset_problem_count);
2689
2690 return (rval);
2691 }
2692 /*
2693 * mptsas_get_manufacture_page0
2694 *
2695 * This function will retrieve the base
2696 * Chip name, Board Name,Board Trace number from the adapter.
2697 * Since this function is only called during the
2698 * initialization process, use handshaking.
2699 */
2700 int
mptsas_get_manufacture_page0(mptsas_t * mpt)2701 mptsas_get_manufacture_page0(mptsas_t *mpt)
2702 {
2703 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2704 ddi_dma_cookie_t page_cookie;
2705 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2706 ddi_acc_handle_t recv_accessp, page_accessp;
2707 pMpi2ConfigReply_t configreply;
2708 caddr_t recv_memp, page_memp;
2709 int recv_numbytes;
2710 pMpi2ManufacturingPage0_t m0;
2711 uint32_t flagslength;
2712 int rval = DDI_SUCCESS;
2713 uint_t iocstatus;
2714 uint8_t i = 0;
2715 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2716
2717 MPTSAS_DISABLE_INTR(mpt);
2718
2719 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2720 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, 0, 0, 0, 0)) {
2721 rval = DDI_FAILURE;
2722 goto done;
2723 }
2724
2725 /*
2726 * dynamically create a customized dma attribute structure
2727 * that describes the MPT's config reply page request structure.
2728 */
2729 recv_dma_attrs = mpt->m_msg_dma_attr;
2730 recv_dma_attrs.dma_attr_sgllen = 1;
2731 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2732
2733 if (mptsas_dma_addr_create(mpt, recv_dma_attrs, &recv_dma_handle,
2734 &recv_accessp, &recv_memp, (sizeof (MPI2_CONFIG_REPLY)),
2735 NULL) == FALSE) {
2736 rval = DDI_FAILURE;
2737 goto done;
2738 }
2739 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2740 free_recv = B_TRUE;
2741
2742 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2743 configreply = (pMpi2ConfigReply_t)recv_memp;
2744 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2745
2746 /*
2747 * get config reply message
2748 */
2749 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2750 recv_accessp)) {
2751 rval = DDI_FAILURE;
2752 goto done;
2753 }
2754
2755 if ((iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) !=
2756 0) {
2757 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2758 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2759 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2760 goto done;
2761 }
2762
2763 /*
2764 * dynamically create a customized dma attribute structure
2765 * that describes the MPT's config page structure.
2766 */
2767 page_dma_attrs = mpt->m_msg_dma_attr;
2768 page_dma_attrs.dma_attr_sgllen = 1;
2769 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2770
2771 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2772 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2773 &page_cookie) == FALSE) {
2774 rval = DDI_FAILURE;
2775 goto done;
2776 }
2777 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2778 free_page = B_TRUE;
2779
2780 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
2781 m0 = (pMpi2ManufacturingPage0_t)page_memp;
2782
2783 /*
2784 * Give reply address to IOC to store config page in and send
2785 * config request out.
2786 */
2787
2788 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
2789 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2790 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2791 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2792 MPI2_SGE_FLAGS_IOC_TO_HOST |
2793 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2794
2795 if (mptsas_send_config_request_msg(mpt,
2796 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2797 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2798 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2799 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2800 flagslength, page_cookie.dmac_laddress)) {
2801 rval = DDI_FAILURE;
2802 goto done;
2803 }
2804
2805 /*
2806 * get reply view handshake
2807 */
2808 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2809 recv_accessp)) {
2810 rval = DDI_FAILURE;
2811 goto done;
2812 }
2813
2814 if ((iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) !=
2815 0) {
2816 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2817 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2818 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2819 goto done;
2820 }
2821
2822 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2823
2824 /*
2825 * Fusion-MPT stores fields in little-endian format. This is
2826 * why the low-order 32 bits are stored first.
2827 */
2828
2829 for (i = 0; i < 16; i++) {
2830 mpt->m_MANU_page0.ChipName[i] =
2831 ddi_get8(page_accessp,
2832 (uint8_t *)(void *)&m0->ChipName[i]);
2833 }
2834
2835 for (i = 0; i < 8; i++) {
2836 mpt->m_MANU_page0.ChipRevision[i] =
2837 ddi_get8(page_accessp,
2838 (uint8_t *)(void *)&m0->ChipRevision[i]);
2839 }
2840
2841 for (i = 0; i < 16; i++) {
2842 mpt->m_MANU_page0.BoardName[i] =
2843 ddi_get8(page_accessp,
2844 (uint8_t *)(void *)&m0->BoardName[i]);
2845 }
2846
2847 for (i = 0; i < 16; i++) {
2848 mpt->m_MANU_page0.BoardAssembly[i] =
2849 ddi_get8(page_accessp,
2850 (uint8_t *)(void *)&m0->BoardAssembly[i]);
2851 }
2852
2853 for (i = 0; i < 16; i++) {
2854 mpt->m_MANU_page0.BoardTracerNumber[i] =
2855 ddi_get8(page_accessp,
2856 (uint8_t *)(void *)&m0->BoardTracerNumber[i]);
2857 }
2858
2859 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2860 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2861 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2862 rval = DDI_FAILURE;
2863 goto done;
2864 }
2865 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2866 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2867 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2868 rval = DDI_FAILURE;
2869 }
2870 done:
2871 /*
2872 * free up memory
2873 */
2874 if (free_recv)
2875 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2876 if (free_page)
2877 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2878 MPTSAS_ENABLE_INTR(mpt);
2879
2880 return (rval);
2881 }
2882
2883 static int
mptsas_enclosurepage_0_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)2884 mptsas_enclosurepage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2885 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2886 va_list ap)
2887 {
2888 uint32_t page_address;
2889 pMpi2SasEnclosurePage0_t encpage, encout;
2890
2891 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2892 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2893 mptsas_log(mpt, CE_WARN, "mptsas_get_enclsourepage0 "
2894 "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
2895 iocstatus, iocloginfo);
2896 return (DDI_FAILURE);
2897 }
2898
2899 page_address = va_arg(ap, uint32_t);
2900 encout = va_arg(ap, pMpi2SasEnclosurePage0_t);
2901 encpage = (pMpi2SasEnclosurePage0_t)page_memp;
2902
2903 /*
2904 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2905 * are no more pages. If everything is OK up to this point but the
2906 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2907 * signal that enclosure traversal is complete.
2908 */
2909 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2910 if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
2911 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
2912 mpt->m_done_traverse_enc = 1;
2913 }
2914 return (DDI_FAILURE);
2915 }
2916
2917 encout->Header.PageVersion = ddi_get8(accessp,
2918 &encpage->Header.PageVersion);
2919 encout->Header.PageNumber = ddi_get8(accessp,
2920 &encpage->Header.PageNumber);
2921 encout->Header.PageType = ddi_get8(accessp, &encpage->Header.PageType);
2922 encout->Header.ExtPageLength = ddi_get16(accessp,
2923 &encpage->Header.ExtPageLength);
2924 encout->Header.ExtPageType = ddi_get8(accessp,
2925 &encpage->Header.ExtPageType);
2926
2927 encout->EnclosureLogicalID.Low = ddi_get32(accessp,
2928 &encpage->EnclosureLogicalID.Low);
2929 encout->EnclosureLogicalID.High = ddi_get32(accessp,
2930 &encpage->EnclosureLogicalID.High);
2931 encout->Flags = ddi_get16(accessp, &encpage->Flags);
2932 encout->EnclosureHandle = ddi_get16(accessp, &encpage->EnclosureHandle);
2933 encout->NumSlots = ddi_get16(accessp, &encpage->NumSlots);
2934 encout->StartSlot = ddi_get16(accessp, &encpage->StartSlot);
2935 encout->EnclosureLevel = ddi_get8(accessp, &encpage->EnclosureLevel);
2936 encout->SEPDevHandle = ddi_get16(accessp, &encpage->SEPDevHandle);
2937
2938 return (DDI_SUCCESS);
2939 }
2940
2941 /*
2942 * Request information about the SES enclosures.
2943 */
2944 int
mptsas_get_enclosure_page0(mptsas_t * mpt,uint32_t page_address,mptsas_enclosure_t * mep)2945 mptsas_get_enclosure_page0(mptsas_t *mpt, uint32_t page_address,
2946 mptsas_enclosure_t *mep)
2947 {
2948 int rval = DDI_SUCCESS;
2949 Mpi2SasEnclosurePage0_t encpage;
2950
2951 ASSERT(MUTEX_HELD(&mpt->m_mutex));
2952
2953 bzero(&encpage, sizeof (encpage));
2954 rval = mptsas_access_config_page(mpt,
2955 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2956 MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE, 0, page_address,
2957 mptsas_enclosurepage_0_cb, page_address, &encpage);
2958
2959 if (rval == DDI_SUCCESS) {
2960 mep->me_enchdl = encpage.EnclosureHandle;
2961 mep->me_flags = encpage.Flags;
2962 mep->me_nslots = encpage.NumSlots;
2963 mep->me_fslot = encpage.StartSlot;
2964 mep->me_slotleds = NULL;
2965 }
2966
2967 return (rval);
2968 }
2969