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