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