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