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