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