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