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 */
25
26 /*
27 * Copyright (c) 2000 to 2010, LSI Corporation.
28 * All rights reserved.
29 *
30 * Redistribution and use in source and binary forms of all code within
31 * this file that is exclusively owned by LSI, with or without
32 * modification, is permitted provided that, in addition to the CDDL 1.0
33 * License requirements, the following conditions are met:
34 *
35 * Neither the name of the author nor the names of its contributors may be
36 * used to endorse or promote products derived from this software without
37 * specific prior written permission.
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
40 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
41 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
42 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
43 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
44 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
45 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
46 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
47 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
48 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
49 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
50 * DAMAGE.
51 */
52
53 /*
54 * mptsas_impl - This file contains all the basic functions for communicating
55 * to MPT based hardware.
56 */
57
58 #if defined(lint) || defined(DEBUG)
59 #define MPTSAS_DEBUG
60 #endif
61
62 /*
63 * standard header files
64 */
65 #include <sys/note.h>
66 #include <sys/scsi/scsi.h>
67 #include <sys/pci.h>
68
69 #pragma pack(1)
70 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
71 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
72 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
73 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
74 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
75 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
76 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
77 #pragma pack()
78
79 /*
80 * private header files.
81 */
82 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
83 #include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
84
85 /*
86 * FMA header files.
87 */
88 #include <sys/fm/io/ddi.h>
89
90 #if defined(MPTSAS_DEBUG)
91 extern uint32_t mptsas_debug_flags;
92 #endif
93
94 /*
95 * prototypes
96 */
97 static void mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd);
98 static void mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd);
99 static m_event_struct_t *mptsas_ioc_event_find_by_cmd(mptsas_t *mpt,
100 struct mptsas_cmd *cmd);
101
102 /*
103 * add ioc evnet cmd into the queue
104 */
105 static void
mptsas_ioc_event_cmdq_add(mptsas_t * mpt,m_event_struct_t * cmd)106 mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd)
107 {
108 if ((cmd->m_event_linkp = mpt->m_ioc_event_cmdq) == NULL) {
109 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
110 mpt->m_ioc_event_cmdq = cmd;
111 } else {
112 cmd->m_event_linkp = NULL;
113 *(mpt->m_ioc_event_cmdtail) = cmd;
114 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
115 }
116 }
117
118 /*
119 * remove specified cmd from the ioc event queue
120 */
121 static void
mptsas_ioc_event_cmdq_delete(mptsas_t * mpt,m_event_struct_t * cmd)122 mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd)
123 {
124 m_event_struct_t *prev = mpt->m_ioc_event_cmdq;
125 if (prev == cmd) {
126 if ((mpt->m_ioc_event_cmdq = cmd->m_event_linkp) == NULL) {
127 mpt->m_ioc_event_cmdtail = &mpt->m_ioc_event_cmdq;
128 }
129 cmd->m_event_linkp = NULL;
130 return;
131 }
132 while (prev != NULL) {
133 if (prev->m_event_linkp == cmd) {
134 prev->m_event_linkp = cmd->m_event_linkp;
135 if (cmd->m_event_linkp == NULL) {
136 mpt->m_ioc_event_cmdtail = &prev->m_event_linkp;
137 }
138
139 cmd->m_event_linkp = NULL;
140 return;
141 }
142 prev = prev->m_event_linkp;
143 }
144 }
145
146 static m_event_struct_t *
mptsas_ioc_event_find_by_cmd(mptsas_t * mpt,struct mptsas_cmd * cmd)147 mptsas_ioc_event_find_by_cmd(mptsas_t *mpt, struct mptsas_cmd *cmd)
148 {
149 m_event_struct_t *ioc_cmd = NULL;
150
151 ioc_cmd = mpt->m_ioc_event_cmdq;
152 while (ioc_cmd != NULL) {
153 if (&(ioc_cmd->m_event_cmd) == cmd) {
154 return (ioc_cmd);
155 }
156 ioc_cmd = ioc_cmd->m_event_linkp;
157 }
158 ioc_cmd = NULL;
159 return (ioc_cmd);
160 }
161
162 void
mptsas_destroy_ioc_event_cmd(mptsas_t * mpt)163 mptsas_destroy_ioc_event_cmd(mptsas_t *mpt)
164 {
165 m_event_struct_t *ioc_cmd = NULL;
166 m_event_struct_t *ioc_cmd_tmp = NULL;
167 ioc_cmd = mpt->m_ioc_event_cmdq;
168
169 /*
170 * because the IOC event queue is resource of per instance for driver,
171 * it's not only ACK event commands used it, but also some others used
172 * it. We need destroy all ACK event commands when IOC reset, but can't
173 * disturb others.So we use filter to clear the ACK event cmd in ioc
174 * event queue, and other requests should be reserved, and they would
175 * be free by its owner.
176 */
177 while (ioc_cmd != NULL) {
178 if (ioc_cmd->m_event_cmd.cmd_flags & CFLAG_CMDACK) {
179 NDBG20(("destroy!! remove Ack Flag ioc_cmd\n"));
180 if ((mpt->m_ioc_event_cmdq =
181 ioc_cmd->m_event_linkp) == NULL)
182 mpt->m_ioc_event_cmdtail =
183 &mpt->m_ioc_event_cmdq;
184 ioc_cmd_tmp = ioc_cmd;
185 ioc_cmd = ioc_cmd->m_event_linkp;
186 kmem_free(ioc_cmd_tmp, M_EVENT_STRUCT_SIZE);
187 } else {
188 /*
189 * it's not ack cmd, so continue to check next one
190 */
191
192 NDBG20(("destroy!! it's not Ack Flag, continue\n"));
193 ioc_cmd = ioc_cmd->m_event_linkp;
194 }
195
196 }
197 }
198
199 void
mptsas_start_config_page_access(mptsas_t * mpt,mptsas_cmd_t * cmd)200 mptsas_start_config_page_access(mptsas_t *mpt, mptsas_cmd_t *cmd)
201 {
202 pMpi2ConfigRequest_t request;
203 pMpi2SGESimple64_t sge;
204 struct scsi_pkt *pkt = cmd->cmd_pkt;
205 mptsas_config_request_t *config = pkt->pkt_ha_private;
206 uint8_t direction;
207 uint32_t length, flagslength, request_desc_low;
208
209 ASSERT(mutex_owned(&mpt->m_mutex));
210
211 /*
212 * Point to the correct message and clear it as well as the global
213 * config page memory.
214 */
215 request = (pMpi2ConfigRequest_t)(mpt->m_req_frame +
216 (mpt->m_req_frame_size * cmd->cmd_slot));
217 bzero(request, mpt->m_req_frame_size);
218
219 /*
220 * Form the request message.
221 */
222 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Function,
223 MPI2_FUNCTION_CONFIG);
224 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Action, config->action);
225 direction = MPI2_SGE_FLAGS_IOC_TO_HOST;
226 length = 0;
227 sge = (pMpi2SGESimple64_t)&request->PageBufferSGE;
228 if (config->action == MPI2_CONFIG_ACTION_PAGE_HEADER) {
229 if (config->page_type > MPI2_CONFIG_PAGETYPE_MASK) {
230 ddi_put8(mpt->m_acc_req_frame_hdl,
231 &request->Header.PageType,
232 MPI2_CONFIG_PAGETYPE_EXTENDED);
233 ddi_put8(mpt->m_acc_req_frame_hdl,
234 &request->ExtPageType, config->page_type);
235 } else {
236 ddi_put8(mpt->m_acc_req_frame_hdl,
237 &request->Header.PageType, config->page_type);
238 }
239 } else {
240 ddi_put8(mpt->m_acc_req_frame_hdl, &request->ExtPageType,
241 config->ext_page_type);
242 ddi_put16(mpt->m_acc_req_frame_hdl, &request->ExtPageLength,
243 config->ext_page_length);
244 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageType,
245 config->page_type);
246 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageLength,
247 config->page_length);
248 ddi_put8(mpt->m_acc_req_frame_hdl,
249 &request->Header.PageVersion, config->page_version);
250 if ((config->page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
251 MPI2_CONFIG_PAGETYPE_EXTENDED) {
252 length = config->ext_page_length * 4;
253 } else {
254 length = config->page_length * 4;
255 }
256
257 if (config->action == MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
258 direction = MPI2_SGE_FLAGS_HOST_TO_IOC;
259 }
260 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
261 (uint32_t)cmd->cmd_dma_addr);
262 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
263 (uint32_t)(cmd->cmd_dma_addr >> 32));
264 }
265 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageNumber,
266 config->page_number);
267 ddi_put32(mpt->m_acc_req_frame_hdl, &request->PageAddress,
268 config->page_address);
269 flagslength = ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
270 MPI2_SGE_FLAGS_END_OF_BUFFER |
271 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
272 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
273 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
274 direction |
275 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
276 flagslength |= length;
277 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
278
279 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
280 DDI_DMA_SYNC_FORDEV);
281 request_desc_low = (cmd->cmd_slot << 16) +
282 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
283 cmd->cmd_rfm = NULL;
284 mpt->m_active->m_slot[cmd->cmd_slot] = cmd;
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
mptsas_access_config_page(mptsas_t * mpt,uint8_t action,uint8_t page_type,uint8_t page_number,uint32_t page_address,int (* callback)(mptsas_t *,caddr_t,ddi_acc_handle_t,uint16_t,uint32_t,va_list),...)295 mptsas_access_config_page(mptsas_t *mpt, uint8_t action, uint8_t page_type,
296 uint8_t page_number, uint32_t page_address, int (*callback) (mptsas_t *,
297 caddr_t, ddi_acc_handle_t, uint16_t, uint32_t, va_list), ...)
298 {
299 va_list ap;
300 ddi_dma_attr_t attrs;
301 ddi_dma_cookie_t cookie;
302 ddi_acc_handle_t accessp;
303 size_t len = 0;
304 mptsas_config_request_t config;
305 int rval = DDI_SUCCESS, config_flags = 0;
306 mptsas_cmd_t *cmd;
307 struct scsi_pkt *pkt;
308 pMpi2ConfigReply_t reply;
309 uint16_t iocstatus = 0;
310 uint32_t iocloginfo;
311 caddr_t page_memp;
312
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
mptsas_send_config_request_msg(mptsas_t * mpt,uint8_t action,uint8_t pagetype,uint32_t pageaddress,uint8_t pagenumber,uint8_t pageversion,uint8_t pagelength,uint32_t SGEflagslength,uint32_t SGEaddress32)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
mptsas_send_extended_config_request_msg(mptsas_t * mpt,uint8_t action,uint8_t extpagetype,uint32_t pageaddress,uint8_t pagenumber,uint8_t pageversion,uint16_t extpagelength,uint32_t SGEflagslength,uint32_t SGEaddress32)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
mptsas_ioc_wait_for_response(mptsas_t * mpt)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
mptsas_ioc_wait_for_doorbell(mptsas_t * mpt)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
mptsas_send_handshake_msg(mptsas_t * mpt,caddr_t memp,int numbytes,ddi_acc_handle_t accessp)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
mptsas_get_handshake_msg(mptsas_t * mpt,caddr_t memp,int numbytes,ddi_acc_handle_t accessp)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
mptsas_kick_start(mptsas_t * mpt)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
mptsas_ioc_reset(mptsas_t * mpt)958 mptsas_ioc_reset(mptsas_t *mpt)
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 if (mpt->m_event_replay && (mpt->m_softstate &
977 MPTSAS_SS_MSG_UNIT_RESET)) {
978 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
979 reset_msg = MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET;
980 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
981 (reset_msg << MPI2_DOORBELL_FUNCTION_SHIFT));
982 if (mptsas_ioc_wait_for_response(mpt)) {
983 NDBG19(("mptsas_ioc_reset failure sending "
984 "message_unit_reset\n"));
985 goto hard_reset;
986 }
987
988 /*
989 * Wait no more than 60 seconds for chip to become
990 * ready.
991 */
992 while ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell) &
993 MPI2_IOC_STATE_READY) == 0x0) {
994 drv_usecwait(1000);
995 if (polls++ > 60000) {
996 goto hard_reset;
997 }
998 }
999
1000 /*
1001 * Save the last reset mode done on IOC which will be
1002 * helpful while resuming from suspension.
1003 */
1004 mpt->m_softstate |= MPTSAS_DID_MSG_UNIT_RESET;
1005
1006 /*
1007 * the message unit reset would do reset operations
1008 * clear reply and request queue, so we should clear
1009 * ACK event cmd.
1010 */
1011 mptsas_destroy_ioc_event_cmd(mpt);
1012 return (MPTSAS_SUCCESS_MUR);
1013 }
1014 }
1015 hard_reset:
1016 mpt->m_softstate &= ~MPTSAS_DID_MSG_UNIT_RESET;
1017 if (mptsas_kick_start(mpt) == DDI_FAILURE) {
1018 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
1019 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
1020 return (MPTSAS_RESET_FAIL);
1021 }
1022 return (MPTSAS_SUCCESS_HARDRESET);
1023 }
1024
1025
1026 int
mptsas_request_from_pool(mptsas_t * mpt,mptsas_cmd_t ** cmd,struct scsi_pkt ** pkt)1027 mptsas_request_from_pool(mptsas_t *mpt, mptsas_cmd_t **cmd,
1028 struct scsi_pkt **pkt)
1029 {
1030 m_event_struct_t *ioc_cmd = NULL;
1031
1032 ioc_cmd = kmem_zalloc(M_EVENT_STRUCT_SIZE, KM_SLEEP);
1033 if (ioc_cmd == NULL) {
1034 return (DDI_FAILURE);
1035 }
1036 ioc_cmd->m_event_linkp = NULL;
1037 mptsas_ioc_event_cmdq_add(mpt, ioc_cmd);
1038 *cmd = &(ioc_cmd->m_event_cmd);
1039 *pkt = &(ioc_cmd->m_event_pkt);
1040
1041 return (DDI_SUCCESS);
1042 }
1043
1044 void
mptsas_return_to_pool(mptsas_t * mpt,mptsas_cmd_t * cmd)1045 mptsas_return_to_pool(mptsas_t *mpt, mptsas_cmd_t *cmd)
1046 {
1047 m_event_struct_t *ioc_cmd = NULL;
1048
1049 ioc_cmd = mptsas_ioc_event_find_by_cmd(mpt, cmd);
1050 if (ioc_cmd == NULL) {
1051 return;
1052 }
1053
1054 mptsas_ioc_event_cmdq_delete(mpt, ioc_cmd);
1055 kmem_free(ioc_cmd, M_EVENT_STRUCT_SIZE);
1056 ioc_cmd = NULL;
1057 }
1058
1059 /*
1060 * NOTE: We should be able to queue TM requests in the controller to make this
1061 * a lot faster. If resetting all targets, for example, we can load the hi
1062 * priority queue with its limit and the controller will reply as they are
1063 * completed. This way, we don't have to poll for one reply at a time.
1064 * Think about enhancing this later.
1065 */
1066 int
mptsas_ioc_task_management(mptsas_t * mpt,int task_type,uint16_t dev_handle,int lun,uint8_t * reply,uint32_t reply_size,int mode)1067 mptsas_ioc_task_management(mptsas_t *mpt, int task_type, uint16_t dev_handle,
1068 int lun, uint8_t *reply, uint32_t reply_size, int mode)
1069 {
1070 /*
1071 * In order to avoid allocating variables on the stack,
1072 * we make use of the pre-existing mptsas_cmd_t and
1073 * scsi_pkt which are included in the mptsas_t which
1074 * is passed to this routine.
1075 */
1076
1077 pMpi2SCSITaskManagementRequest_t task;
1078 int rval = FALSE;
1079 mptsas_cmd_t *cmd;
1080 struct scsi_pkt *pkt;
1081 mptsas_slots_t *slots = mpt->m_active;
1082 uint32_t request_desc_low, i;
1083 pMPI2DefaultReply_t reply_msg;
1084
1085 /*
1086 * Can't start another task management routine.
1087 */
1088 if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
1089 mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
1090 " command at a time\n");
1091 return (FALSE);
1092 }
1093
1094 cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
1095 pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
1096
1097 bzero((caddr_t)cmd, sizeof (*cmd));
1098 bzero((caddr_t)pkt, scsi_pkt_size());
1099
1100 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1101 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1102 pkt->pkt_ha_private = (opaque_t)cmd;
1103 pkt->pkt_flags = (FLAG_NOINTR | FLAG_HEAD);
1104 pkt->pkt_time = 60;
1105 pkt->pkt_address.a_target = dev_handle;
1106 pkt->pkt_address.a_lun = (uchar_t)lun;
1107 cmd->cmd_pkt = pkt;
1108 cmd->cmd_scblen = 1;
1109 cmd->cmd_flags = CFLAG_TM_CMD;
1110 cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
1111
1112 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
1113
1114 /*
1115 * Store the TM message in memory location corresponding to the TM slot
1116 * number.
1117 */
1118 task = (pMpi2SCSITaskManagementRequest_t)(mpt->m_req_frame +
1119 (mpt->m_req_frame_size * cmd->cmd_slot));
1120 bzero(task, mpt->m_req_frame_size);
1121
1122 /*
1123 * form message for requested task
1124 */
1125 mptsas_init_std_hdr(mpt->m_acc_req_frame_hdl, task, dev_handle, lun, 0,
1126 MPI2_FUNCTION_SCSI_TASK_MGMT);
1127
1128 /*
1129 * Set the task type
1130 */
1131 ddi_put8(mpt->m_acc_req_frame_hdl, &task->TaskType, task_type);
1132
1133 /*
1134 * Send TM request using High Priority Queue.
1135 */
1136 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1137 DDI_DMA_SYNC_FORDEV);
1138 request_desc_low = (cmd->cmd_slot << 16) +
1139 MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1140 MPTSAS_START_CMD(mpt, request_desc_low, 0);
1141 rval = mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
1142
1143 if (pkt->pkt_reason == CMD_INCOMPLETE)
1144 rval = FALSE;
1145
1146 /*
1147 * If a reply frame was used and there is a reply buffer to copy the
1148 * reply data into, copy it. If this fails, log a message, but don't
1149 * fail the TM request.
1150 */
1151 if (cmd->cmd_rfm && reply) {
1152 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
1153 DDI_DMA_SYNC_FORCPU);
1154 reply_msg = (pMPI2DefaultReply_t)
1155 (mpt->m_reply_frame + (cmd->cmd_rfm -
1156 mpt->m_reply_frame_dma_addr));
1157 if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
1158 reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
1159 }
1160 mutex_exit(&mpt->m_mutex);
1161 for (i = 0; i < reply_size; i++) {
1162 if (ddi_copyout((uint8_t *)reply_msg + i, reply + i, 1,
1163 mode)) {
1164 mptsas_log(mpt, CE_WARN, "failed to copy out "
1165 "reply data for TM request");
1166 break;
1167 }
1168 }
1169 mutex_enter(&mpt->m_mutex);
1170 }
1171
1172 /*
1173 * clear the TM slot before returning
1174 */
1175 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
1176
1177 /*
1178 * If we lost our task management command
1179 * we need to reset the ioc
1180 */
1181 if (rval == FALSE) {
1182 mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
1183 "try to reset ioc to recovery!");
1184 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1185 if (mptsas_restart_ioc(mpt)) {
1186 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1187 rval = FAILED;
1188 }
1189 }
1190
1191 return (rval);
1192 }
1193
1194 int
mptsas_update_flash(mptsas_t * mpt,caddr_t ptrbuffer,uint32_t size,uint8_t type,int mode)1195 mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
1196 uint8_t type, int mode)
1197 {
1198
1199 /*
1200 * In order to avoid allocating variables on the stack,
1201 * we make use of the pre-existing mptsas_cmd_t and
1202 * scsi_pkt which are included in the mptsas_t which
1203 * is passed to this routine.
1204 */
1205
1206 ddi_dma_attr_t flsh_dma_attrs;
1207 ddi_dma_cookie_t flsh_cookie;
1208 ddi_dma_handle_t flsh_dma_handle;
1209 ddi_acc_handle_t flsh_accessp;
1210 caddr_t memp, flsh_memp;
1211 uint32_t flagslength;
1212 pMpi2FWDownloadRequest fwdownload;
1213 pMpi2FWDownloadTCSGE_t tcsge;
1214 pMpi2SGESimple64_t sge;
1215 mptsas_cmd_t *cmd;
1216 struct scsi_pkt *pkt;
1217 int i;
1218 int rvalue = 0;
1219 uint32_t request_desc_low;
1220
1221 if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1222 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1223 "failed. event ack command pool is full\n");
1224 return (rvalue);
1225 }
1226
1227 bzero((caddr_t)cmd, sizeof (*cmd));
1228 bzero((caddr_t)pkt, scsi_pkt_size());
1229 cmd->ioc_cmd_slot = (uint32_t)rvalue;
1230
1231 /*
1232 * dynamically create a customized dma attribute structure
1233 * that describes the flash file.
1234 */
1235 flsh_dma_attrs = mpt->m_msg_dma_attr;
1236 flsh_dma_attrs.dma_attr_sgllen = 1;
1237
1238 if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1239 &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1240 mptsas_log(mpt, CE_WARN,
1241 "(unable to allocate dma resource.");
1242 mptsas_return_to_pool(mpt, cmd);
1243 return (-1);
1244 }
1245
1246 bzero(flsh_memp, size);
1247
1248 for (i = 0; i < size; i++) {
1249 (void) ddi_copyin(ptrbuffer + i, flsh_memp + i, 1, mode);
1250 }
1251 (void) ddi_dma_sync(flsh_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
1252
1253 /*
1254 * form a cmd/pkt to store the fw download message
1255 */
1256 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1257 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1258 pkt->pkt_ha_private = (opaque_t)cmd;
1259 pkt->pkt_flags = FLAG_HEAD;
1260 pkt->pkt_time = 60;
1261 cmd->cmd_pkt = pkt;
1262 cmd->cmd_scblen = 1;
1263 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_FW_CMD;
1264
1265 /*
1266 * Save the command in a slot
1267 */
1268 if (mptsas_save_cmd(mpt, cmd) == FALSE) {
1269 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1270 mptsas_return_to_pool(mpt, cmd);
1271 return (-1);
1272 }
1273
1274 /*
1275 * Fill in fw download message
1276 */
1277 ASSERT(cmd->cmd_slot != 0);
1278 memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
1279 bzero(memp, mpt->m_req_frame_size);
1280 fwdownload = (void *)memp;
1281 ddi_put8(mpt->m_acc_req_frame_hdl, &fwdownload->Function,
1282 MPI2_FUNCTION_FW_DOWNLOAD);
1283 ddi_put8(mpt->m_acc_req_frame_hdl, &fwdownload->ImageType, type);
1284 ddi_put8(mpt->m_acc_req_frame_hdl, &fwdownload->MsgFlags,
1285 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1286 ddi_put32(mpt->m_acc_req_frame_hdl, &fwdownload->TotalImageSize, size);
1287
1288 tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
1289 ddi_put8(mpt->m_acc_req_frame_hdl, &tcsge->ContextSize, 0);
1290 ddi_put8(mpt->m_acc_req_frame_hdl, &tcsge->DetailsLength, 12);
1291 ddi_put8(mpt->m_acc_req_frame_hdl, &tcsge->Flags, 0);
1292 ddi_put32(mpt->m_acc_req_frame_hdl, &tcsge->ImageOffset, 0);
1293 ddi_put32(mpt->m_acc_req_frame_hdl, &tcsge->ImageSize, size);
1294
1295 sge = (pMpi2SGESimple64_t)(tcsge + 1);
1296 flagslength = size;
1297 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
1298 MPI2_SGE_FLAGS_END_OF_BUFFER |
1299 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1300 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1301 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
1302 MPI2_SGE_FLAGS_HOST_TO_IOC |
1303 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
1304 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
1305 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
1306 flsh_cookie.dmac_address);
1307 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
1308 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1309
1310 /*
1311 * Start command
1312 */
1313 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1314 DDI_DMA_SYNC_FORDEV);
1315 request_desc_low = (cmd->cmd_slot << 16) +
1316 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1317 cmd->cmd_rfm = NULL;
1318 mpt->m_active->m_slot[cmd->cmd_slot] = cmd;
1319 MPTSAS_START_CMD(mpt, request_desc_low, 0);
1320
1321 rvalue = 0;
1322 (void) cv_reltimedwait(&mpt->m_fw_cv, &mpt->m_mutex,
1323 drv_usectohz(60 * MICROSEC), TR_CLOCK_TICK);
1324 if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
1325 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1326 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
1327 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1328 }
1329 rvalue = -1;
1330 }
1331 mptsas_remove_cmd(mpt, cmd);
1332 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1333
1334 return (rvalue);
1335 }
1336
1337 static int
mptsas_sasdevpage_0_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)1338 mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1339 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1340 va_list ap)
1341 {
1342 #ifndef __lock_lint
1343 _NOTE(ARGUNUSED(ap))
1344 #endif
1345 pMpi2SasDevicePage0_t sasdevpage;
1346 int rval = DDI_SUCCESS, i;
1347 uint8_t *sas_addr = NULL;
1348 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1349 uint16_t *devhdl, *bay_num, *enclosure;
1350 uint64_t *sas_wwn;
1351 uint32_t *dev_info;
1352 uint8_t *physport, *phynum;
1353 uint16_t *pdevhdl;
1354 uint32_t page_address;
1355
1356 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1357 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1358 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_device_page0 "
1359 "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
1360 iocstatus, iocloginfo);
1361 rval = DDI_FAILURE;
1362 return (rval);
1363 }
1364 page_address = va_arg(ap, uint32_t);
1365 /*
1366 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1367 * are no more pages. If everything is OK up to this point but the
1368 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1369 * signal that device traversal is complete.
1370 */
1371 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1372 if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
1373 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
1374 mpt->m_done_traverse_dev = 1;
1375 }
1376 rval = DDI_FAILURE;
1377 return (rval);
1378 }
1379 devhdl = va_arg(ap, uint16_t *);
1380 sas_wwn = va_arg(ap, uint64_t *);
1381 dev_info = va_arg(ap, uint32_t *);
1382 physport = va_arg(ap, uint8_t *);
1383 phynum = va_arg(ap, uint8_t *);
1384 pdevhdl = va_arg(ap, uint16_t *);
1385 bay_num = va_arg(ap, uint16_t *);
1386 enclosure = va_arg(ap, uint16_t *);
1387
1388
1389 sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
1390
1391 *dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
1392 *devhdl = ddi_get16(accessp, &sasdevpage->DevHandle);
1393 sas_addr = (uint8_t *)(&sasdevpage->SASAddress);
1394 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1395 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1396 }
1397 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1398 *sas_wwn = LE_64(*sas_wwn);
1399 *physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
1400 *phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
1401 *pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
1402 *bay_num = ddi_get16(accessp, &sasdevpage->Slot);
1403 *enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
1404 return (rval);
1405 }
1406
1407 /*
1408 * Request MPI configuration page SAS device page 0 to get DevHandle, device
1409 * info and SAS address.
1410 */
1411 int
mptsas_get_sas_device_page0(mptsas_t * mpt,uint32_t page_address,uint16_t * dev_handle,uint64_t * sas_wwn,uint32_t * dev_info,uint8_t * physport,uint8_t * phynum,uint16_t * pdev_handle,uint16_t * bay_num,uint16_t * enclosure)1412 mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
1413 uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
1414 uint8_t *physport, uint8_t *phynum, uint16_t *pdev_handle,
1415 uint16_t *bay_num, uint16_t *enclosure)
1416 {
1417 int rval = DDI_SUCCESS;
1418
1419 ASSERT(mutex_owned(&mpt->m_mutex));
1420
1421 /*
1422 * Get the header and config page. reply contains the reply frame,
1423 * which holds status info for the request.
1424 */
1425 rval = mptsas_access_config_page(mpt,
1426 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1427 MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
1428 mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
1429 dev_info, physport, phynum, pdev_handle,
1430 bay_num, enclosure);
1431
1432 return (rval);
1433 }
1434
1435 static int
mptsas_sasexpdpage_0_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)1436 mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1437 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1438 va_list ap)
1439 {
1440 #ifndef __lock_lint
1441 _NOTE(ARGUNUSED(ap))
1442 #endif
1443 pMpi2ExpanderPage0_t expddevpage;
1444 int rval = DDI_SUCCESS, i;
1445 uint8_t *sas_addr = NULL;
1446 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1447 uint16_t *devhdl;
1448 uint64_t *sas_wwn;
1449 uint8_t physport;
1450 mptsas_phymask_t *phymask;
1451 uint16_t *pdevhdl;
1452 uint32_t page_address;
1453
1454 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1455 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1456 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
1457 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1458 iocstatus, iocloginfo);
1459 rval = DDI_FAILURE;
1460 return (rval);
1461 }
1462 page_address = va_arg(ap, uint32_t);
1463 /*
1464 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1465 * are no more pages. If everything is OK up to this point but the
1466 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1467 * signal that device traversal is complete.
1468 */
1469 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1470 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
1471 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
1472 mpt->m_done_traverse_smp = 1;
1473 }
1474 rval = DDI_FAILURE;
1475 return (rval);
1476 }
1477 devhdl = va_arg(ap, uint16_t *);
1478 sas_wwn = va_arg(ap, uint64_t *);
1479 phymask = va_arg(ap, mptsas_phymask_t *);
1480 pdevhdl = va_arg(ap, uint16_t *);
1481
1482 expddevpage = (pMpi2ExpanderPage0_t)page_memp;
1483
1484 *devhdl = ddi_get16(accessp, &expddevpage->DevHandle);
1485 physport = ddi_get8(accessp, &expddevpage->PhysicalPort);
1486 *phymask = mptsas_physport_to_phymask(mpt, physport);
1487 *pdevhdl = ddi_get16(accessp, &expddevpage->ParentDevHandle);
1488 sas_addr = (uint8_t *)(&expddevpage->SASAddress);
1489 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1490 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1491 }
1492 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1493 *sas_wwn = LE_64(*sas_wwn);
1494
1495 return (rval);
1496 }
1497
1498 /*
1499 * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
1500 * and SAS address.
1501 */
1502 int
mptsas_get_sas_expander_page0(mptsas_t * mpt,uint32_t page_address,mptsas_smp_t * info)1503 mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
1504 mptsas_smp_t *info)
1505 {
1506 int rval = DDI_SUCCESS;
1507
1508 ASSERT(mutex_owned(&mpt->m_mutex));
1509
1510 /*
1511 * Get the header and config page. reply contains the reply frame,
1512 * which holds status info for the request.
1513 */
1514 rval = mptsas_access_config_page(mpt,
1515 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1516 MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
1517 mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
1518 &info->m_sasaddr, &info->m_phymask, &info->m_pdevhdl);
1519
1520 return (rval);
1521 }
1522
1523 static int
mptsas_sasportpage_0_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)1524 mptsas_sasportpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1525 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1526 va_list ap)
1527 {
1528 #ifndef __lock_lint
1529 _NOTE(ARGUNUSED(ap))
1530 #endif
1531 int rval = DDI_SUCCESS, i;
1532 uint8_t *sas_addr = NULL;
1533 uint64_t *sas_wwn;
1534 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1535 uint8_t *portwidth;
1536 pMpi2SasPortPage0_t sasportpage;
1537
1538 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1539 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_port_page0 "
1540 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1541 iocstatus, iocloginfo);
1542 rval = DDI_FAILURE;
1543 return (rval);
1544 }
1545 sas_wwn = va_arg(ap, uint64_t *);
1546 portwidth = va_arg(ap, uint8_t *);
1547
1548 sasportpage = (pMpi2SasPortPage0_t)page_memp;
1549 sas_addr = (uint8_t *)(&sasportpage->SASAddress);
1550 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1551 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1552 }
1553 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1554 *sas_wwn = LE_64(*sas_wwn);
1555 *portwidth = ddi_get8(accessp, &sasportpage->PortWidth);
1556 return (rval);
1557 }
1558
1559 /*
1560 * Request MPI configuration page SAS port page 0 to get initiator SAS address
1561 * and port width.
1562 */
1563 int
mptsas_get_sas_port_page0(mptsas_t * mpt,uint32_t page_address,uint64_t * sas_wwn,uint8_t * portwidth)1564 mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
1565 uint64_t *sas_wwn, uint8_t *portwidth)
1566 {
1567 int rval = DDI_SUCCESS;
1568
1569 ASSERT(mutex_owned(&mpt->m_mutex));
1570
1571 /*
1572 * Get the header and config page. reply contains the reply frame,
1573 * which holds status info for the request.
1574 */
1575 rval = mptsas_access_config_page(mpt,
1576 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1577 MPI2_CONFIG_EXTPAGETYPE_SAS_PORT, 0, page_address,
1578 mptsas_sasportpage_0_cb, sas_wwn, portwidth);
1579
1580 return (rval);
1581 }
1582
1583 static int
mptsas_sasiou_page_0_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)1584 mptsas_sasiou_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
1585 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1586 va_list ap)
1587 {
1588 #ifndef __lock_lint
1589 _NOTE(ARGUNUSED(ap))
1590 #endif
1591 int rval = DDI_SUCCESS;
1592 pMpi2SasIOUnitPage0_t sasioupage0;
1593 int i, num_phys;
1594 uint32_t cpdi[MPTSAS_MAX_PHYS], *retrypage0, *readpage1;
1595 uint8_t port_flags;
1596
1597 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1598 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
1599 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1600 iocstatus, iocloginfo);
1601 rval = DDI_FAILURE;
1602 return (rval);
1603 }
1604 readpage1 = va_arg(ap, uint32_t *);
1605 retrypage0 = va_arg(ap, uint32_t *);
1606
1607 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1608
1609 num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
1610 /*
1611 * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1612 * was initially set. This should never change throughout the life of
1613 * the driver.
1614 */
1615 ASSERT(num_phys == mpt->m_num_phys);
1616 for (i = 0; i < num_phys; i++) {
1617 cpdi[i] = ddi_get32(accessp,
1618 &sasioupage0->PhyData[i].
1619 ControllerPhyDeviceInfo);
1620 port_flags = ddi_get8(accessp,
1621 &sasioupage0->PhyData[i].PortFlags);
1622 mpt->m_phy_info[i].port_num =
1623 ddi_get8(accessp,
1624 &sasioupage0->PhyData[i].Port);
1625 mpt->m_phy_info[i].ctrl_devhdl =
1626 ddi_get16(accessp, &sasioupage0->
1627 PhyData[i].ControllerDevHandle);
1628 mpt->m_phy_info[i].attached_devhdl =
1629 ddi_get16(accessp, &sasioupage0->
1630 PhyData[i].AttachedDevHandle);
1631 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1632 mpt->m_phy_info[i].port_flags = port_flags;
1633
1634 if (port_flags & DISCOVERY_IN_PROGRESS) {
1635 *retrypage0 = *retrypage0 + 1;
1636 break;
1637 } else {
1638 *retrypage0 = 0;
1639 }
1640 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
1641 /*
1642 * some PHY configuration described in
1643 * SAS IO Unit Page1
1644 */
1645 *readpage1 = 1;
1646 }
1647 }
1648
1649 return (rval);
1650 }
1651
1652 static int
mptsas_sasiou_page_1_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)1653 mptsas_sasiou_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
1654 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1655 va_list ap)
1656 {
1657 #ifndef __lock_lint
1658 _NOTE(ARGUNUSED(ap))
1659 #endif
1660 int rval = DDI_SUCCESS;
1661 pMpi2SasIOUnitPage1_t sasioupage1;
1662 int i, num_phys;
1663 uint32_t cpdi[MPTSAS_MAX_PHYS];
1664 uint8_t port_flags;
1665
1666 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1667 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
1668 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1669 iocstatus, iocloginfo);
1670 rval = DDI_FAILURE;
1671 return (rval);
1672 }
1673
1674 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1675 num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
1676 /*
1677 * ASSERT that the num_phys value in SAS IO Unit Page 1 is the same as
1678 * was initially set. This should never change throughout the life of
1679 * the driver.
1680 */
1681 ASSERT(num_phys == mpt->m_num_phys);
1682 for (i = 0; i < num_phys; i++) {
1683 cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
1684 ControllerPhyDeviceInfo);
1685 port_flags = ddi_get8(accessp,
1686 &sasioupage1->PhyData[i].PortFlags);
1687 mpt->m_phy_info[i].port_num =
1688 ddi_get8(accessp,
1689 &sasioupage1->PhyData[i].Port);
1690 mpt->m_phy_info[i].port_flags = port_flags;
1691 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1692 }
1693 return (rval);
1694 }
1695
1696 /*
1697 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1698 * page1 to update the PHY information. This is the message passing method of
1699 * this function which should be called except during initialization.
1700 */
1701 int
mptsas_get_sas_io_unit_page(mptsas_t * mpt)1702 mptsas_get_sas_io_unit_page(mptsas_t *mpt)
1703 {
1704 int rval = DDI_SUCCESS, state;
1705 uint32_t readpage1 = 0, retrypage0 = 0;
1706
1707 ASSERT(mutex_owned(&mpt->m_mutex));
1708
1709 /*
1710 * Now we cycle through the state machine. Here's what happens:
1711 * 1. Read IO unit page 0 and set phy information
1712 * 2. See if Read IO unit page1 is needed because of port configuration
1713 * 3. Read IO unit page 1 and update phy information.
1714 */
1715 state = IOUC_READ_PAGE0;
1716 while (state != IOUC_DONE) {
1717 if (state == IOUC_READ_PAGE0) {
1718 rval = mptsas_access_config_page(mpt,
1719 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1720 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
1721 mptsas_sasiou_page_0_cb, &readpage1,
1722 &retrypage0);
1723 } else if (state == IOUC_READ_PAGE1) {
1724 rval = mptsas_access_config_page(mpt,
1725 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1726 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0,
1727 mptsas_sasiou_page_1_cb);
1728 }
1729
1730 if (rval == DDI_SUCCESS) {
1731 switch (state) {
1732 case IOUC_READ_PAGE0:
1733 /*
1734 * retry 30 times if discovery is in process
1735 */
1736 if (retrypage0 && (retrypage0 < 30)) {
1737 drv_usecwait(1000 * 100);
1738 state = IOUC_READ_PAGE0;
1739 break;
1740 } else if (retrypage0 == 30) {
1741 mptsas_log(mpt, CE_WARN,
1742 "!Discovery in progress, can't "
1743 "verify IO unit config, then "
1744 "after 30 times retry, give "
1745 "up!");
1746 state = IOUC_DONE;
1747 rval = DDI_FAILURE;
1748 break;
1749 }
1750
1751 if (readpage1 == 0) {
1752 state = IOUC_DONE;
1753 rval = DDI_SUCCESS;
1754 break;
1755 }
1756
1757 state = IOUC_READ_PAGE1;
1758 break;
1759
1760 case IOUC_READ_PAGE1:
1761 state = IOUC_DONE;
1762 rval = DDI_SUCCESS;
1763 break;
1764 }
1765 } else {
1766 return (rval);
1767 }
1768 }
1769
1770 return (rval);
1771 }
1772
1773 static int
mptsas_biospage_3_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)1774 mptsas_biospage_3_cb(mptsas_t *mpt, caddr_t page_memp,
1775 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1776 va_list ap)
1777 {
1778 #ifndef __lock_lint
1779 _NOTE(ARGUNUSED(ap))
1780 #endif
1781 pMpi2BiosPage3_t sasbiospage;
1782 int rval = DDI_SUCCESS;
1783 uint32_t *bios_version;
1784
1785 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1786 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1787 mptsas_log(mpt, CE_WARN, "mptsas_get_bios_page3 header: "
1788 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, iocloginfo);
1789 rval = DDI_FAILURE;
1790 return (rval);
1791 }
1792 bios_version = va_arg(ap, uint32_t *);
1793 sasbiospage = (pMpi2BiosPage3_t)page_memp;
1794 *bios_version = ddi_get32(accessp, &sasbiospage->BiosVersion);
1795
1796 return (rval);
1797 }
1798
1799 /*
1800 * Request MPI configuration page BIOS page 3 to get BIOS version. Since all
1801 * other information in this page is not needed, just ignore it.
1802 */
1803 int
mptsas_get_bios_page3(mptsas_t * mpt,uint32_t * bios_version)1804 mptsas_get_bios_page3(mptsas_t *mpt, uint32_t *bios_version)
1805 {
1806 int rval = DDI_SUCCESS;
1807
1808 ASSERT(mutex_owned(&mpt->m_mutex));
1809
1810 /*
1811 * Get the header and config page. reply contains the reply frame,
1812 * which holds status info for the request.
1813 */
1814 rval = mptsas_access_config_page(mpt,
1815 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, MPI2_CONFIG_PAGETYPE_BIOS, 3,
1816 0, mptsas_biospage_3_cb, bios_version);
1817
1818 return (rval);
1819 }
1820
1821 /*
1822 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1823 * page1 to update the PHY information. This is the handshaking version of
1824 * this function, which should be called during initialization only.
1825 */
1826 int
mptsas_get_sas_io_unit_page_hndshk(mptsas_t * mpt)1827 mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
1828 {
1829 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
1830 ddi_dma_cookie_t page_cookie;
1831 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
1832 ddi_acc_handle_t recv_accessp, page_accessp;
1833 pMpi2ConfigReply_t configreply;
1834 pMpi2SasIOUnitPage0_t sasioupage0;
1835 pMpi2SasIOUnitPage1_t sasioupage1;
1836 int recv_numbytes;
1837 caddr_t recv_memp, page_memp;
1838 int i, num_phys, start_phy = 0;
1839 int page0_size =
1840 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1841 (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1842 int page1_size =
1843 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1844 (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1845 uint32_t flags_length;
1846 uint32_t cpdi[MPTSAS_MAX_PHYS];
1847 uint32_t readpage1 = 0, retrypage0 = 0;
1848 uint16_t iocstatus;
1849 uint8_t port_flags, page_number, action;
1850 uint32_t reply_size = 256; /* Big enough for any page */
1851 uint_t state;
1852 int rval = DDI_FAILURE;
1853
1854 /*
1855 * Initialize our "state machine". This is a bit convoluted,
1856 * but it keeps us from having to do the ddi allocations numerous
1857 * times.
1858 */
1859
1860 NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
1861 ASSERT(mutex_owned(&mpt->m_mutex));
1862 state = IOUC_READ_PAGE0;
1863
1864 /*
1865 * dynamically create a customized dma attribute structure
1866 * that describes mpt's config reply page request structure.
1867 */
1868 recv_dma_attrs = mpt->m_msg_dma_attr;
1869 recv_dma_attrs.dma_attr_sgllen = 1;
1870 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
1871
1872 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
1873 &recv_dma_handle, &recv_accessp, &recv_memp,
1874 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
1875 mptsas_log(mpt, CE_WARN,
1876 "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
1877 goto cleanup;
1878 }
1879
1880 page_dma_attrs = mpt->m_msg_dma_attr;
1881 page_dma_attrs.dma_attr_sgllen = 1;
1882 page_dma_attrs.dma_attr_granular = reply_size;
1883
1884 if (mptsas_dma_addr_create(mpt, page_dma_attrs,
1885 &page_dma_handle, &page_accessp, &page_memp,
1886 reply_size, &page_cookie) == FALSE) {
1887 mptsas_log(mpt, CE_WARN,
1888 "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
1889 goto cleanup;
1890 }
1891
1892 /*
1893 * Now we cycle through the state machine. Here's what happens:
1894 * 1. Read IO unit page 0 and set phy information
1895 * 2. See if Read IO unit page1 is needed because of port configuration
1896 * 3. Read IO unit page 1 and update phy information.
1897 */
1898
1899 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1900 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1901
1902 while (state != IOUC_DONE) {
1903 switch (state) {
1904 case IOUC_READ_PAGE0:
1905 page_number = 0;
1906 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1907 flags_length = (uint32_t)page0_size;
1908 flags_length |= ((uint32_t)(
1909 MPI2_SGE_FLAGS_LAST_ELEMENT |
1910 MPI2_SGE_FLAGS_END_OF_BUFFER |
1911 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1912 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1913 MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
1914 MPI2_SGE_FLAGS_IOC_TO_HOST |
1915 MPI2_SGE_FLAGS_END_OF_LIST) <<
1916 MPI2_SGE_FLAGS_SHIFT);
1917
1918 break;
1919
1920 case IOUC_READ_PAGE1:
1921 page_number = 1;
1922 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1923 flags_length = (uint32_t)page1_size;
1924 flags_length |= ((uint32_t)(
1925 MPI2_SGE_FLAGS_LAST_ELEMENT |
1926 MPI2_SGE_FLAGS_END_OF_BUFFER |
1927 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1928 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1929 MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
1930 MPI2_SGE_FLAGS_IOC_TO_HOST |
1931 MPI2_SGE_FLAGS_END_OF_LIST) <<
1932 MPI2_SGE_FLAGS_SHIFT);
1933
1934 break;
1935 default:
1936 break;
1937 }
1938
1939 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
1940 configreply = (pMpi2ConfigReply_t)recv_memp;
1941 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
1942
1943 if (mptsas_send_extended_config_request_msg(mpt,
1944 MPI2_CONFIG_ACTION_PAGE_HEADER,
1945 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
1946 0, page_number, 0, 0, 0, 0)) {
1947 goto cleanup;
1948 }
1949
1950 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
1951 recv_accessp)) {
1952 goto cleanup;
1953 }
1954
1955 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
1956 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
1957
1958 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1959 mptsas_log(mpt, CE_WARN,
1960 "mptsas_get_sas_io_unit_page_hndshk: read page "
1961 "header iocstatus = 0x%x", iocstatus);
1962 goto cleanup;
1963 }
1964
1965 if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
1966 bzero(page_memp, reply_size);
1967 }
1968
1969 if (mptsas_send_extended_config_request_msg(mpt, action,
1970 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
1971 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
1972 ddi_get16(recv_accessp, &configreply->ExtPageLength),
1973 flags_length, page_cookie.dmac_address)) {
1974 goto cleanup;
1975 }
1976
1977 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
1978 recv_accessp)) {
1979 goto cleanup;
1980 }
1981
1982 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
1983 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
1984
1985 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1986 mptsas_log(mpt, CE_WARN,
1987 "mptsas_get_sas_io_unit_page_hndshk: IO unit "
1988 "config failed for action %d, iocstatus = 0x%x",
1989 action, iocstatus);
1990 goto cleanup;
1991 }
1992
1993 switch (state) {
1994 case IOUC_READ_PAGE0:
1995 if ((ddi_dma_sync(page_dma_handle, 0, 0,
1996 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
1997 goto cleanup;
1998 }
1999
2000 num_phys = ddi_get8(page_accessp,
2001 &sasioupage0->NumPhys);
2002 ASSERT(num_phys == mpt->m_num_phys);
2003 if (num_phys > MPTSAS_MAX_PHYS) {
2004 mptsas_log(mpt, CE_WARN, "Number of phys "
2005 "supported by HBA (%d) is more than max "
2006 "supported by driver (%d). Driver will "
2007 "not attach.", num_phys,
2008 MPTSAS_MAX_PHYS);
2009 rval = DDI_FAILURE;
2010 goto cleanup;
2011 }
2012 for (i = start_phy; i < num_phys; i++, start_phy = i) {
2013 cpdi[i] = ddi_get32(page_accessp,
2014 &sasioupage0->PhyData[i].
2015 ControllerPhyDeviceInfo);
2016 port_flags = ddi_get8(page_accessp,
2017 &sasioupage0->PhyData[i].PortFlags);
2018
2019 mpt->m_phy_info[i].port_num =
2020 ddi_get8(page_accessp,
2021 &sasioupage0->PhyData[i].Port);
2022 mpt->m_phy_info[i].ctrl_devhdl =
2023 ddi_get16(page_accessp, &sasioupage0->
2024 PhyData[i].ControllerDevHandle);
2025 mpt->m_phy_info[i].attached_devhdl =
2026 ddi_get16(page_accessp, &sasioupage0->
2027 PhyData[i].AttachedDevHandle);
2028 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2029 mpt->m_phy_info[i].port_flags = port_flags;
2030
2031 if (port_flags & DISCOVERY_IN_PROGRESS) {
2032 retrypage0++;
2033 NDBG20(("Discovery in progress, can't "
2034 "verify IO unit config, then NO.%d"
2035 " times retry", retrypage0));
2036 break;
2037 } else {
2038 retrypage0 = 0;
2039 }
2040 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
2041 /*
2042 * some PHY configuration described in
2043 * SAS IO Unit Page1
2044 */
2045 readpage1 = 1;
2046 }
2047 }
2048
2049 /*
2050 * retry 30 times if discovery is in process
2051 */
2052 if (retrypage0 && (retrypage0 < 30)) {
2053 drv_usecwait(1000 * 100);
2054 state = IOUC_READ_PAGE0;
2055 break;
2056 } else if (retrypage0 == 30) {
2057 mptsas_log(mpt, CE_WARN,
2058 "!Discovery in progress, can't "
2059 "verify IO unit config, then after"
2060 " 30 times retry, give up!");
2061 state = IOUC_DONE;
2062 rval = DDI_FAILURE;
2063 break;
2064 }
2065
2066 if (readpage1 == 0) {
2067 state = IOUC_DONE;
2068 rval = DDI_SUCCESS;
2069 break;
2070 }
2071
2072 state = IOUC_READ_PAGE1;
2073 break;
2074
2075 case IOUC_READ_PAGE1:
2076 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2077 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2078 goto cleanup;
2079 }
2080
2081 num_phys = ddi_get8(page_accessp,
2082 &sasioupage1->NumPhys);
2083 ASSERT(num_phys == mpt->m_num_phys);
2084 if (num_phys > MPTSAS_MAX_PHYS) {
2085 mptsas_log(mpt, CE_WARN, "Number of phys "
2086 "supported by HBA (%d) is more than max "
2087 "supported by driver (%d). Driver will "
2088 "not attach.", num_phys,
2089 MPTSAS_MAX_PHYS);
2090 rval = DDI_FAILURE;
2091 goto cleanup;
2092 }
2093 for (i = 0; i < num_phys; i++) {
2094 cpdi[i] = ddi_get32(page_accessp,
2095 &sasioupage1->PhyData[i].
2096 ControllerPhyDeviceInfo);
2097 port_flags = ddi_get8(page_accessp,
2098 &sasioupage1->PhyData[i].PortFlags);
2099 mpt->m_phy_info[i].port_num =
2100 ddi_get8(page_accessp,
2101 &sasioupage1->PhyData[i].Port);
2102 mpt->m_phy_info[i].port_flags = port_flags;
2103 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2104
2105 }
2106
2107 state = IOUC_DONE;
2108 rval = DDI_SUCCESS;
2109 break;
2110 }
2111 }
2112 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2113 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2114 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2115 rval = DDI_FAILURE;
2116 goto cleanup;
2117 }
2118 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2119 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2120 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2121 rval = DDI_FAILURE;
2122 goto cleanup;
2123 }
2124
2125 cleanup:
2126 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2127 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2128 if (rval != DDI_SUCCESS) {
2129 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
2130 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
2131 }
2132 return (rval);
2133 }
2134
2135 /*
2136 * mptsas_get_manufacture_page5
2137 *
2138 * This function will retrieve the base WWID from the adapter. Since this
2139 * function is only called during the initialization process, use handshaking.
2140 */
2141 int
mptsas_get_manufacture_page5(mptsas_t * mpt)2142 mptsas_get_manufacture_page5(mptsas_t *mpt)
2143 {
2144 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2145 ddi_dma_cookie_t page_cookie;
2146 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2147 ddi_acc_handle_t recv_accessp, page_accessp;
2148 pMpi2ConfigReply_t configreply;
2149 caddr_t recv_memp, page_memp;
2150 int recv_numbytes;
2151 pMpi2ManufacturingPage5_t m5;
2152 uint32_t flagslength;
2153 int rval = DDI_SUCCESS;
2154 uint_t iocstatus;
2155
2156 MPTSAS_DISABLE_INTR(mpt);
2157
2158 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2159 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
2160 rval = DDI_FAILURE;
2161 goto done;
2162 }
2163
2164 /*
2165 * dynamically create a customized dma attribute structure
2166 * that describes the MPT's config reply page request structure.
2167 */
2168 recv_dma_attrs = mpt->m_msg_dma_attr;
2169 recv_dma_attrs.dma_attr_sgllen = 1;
2170 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2171
2172 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
2173 &recv_dma_handle, &recv_accessp, &recv_memp,
2174 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2175 goto done;
2176 }
2177
2178 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2179 configreply = (pMpi2ConfigReply_t)recv_memp;
2180 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2181
2182 /*
2183 * get config reply message
2184 */
2185 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2186 recv_accessp)) {
2187 rval = DDI_FAILURE;
2188 goto done;
2189 }
2190
2191 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2192 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2193 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2194 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2195 goto done;
2196 }
2197
2198 /*
2199 * dynamically create a customized dma attribute structure
2200 * that describes the MPT's config page structure.
2201 */
2202 page_dma_attrs = mpt->m_msg_dma_attr;
2203 page_dma_attrs.dma_attr_sgllen = 1;
2204 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2205
2206 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2207 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2208 &page_cookie) == FALSE) {
2209 goto done;
2210 }
2211 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
2212 m5 = (pMpi2ManufacturingPage5_t)page_memp;
2213
2214 /*
2215 * Give reply address to IOC to store config page in and send
2216 * config request out.
2217 */
2218
2219 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
2220 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2221 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2222 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2223 MPI2_SGE_FLAGS_IOC_TO_HOST |
2224 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2225
2226 if (mptsas_send_config_request_msg(mpt,
2227 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2228 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2229 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2230 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2231 flagslength, page_cookie.dmac_address)) {
2232 rval = DDI_FAILURE;
2233 goto done;
2234 }
2235
2236 /*
2237 * get reply view handshake
2238 */
2239 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2240 recv_accessp)) {
2241 rval = DDI_FAILURE;
2242 goto done;
2243 }
2244
2245 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2246 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2247 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2248 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2249 goto done;
2250 }
2251
2252 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2253
2254 /*
2255 * Fusion-MPT stores fields in little-endian format. This is
2256 * why the low-order 32 bits are stored first.
2257 */
2258 mpt->un.sasaddr.m_base_wwid_lo =
2259 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
2260 mpt->un.sasaddr.m_base_wwid_hi =
2261 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
2262
2263 if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
2264 "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
2265 NDBG2(("%s%d: failed to create base-wwid property",
2266 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2267 }
2268
2269 /*
2270 * Set the number of PHYs present.
2271 */
2272 mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
2273
2274 if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
2275 "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
2276 NDBG2(("%s%d: failed to create num-phys property",
2277 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2278 }
2279
2280 mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2281 mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
2282 (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2283
2284 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2285 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2286 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2287 rval = DDI_FAILURE;
2288 goto done;
2289 }
2290 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2291 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2292 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2293 rval = DDI_FAILURE;
2294 }
2295 done:
2296 /*
2297 * free up memory
2298 */
2299 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2300 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2301 MPTSAS_ENABLE_INTR(mpt);
2302
2303 return (rval);
2304 }
2305
2306 static int
mptsas_sasphypage_0_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)2307 mptsas_sasphypage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2308 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2309 va_list ap)
2310 {
2311 #ifndef __lock_lint
2312 _NOTE(ARGUNUSED(ap))
2313 #endif
2314 pMpi2SasPhyPage0_t sasphypage;
2315 int rval = DDI_SUCCESS;
2316 uint16_t *owner_devhdl, *attached_devhdl;
2317 uint8_t *attached_phy_identify;
2318 uint32_t *attached_phy_info;
2319 uint8_t *programmed_link_rate;
2320 uint8_t *hw_link_rate;
2321 uint8_t *change_count;
2322 uint32_t *phy_info;
2323 uint8_t *negotiated_link_rate;
2324 uint32_t page_address;
2325
2326 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2327 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2328 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
2329 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2330 iocstatus, iocloginfo);
2331 rval = DDI_FAILURE;
2332 return (rval);
2333 }
2334 page_address = va_arg(ap, uint32_t);
2335 /*
2336 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2337 * are no more pages. If everything is OK up to this point but the
2338 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2339 * signal that device traversal is complete.
2340 */
2341 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2342 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2343 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2344 mpt->m_done_traverse_smp = 1;
2345 }
2346 rval = DDI_FAILURE;
2347 return (rval);
2348 }
2349 owner_devhdl = va_arg(ap, uint16_t *);
2350 attached_devhdl = va_arg(ap, uint16_t *);
2351 attached_phy_identify = va_arg(ap, uint8_t *);
2352 attached_phy_info = va_arg(ap, uint32_t *);
2353 programmed_link_rate = va_arg(ap, uint8_t *);
2354 hw_link_rate = va_arg(ap, uint8_t *);
2355 change_count = va_arg(ap, uint8_t *);
2356 phy_info = va_arg(ap, uint32_t *);
2357 negotiated_link_rate = va_arg(ap, uint8_t *);
2358
2359 sasphypage = (pMpi2SasPhyPage0_t)page_memp;
2360
2361 *owner_devhdl =
2362 ddi_get16(accessp, &sasphypage->OwnerDevHandle);
2363 *attached_devhdl =
2364 ddi_get16(accessp, &sasphypage->AttachedDevHandle);
2365 *attached_phy_identify =
2366 ddi_get8(accessp, &sasphypage->AttachedPhyIdentifier);
2367 *attached_phy_info =
2368 ddi_get32(accessp, &sasphypage->AttachedPhyInfo);
2369 *programmed_link_rate =
2370 ddi_get8(accessp, &sasphypage->ProgrammedLinkRate);
2371 *hw_link_rate =
2372 ddi_get8(accessp, &sasphypage->HwLinkRate);
2373 *change_count =
2374 ddi_get8(accessp, &sasphypage->ChangeCount);
2375 *phy_info =
2376 ddi_get32(accessp, &sasphypage->PhyInfo);
2377 *negotiated_link_rate =
2378 ddi_get8(accessp, &sasphypage->NegotiatedLinkRate);
2379
2380 return (rval);
2381 }
2382
2383 /*
2384 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2385 * and SAS address.
2386 */
2387 int
mptsas_get_sas_phy_page0(mptsas_t * mpt,uint32_t page_address,smhba_info_t * info)2388 mptsas_get_sas_phy_page0(mptsas_t *mpt, uint32_t page_address,
2389 smhba_info_t *info)
2390 {
2391 int rval = DDI_SUCCESS;
2392
2393 ASSERT(mutex_owned(&mpt->m_mutex));
2394
2395 /*
2396 * Get the header and config page. reply contains the reply frame,
2397 * which holds status info for the request.
2398 */
2399 rval = mptsas_access_config_page(mpt,
2400 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2401 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 0, page_address,
2402 mptsas_sasphypage_0_cb, page_address, &info->owner_devhdl,
2403 &info->attached_devhdl, &info->attached_phy_identify,
2404 &info->attached_phy_info, &info->programmed_link_rate,
2405 &info->hw_link_rate, &info->change_count,
2406 &info->phy_info, &info->negotiated_link_rate);
2407
2408 return (rval);
2409 }
2410
2411 static int
mptsas_sasphypage_1_cb(mptsas_t * mpt,caddr_t page_memp,ddi_acc_handle_t accessp,uint16_t iocstatus,uint32_t iocloginfo,va_list ap)2412 mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
2413 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2414 va_list ap)
2415 {
2416 #ifndef __lock_lint
2417 _NOTE(ARGUNUSED(ap))
2418 #endif
2419 pMpi2SasPhyPage1_t sasphypage;
2420 int rval = DDI_SUCCESS;
2421
2422 uint32_t *invalid_dword_count;
2423 uint32_t *running_disparity_error_count;
2424 uint32_t *loss_of_dword_sync_count;
2425 uint32_t *phy_reset_problem_count;
2426 uint32_t page_address;
2427
2428 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2429 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2430 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page1 "
2431 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2432 iocstatus, iocloginfo);
2433 rval = DDI_FAILURE;
2434 return (rval);
2435 }
2436 page_address = va_arg(ap, uint32_t);
2437 /*
2438 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2439 * are no more pages. If everything is OK up to this point but the
2440 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2441 * signal that device traversal is complete.
2442 */
2443 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2444 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2445 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2446 mpt->m_done_traverse_smp = 1;
2447 }
2448 rval = DDI_FAILURE;
2449 return (rval);
2450 }
2451
2452 invalid_dword_count = va_arg(ap, uint32_t *);
2453 running_disparity_error_count = va_arg(ap, uint32_t *);
2454 loss_of_dword_sync_count = va_arg(ap, uint32_t *);
2455 phy_reset_problem_count = va_arg(ap, uint32_t *);
2456
2457 sasphypage = (pMpi2SasPhyPage1_t)page_memp;
2458
2459 *invalid_dword_count =
2460 ddi_get32(accessp, &sasphypage->InvalidDwordCount);
2461 *running_disparity_error_count =
2462 ddi_get32(accessp, &sasphypage->RunningDisparityErrorCount);
2463 *loss_of_dword_sync_count =
2464 ddi_get32(accessp, &sasphypage->LossDwordSynchCount);
2465 *phy_reset_problem_count =
2466 ddi_get32(accessp, &sasphypage->PhyResetProblemCount);
2467
2468 return (rval);
2469 }
2470
2471 /*
2472 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2473 * and SAS address.
2474 */
2475 int
mptsas_get_sas_phy_page1(mptsas_t * mpt,uint32_t page_address,smhba_info_t * info)2476 mptsas_get_sas_phy_page1(mptsas_t *mpt, uint32_t page_address,
2477 smhba_info_t *info)
2478 {
2479 int rval = DDI_SUCCESS;
2480
2481 ASSERT(mutex_owned(&mpt->m_mutex));
2482
2483 /*
2484 * Get the header and config page. reply contains the reply frame,
2485 * which holds status info for the request.
2486 */
2487 rval = mptsas_access_config_page(mpt,
2488 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2489 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 1, page_address,
2490 mptsas_sasphypage_1_cb, page_address,
2491 &info->invalid_dword_count,
2492 &info->running_disparity_error_count,
2493 &info->loss_of_dword_sync_count,
2494 &info->phy_reset_problem_count);
2495
2496 return (rval);
2497 }
2498 /*
2499 * mptsas_get_manufacture_page0
2500 *
2501 * This function will retrieve the base
2502 * Chip name, Board Name,Board Trace number from the adapter.
2503 * Since this function is only called during the
2504 * initialization process, use handshaking.
2505 */
2506 int
mptsas_get_manufacture_page0(mptsas_t * mpt)2507 mptsas_get_manufacture_page0(mptsas_t *mpt)
2508 {
2509 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2510 ddi_dma_cookie_t page_cookie;
2511 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2512 ddi_acc_handle_t recv_accessp, page_accessp;
2513 pMpi2ConfigReply_t configreply;
2514 caddr_t recv_memp, page_memp;
2515 int recv_numbytes;
2516 pMpi2ManufacturingPage0_t m0;
2517 uint32_t flagslength;
2518 int rval = DDI_SUCCESS;
2519 uint_t iocstatus;
2520 uint8_t i = 0;
2521
2522 MPTSAS_DISABLE_INTR(mpt);
2523
2524 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2525 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, 0, 0, 0, 0)) {
2526 rval = DDI_FAILURE;
2527 goto done;
2528 }
2529
2530 /*
2531 * dynamically create a customized dma attribute structure
2532 * that describes the MPT's config reply page request structure.
2533 */
2534 recv_dma_attrs = mpt->m_msg_dma_attr;
2535 recv_dma_attrs.dma_attr_sgllen = 1;
2536 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2537
2538 if (mptsas_dma_addr_create(mpt, recv_dma_attrs, &recv_dma_handle,
2539 &recv_accessp, &recv_memp, (sizeof (MPI2_CONFIG_REPLY)),
2540 NULL) == FALSE) {
2541 goto done;
2542 }
2543 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2544 configreply = (pMpi2ConfigReply_t)recv_memp;
2545 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2546
2547 /*
2548 * get config reply message
2549 */
2550 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2551 recv_accessp)) {
2552 rval = DDI_FAILURE;
2553 goto done;
2554 }
2555
2556 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2557 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2558 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2559 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2560 goto done;
2561 }
2562
2563 /*
2564 * dynamically create a customized dma attribute structure
2565 * that describes the MPT's config page structure.
2566 */
2567 page_dma_attrs = mpt->m_msg_dma_attr;
2568 page_dma_attrs.dma_attr_sgllen = 1;
2569 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2570
2571 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2572 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2573 &page_cookie) == FALSE) {
2574 goto done;
2575 }
2576 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
2577 m0 = (pMpi2ManufacturingPage0_t)page_memp;
2578
2579 /*
2580 * Give reply address to IOC to store config page in and send
2581 * config request out.
2582 */
2583
2584 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
2585 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2586 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2587 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2588 MPI2_SGE_FLAGS_IOC_TO_HOST |
2589 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2590
2591 if (mptsas_send_config_request_msg(mpt,
2592 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2593 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2594 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2595 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2596 flagslength, page_cookie.dmac_address)) {
2597 rval = DDI_FAILURE;
2598 goto done;
2599 }
2600
2601 /*
2602 * get reply view handshake
2603 */
2604 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2605 recv_accessp)) {
2606 rval = DDI_FAILURE;
2607 goto done;
2608 }
2609
2610 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2611 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2612 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2613 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2614 goto done;
2615 }
2616
2617 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2618
2619 /*
2620 * Fusion-MPT stores fields in little-endian format. This is
2621 * why the low-order 32 bits are stored first.
2622 */
2623
2624 for (i = 0; i < 16; i++) {
2625 mpt->m_MANU_page0.ChipName[i] =
2626 ddi_get8(page_accessp,
2627 (uint8_t *)(void *)&m0->ChipName[i]);
2628 }
2629
2630 for (i = 0; i < 8; i++) {
2631 mpt->m_MANU_page0.ChipRevision[i] =
2632 ddi_get8(page_accessp,
2633 (uint8_t *)(void *)&m0->ChipRevision[i]);
2634 }
2635
2636 for (i = 0; i < 16; i++) {
2637 mpt->m_MANU_page0.BoardName[i] =
2638 ddi_get8(page_accessp,
2639 (uint8_t *)(void *)&m0->BoardName[i]);
2640 }
2641
2642 for (i = 0; i < 16; i++) {
2643 mpt->m_MANU_page0.BoardAssembly[i] =
2644 ddi_get8(page_accessp,
2645 (uint8_t *)(void *)&m0->BoardAssembly[i]);
2646 }
2647
2648 for (i = 0; i < 16; i++) {
2649 mpt->m_MANU_page0.BoardTracerNumber[i] =
2650 ddi_get8(page_accessp,
2651 (uint8_t *)(void *)&m0->BoardTracerNumber[i]);
2652 }
2653
2654 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2655 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2656 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2657 rval = DDI_FAILURE;
2658 goto done;
2659 }
2660 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2661 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2662 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2663 rval = DDI_FAILURE;
2664 }
2665 done:
2666 /*
2667 * free up memory
2668 */
2669 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2670 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2671 MPTSAS_ENABLE_INTR(mpt);
2672
2673 return (rval);
2674 }
2675