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 }
2682