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