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