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