1 /*
2  * This module provides common API for accessing firmware configuration pages
3  *
4  * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c
5  * Copyright (C) 2012-2013  LSI Corporation
6  *  (mailto:DL-MPTFusionLinux@lsi.com)
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * NO WARRANTY
19  * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
20  * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
21  * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
22  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
23  * solely responsible for determining the appropriateness of using and
24  * distributing the Program and assumes all risks associated with its
25  * exercise of rights under this Agreement, including but not limited to
26  * the risks and costs of program errors, damage to or loss of data,
27  * programs or equipment, and unavailability or interruption of operations.
28 
29  * DISCLAIMER OF LIABILITY
30  * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
31  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
33  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
34  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
35  * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
36  * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
37 
38  * You should have received a copy of the GNU General Public License
39  * along with this program; if not, write to the Free Software
40  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
41  * USA.
42  */
43 
44 #include <linux/module.h>
45 #include <linux/kernel.h>
46 #include <linux/init.h>
47 #include <linux/errno.h>
48 #include <linux/blkdev.h>
49 #include <linux/sched.h>
50 #include <linux/workqueue.h>
51 #include <linux/delay.h>
52 #include <linux/pci.h>
53 
54 #include "mpt3sas_base.h"
55 
56 /* local definitions */
57 
58 /* Timeout for config page request (in seconds) */
59 #define MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT 15
60 
61 /* Common sgl flags for READING a config page. */
62 #define MPT3_CONFIG_COMMON_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \
63 	MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \
64 	| MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT)
65 
66 /* Common sgl flags for WRITING a config page. */
67 #define MPT3_CONFIG_COMMON_WRITE_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \
68 	MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \
69 	| MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC) \
70 	<< MPI2_SGE_FLAGS_SHIFT)
71 
72 /**
73  * struct config_request - obtain dma memory via routine
74  * @sz: size
75  * @page: virt pointer
76  * @page_dma: phys pointer
77  *
78  */
79 struct config_request {
80 	u16			sz;
81 	void			*page;
82 	dma_addr_t		page_dma;
83 };
84 
85 #ifdef CONFIG_SCSI_MPT3SAS_LOGGING
86 /**
87  * _config_display_some_debug - debug routine
88  * @ioc: per adapter object
89  * @smid: system request message index
90  * @calling_function_name: string pass from calling function
91  * @mpi_reply: reply message frame
92  * Context: none.
93  *
94  * Function for displaying debug info helpful when debugging issues
95  * in this module.
96  */
97 static void
98 _config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
99 	char *calling_function_name, MPI2DefaultReply_t *mpi_reply)
100 {
101 	Mpi2ConfigRequest_t *mpi_request;
102 	char *desc = NULL;
103 
104 	if (!(ioc->logging_level & MPT_DEBUG_CONFIG))
105 		return;
106 
107 	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
108 	switch (mpi_request->Header.PageType & MPI2_CONFIG_PAGETYPE_MASK) {
109 	case MPI2_CONFIG_PAGETYPE_IO_UNIT:
110 		desc = "io_unit";
111 		break;
112 	case MPI2_CONFIG_PAGETYPE_IOC:
113 		desc = "ioc";
114 		break;
115 	case MPI2_CONFIG_PAGETYPE_BIOS:
116 		desc = "bios";
117 		break;
118 	case MPI2_CONFIG_PAGETYPE_RAID_VOLUME:
119 		desc = "raid_volume";
120 		break;
121 	case MPI2_CONFIG_PAGETYPE_MANUFACTURING:
122 		desc = "manufaucturing";
123 		break;
124 	case MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK:
125 		desc = "physdisk";
126 		break;
127 	case MPI2_CONFIG_PAGETYPE_EXTENDED:
128 		switch (mpi_request->ExtPageType) {
129 		case MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT:
130 			desc = "sas_io_unit";
131 			break;
132 		case MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER:
133 			desc = "sas_expander";
134 			break;
135 		case MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE:
136 			desc = "sas_device";
137 			break;
138 		case MPI2_CONFIG_EXTPAGETYPE_SAS_PHY:
139 			desc = "sas_phy";
140 			break;
141 		case MPI2_CONFIG_EXTPAGETYPE_LOG:
142 			desc = "log";
143 			break;
144 		case MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE:
145 			desc = "enclosure";
146 			break;
147 		case MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG:
148 			desc = "raid_config";
149 			break;
150 		case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING:
151 			desc = "driver_mapping";
152 			break;
153 		}
154 		break;
155 	}
156 
157 	if (!desc)
158 		return;
159 
160 	pr_info(MPT3SAS_FMT
161 		"%s: %s(%d), action(%d), form(0x%08x), smid(%d)\n",
162 		ioc->name, calling_function_name, desc,
163 	    mpi_request->Header.PageNumber, mpi_request->Action,
164 	    le32_to_cpu(mpi_request->PageAddress), smid);
165 
166 	if (!mpi_reply)
167 		return;
168 
169 	if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
170 		pr_info(MPT3SAS_FMT
171 		    "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
172 		    ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
173 		    le32_to_cpu(mpi_reply->IOCLogInfo));
174 }
175 #endif
176 
177 /**
178  * _config_alloc_config_dma_memory - obtain physical memory
179  * @ioc: per adapter object
180  * @mem: struct config_request
181  *
182  * A wrapper for obtaining dma-able memory for config page request.
183  *
184  * Returns 0 for success, non-zero for failure.
185  */
186 static int
187 _config_alloc_config_dma_memory(struct MPT3SAS_ADAPTER *ioc,
188 	struct config_request *mem)
189 {
190 	int r = 0;
191 
192 	if (mem->sz > ioc->config_page_sz) {
193 		mem->page = dma_alloc_coherent(&ioc->pdev->dev, mem->sz,
194 		    &mem->page_dma, GFP_KERNEL);
195 		if (!mem->page) {
196 			pr_err(MPT3SAS_FMT
197 				"%s: dma_alloc_coherent failed asking for (%d) bytes!!\n",
198 			    ioc->name, __func__, mem->sz);
199 			r = -ENOMEM;
200 		}
201 	} else { /* use tmp buffer if less than 512 bytes */
202 		mem->page = ioc->config_page;
203 		mem->page_dma = ioc->config_page_dma;
204 	}
205 	return r;
206 }
207 
208 /**
209  * _config_free_config_dma_memory - wrapper to free the memory
210  * @ioc: per adapter object
211  * @mem: struct config_request
212  *
213  * A wrapper to free dma-able memory when using _config_alloc_config_dma_memory.
214  *
215  * Returns 0 for success, non-zero for failure.
216  */
217 static void
218 _config_free_config_dma_memory(struct MPT3SAS_ADAPTER *ioc,
219 	struct config_request *mem)
220 {
221 	if (mem->sz > ioc->config_page_sz)
222 		dma_free_coherent(&ioc->pdev->dev, mem->sz, mem->page,
223 		    mem->page_dma);
224 }
225 
226 /**
227  * mpt3sas_config_done - config page completion routine
228  * @ioc: per adapter object
229  * @smid: system request message index
230  * @msix_index: MSIX table index supplied by the OS
231  * @reply: reply message frame(lower 32bit addr)
232  * Context: none.
233  *
234  * The callback handler when using _config_request.
235  *
236  * Return 1 meaning mf should be freed from _base_interrupt
237  *        0 means the mf is freed from this function.
238  */
239 u8
240 mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
241 	u32 reply)
242 {
243 	MPI2DefaultReply_t *mpi_reply;
244 
245 	if (ioc->config_cmds.status == MPT3_CMD_NOT_USED)
246 		return 1;
247 	if (ioc->config_cmds.smid != smid)
248 		return 1;
249 	ioc->config_cmds.status |= MPT3_CMD_COMPLETE;
250 	mpi_reply =  mpt3sas_base_get_reply_virt_addr(ioc, reply);
251 	if (mpi_reply) {
252 		ioc->config_cmds.status |= MPT3_CMD_REPLY_VALID;
253 		memcpy(ioc->config_cmds.reply, mpi_reply,
254 		    mpi_reply->MsgLength*4);
255 	}
256 	ioc->config_cmds.status &= ~MPT3_CMD_PENDING;
257 #ifdef CONFIG_SCSI_MPT3SAS_LOGGING
258 	_config_display_some_debug(ioc, smid, "config_done", mpi_reply);
259 #endif
260 	ioc->config_cmds.smid = USHRT_MAX;
261 	complete(&ioc->config_cmds.done);
262 	return 1;
263 }
264 
265 /**
266  * _config_request - main routine for sending config page requests
267  * @ioc: per adapter object
268  * @mpi_request: request message frame
269  * @mpi_reply: reply mf payload returned from firmware
270  * @timeout: timeout in seconds
271  * @config_page: contents of the config page
272  * @config_page_sz: size of config page
273  * Context: sleep
274  *
275  * A generic API for config page requests to firmware.
276  *
277  * The ioc->config_cmds.status flag should be MPT3_CMD_NOT_USED before calling
278  * this API.
279  *
280  * The callback index is set inside `ioc->config_cb_idx.
281  *
282  * Returns 0 for success, non-zero for failure.
283  */
284 static int
285 _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
286 	*mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout,
287 	void *config_page, u16 config_page_sz)
288 {
289 	u16 smid;
290 	u32 ioc_state;
291 	unsigned long timeleft;
292 	Mpi2ConfigRequest_t *config_request;
293 	int r;
294 	u8 retry_count, issue_host_reset = 0;
295 	u16 wait_state_count;
296 	struct config_request mem;
297 	u32 ioc_status = UINT_MAX;
298 
299 	mutex_lock(&ioc->config_cmds.mutex);
300 	if (ioc->config_cmds.status != MPT3_CMD_NOT_USED) {
301 		pr_err(MPT3SAS_FMT "%s: config_cmd in use\n",
302 		    ioc->name, __func__);
303 		mutex_unlock(&ioc->config_cmds.mutex);
304 		return -EAGAIN;
305 	}
306 
307 	retry_count = 0;
308 	memset(&mem, 0, sizeof(struct config_request));
309 
310 	mpi_request->VF_ID = 0; /* TODO */
311 	mpi_request->VP_ID = 0;
312 
313 	if (config_page) {
314 		mpi_request->Header.PageVersion = mpi_reply->Header.PageVersion;
315 		mpi_request->Header.PageNumber = mpi_reply->Header.PageNumber;
316 		mpi_request->Header.PageType = mpi_reply->Header.PageType;
317 		mpi_request->Header.PageLength = mpi_reply->Header.PageLength;
318 		mpi_request->ExtPageLength = mpi_reply->ExtPageLength;
319 		mpi_request->ExtPageType = mpi_reply->ExtPageType;
320 		if (mpi_request->Header.PageLength)
321 			mem.sz = mpi_request->Header.PageLength * 4;
322 		else
323 			mem.sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
324 		r = _config_alloc_config_dma_memory(ioc, &mem);
325 		if (r != 0)
326 			goto out;
327 		if (mpi_request->Action ==
328 		    MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT ||
329 		    mpi_request->Action ==
330 		    MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
331 			ioc->base_add_sg_single(&mpi_request->PageBufferSGE,
332 			    MPT3_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz,
333 			    mem.page_dma);
334 			memcpy(mem.page, config_page, min_t(u16, mem.sz,
335 			    config_page_sz));
336 		} else {
337 			memset(config_page, 0, config_page_sz);
338 			ioc->base_add_sg_single(&mpi_request->PageBufferSGE,
339 			    MPT3_CONFIG_COMMON_SGLFLAGS | mem.sz, mem.page_dma);
340 			memset(mem.page, 0, min_t(u16, mem.sz, config_page_sz));
341 		}
342 	}
343 
344  retry_config:
345 	if (retry_count) {
346 		if (retry_count > 2) { /* attempt only 2 retries */
347 			r = -EFAULT;
348 			goto free_mem;
349 		}
350 		pr_info(MPT3SAS_FMT "%s: attempting retry (%d)\n",
351 		    ioc->name, __func__, retry_count);
352 	}
353 	wait_state_count = 0;
354 	ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
355 	while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
356 		if (wait_state_count++ == MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT) {
357 			pr_err(MPT3SAS_FMT
358 			    "%s: failed due to ioc not operational\n",
359 			    ioc->name, __func__);
360 			ioc->config_cmds.status = MPT3_CMD_NOT_USED;
361 			r = -EFAULT;
362 			goto free_mem;
363 		}
364 		ssleep(1);
365 		ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
366 		pr_info(MPT3SAS_FMT
367 			"%s: waiting for operational state(count=%d)\n",
368 			ioc->name, __func__, wait_state_count);
369 	}
370 	if (wait_state_count)
371 		pr_info(MPT3SAS_FMT "%s: ioc is operational\n",
372 		    ioc->name, __func__);
373 
374 	smid = mpt3sas_base_get_smid(ioc, ioc->config_cb_idx);
375 	if (!smid) {
376 		pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
377 		    ioc->name, __func__);
378 		ioc->config_cmds.status = MPT3_CMD_NOT_USED;
379 		r = -EAGAIN;
380 		goto free_mem;
381 	}
382 
383 	r = 0;
384 	memset(mpi_reply, 0, sizeof(Mpi2ConfigReply_t));
385 	ioc->config_cmds.status = MPT3_CMD_PENDING;
386 	config_request = mpt3sas_base_get_msg_frame(ioc, smid);
387 	ioc->config_cmds.smid = smid;
388 	memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
389 #ifdef CONFIG_SCSI_MPT3SAS_LOGGING
390 	_config_display_some_debug(ioc, smid, "config_request", NULL);
391 #endif
392 	init_completion(&ioc->config_cmds.done);
393 	mpt3sas_base_put_smid_default(ioc, smid);
394 	timeleft = wait_for_completion_timeout(&ioc->config_cmds.done,
395 	    timeout*HZ);
396 	if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) {
397 		pr_err(MPT3SAS_FMT "%s: timeout\n",
398 		    ioc->name, __func__);
399 		_debug_dump_mf(mpi_request,
400 		    sizeof(Mpi2ConfigRequest_t)/4);
401 		retry_count++;
402 		if (ioc->config_cmds.smid == smid)
403 			mpt3sas_base_free_smid(ioc, smid);
404 		if ((ioc->shost_recovery) || (ioc->config_cmds.status &
405 		    MPT3_CMD_RESET) || ioc->pci_error_recovery)
406 			goto retry_config;
407 		issue_host_reset = 1;
408 		r = -EFAULT;
409 		goto free_mem;
410 	}
411 
412 	if (ioc->config_cmds.status & MPT3_CMD_REPLY_VALID) {
413 		memcpy(mpi_reply, ioc->config_cmds.reply,
414 		    sizeof(Mpi2ConfigReply_t));
415 
416 		/* Reply Frame Sanity Checks to workaround FW issues */
417 		if ((mpi_request->Header.PageType & 0xF) !=
418 		    (mpi_reply->Header.PageType & 0xF)) {
419 			_debug_dump_mf(mpi_request, ioc->request_sz/4);
420 			_debug_dump_reply(mpi_reply, ioc->request_sz/4);
421 			panic(KERN_WARNING MPT3SAS_FMT "%s: Firmware BUG:" \
422 			    " mpi_reply mismatch: Requested PageType(0x%02x)" \
423 			    " Reply PageType(0x%02x)\n", \
424 			    ioc->name, __func__,
425 			    (mpi_request->Header.PageType & 0xF),
426 			    (mpi_reply->Header.PageType & 0xF));
427 		}
428 
429 		if (((mpi_request->Header.PageType & 0xF) ==
430 		    MPI2_CONFIG_PAGETYPE_EXTENDED) &&
431 		    mpi_request->ExtPageType != mpi_reply->ExtPageType) {
432 			_debug_dump_mf(mpi_request, ioc->request_sz/4);
433 			_debug_dump_reply(mpi_reply, ioc->request_sz/4);
434 			panic(KERN_WARNING MPT3SAS_FMT "%s: Firmware BUG:" \
435 			    " mpi_reply mismatch: Requested ExtPageType(0x%02x)"
436 			    " Reply ExtPageType(0x%02x)\n",
437 			    ioc->name, __func__, mpi_request->ExtPageType,
438 			    mpi_reply->ExtPageType);
439 		}
440 		ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
441 		    & MPI2_IOCSTATUS_MASK;
442 	}
443 
444 	if (retry_count)
445 		pr_info(MPT3SAS_FMT "%s: retry (%d) completed!!\n", \
446 		    ioc->name, __func__, retry_count);
447 
448 	if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) &&
449 	    config_page && mpi_request->Action ==
450 	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT) {
451 		u8 *p = (u8 *)mem.page;
452 
453 		/* Config Page Sanity Checks to workaround FW issues */
454 		if (p) {
455 			if ((mpi_request->Header.PageType & 0xF) !=
456 			    (p[3] & 0xF)) {
457 				_debug_dump_mf(mpi_request, ioc->request_sz/4);
458 				_debug_dump_reply(mpi_reply, ioc->request_sz/4);
459 				_debug_dump_config(p, min_t(u16, mem.sz,
460 				    config_page_sz)/4);
461 				panic(KERN_WARNING MPT3SAS_FMT
462 					"%s: Firmware BUG:" \
463 				    " config page mismatch:"
464 				    " Requested PageType(0x%02x)"
465 				    " Reply PageType(0x%02x)\n",
466 				    ioc->name, __func__,
467 				    (mpi_request->Header.PageType & 0xF),
468 				    (p[3] & 0xF));
469 			}
470 
471 			if (((mpi_request->Header.PageType & 0xF) ==
472 			    MPI2_CONFIG_PAGETYPE_EXTENDED) &&
473 			    (mpi_request->ExtPageType != p[6])) {
474 				_debug_dump_mf(mpi_request, ioc->request_sz/4);
475 				_debug_dump_reply(mpi_reply, ioc->request_sz/4);
476 				_debug_dump_config(p, min_t(u16, mem.sz,
477 				    config_page_sz)/4);
478 				panic(KERN_WARNING MPT3SAS_FMT
479 					"%s: Firmware BUG:" \
480 				    " config page mismatch:"
481 				    " Requested ExtPageType(0x%02x)"
482 				    " Reply ExtPageType(0x%02x)\n",
483 				    ioc->name, __func__,
484 				    mpi_request->ExtPageType, p[6]);
485 			}
486 		}
487 		memcpy(config_page, mem.page, min_t(u16, mem.sz,
488 		    config_page_sz));
489 	}
490 
491  free_mem:
492 	if (config_page)
493 		_config_free_config_dma_memory(ioc, &mem);
494  out:
495 	ioc->config_cmds.status = MPT3_CMD_NOT_USED;
496 	mutex_unlock(&ioc->config_cmds.mutex);
497 
498 	if (issue_host_reset)
499 		mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
500 		    FORCE_BIG_HAMMER);
501 	return r;
502 }
503 
504 /**
505  * mpt3sas_config_get_manufacturing_pg0 - obtain manufacturing page 0
506  * @ioc: per adapter object
507  * @mpi_reply: reply mf payload returned from firmware
508  * @config_page: contents of the config page
509  * Context: sleep.
510  *
511  * Returns 0 for success, non-zero for failure.
512  */
513 int
514 mpt3sas_config_get_manufacturing_pg0(struct MPT3SAS_ADAPTER *ioc,
515 	Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page)
516 {
517 	Mpi2ConfigRequest_t mpi_request;
518 	int r;
519 
520 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
521 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
522 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
523 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
524 	mpi_request.Header.PageNumber = 0;
525 	mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION;
526 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
527 	r = _config_request(ioc, &mpi_request, mpi_reply,
528 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
529 	if (r)
530 		goto out;
531 
532 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
533 	r = _config_request(ioc, &mpi_request, mpi_reply,
534 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
535 	    sizeof(*config_page));
536  out:
537 	return r;
538 }
539 
540 /**
541  * mpt3sas_config_get_manufacturing_pg7 - obtain manufacturing page 7
542  * @ioc: per adapter object
543  * @mpi_reply: reply mf payload returned from firmware
544  * @config_page: contents of the config page
545  * @sz: size of buffer passed in config_page
546  * Context: sleep.
547  *
548  * Returns 0 for success, non-zero for failure.
549  */
550 int
551 mpt3sas_config_get_manufacturing_pg7(struct MPT3SAS_ADAPTER *ioc,
552 	Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage7_t *config_page,
553 	u16 sz)
554 {
555 	Mpi2ConfigRequest_t mpi_request;
556 	int r;
557 
558 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
559 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
560 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
561 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
562 	mpi_request.Header.PageNumber = 7;
563 	mpi_request.Header.PageVersion = MPI2_MANUFACTURING7_PAGEVERSION;
564 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
565 	r = _config_request(ioc, &mpi_request, mpi_reply,
566 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
567 	if (r)
568 		goto out;
569 
570 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
571 	r = _config_request(ioc, &mpi_request, mpi_reply,
572 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
573 	    sz);
574  out:
575 	return r;
576 }
577 
578 /**
579  * mpt3sas_config_get_manufacturing_pg10 - obtain manufacturing page 10
580  * @ioc: per adapter object
581  * @mpi_reply: reply mf payload returned from firmware
582  * @config_page: contents of the config page
583  * Context: sleep.
584  *
585  * Returns 0 for success, non-zero for failure.
586  */
587 int
588 mpt3sas_config_get_manufacturing_pg10(struct MPT3SAS_ADAPTER *ioc,
589 	Mpi2ConfigReply_t *mpi_reply,
590 	struct Mpi2ManufacturingPage10_t *config_page)
591 {
592 	Mpi2ConfigRequest_t mpi_request;
593 	int r;
594 
595 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
596 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
597 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
598 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
599 	mpi_request.Header.PageNumber = 10;
600 	mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION;
601 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
602 	r = _config_request(ioc, &mpi_request, mpi_reply,
603 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
604 	if (r)
605 		goto out;
606 
607 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
608 	r = _config_request(ioc, &mpi_request, mpi_reply,
609 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
610 	    sizeof(*config_page));
611  out:
612 	return r;
613 }
614 
615 /**
616  * mpt3sas_config_get_manufacturing_pg11 - obtain manufacturing page 11
617  * @ioc: per adapter object
618  * @mpi_reply: reply mf payload returned from firmware
619  * @config_page: contents of the config page
620  * Context: sleep.
621  *
622  * Returns 0 for success, non-zero for failure.
623  */
624 int
625 mpt3sas_config_get_manufacturing_pg11(struct MPT3SAS_ADAPTER *ioc,
626 	Mpi2ConfigReply_t *mpi_reply,
627 	struct Mpi2ManufacturingPage11_t *config_page)
628 {
629 	Mpi2ConfigRequest_t mpi_request;
630 	int r;
631 
632 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
633 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
634 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
635 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
636 	mpi_request.Header.PageNumber = 11;
637 	mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION;
638 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
639 	r = _config_request(ioc, &mpi_request, mpi_reply,
640 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
641 	if (r)
642 		goto out;
643 
644 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
645 	r = _config_request(ioc, &mpi_request, mpi_reply,
646 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
647 	    sizeof(*config_page));
648  out:
649 	return r;
650 }
651 
652 /**
653  * mpt3sas_config_set_manufacturing_pg11 - set manufacturing page 11
654  * @ioc: per adapter object
655  * @mpi_reply: reply mf payload returned from firmware
656  * @config_page: contents of the config page
657  * Context: sleep.
658  *
659  * Returns 0 for success, non-zero for failure.
660  */
661 int
662 mpt3sas_config_set_manufacturing_pg11(struct MPT3SAS_ADAPTER *ioc,
663 	Mpi2ConfigReply_t *mpi_reply,
664 	struct Mpi2ManufacturingPage11_t *config_page)
665 {
666 	Mpi2ConfigRequest_t mpi_request;
667 	int r;
668 
669 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
670 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
671 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
672 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
673 	mpi_request.Header.PageNumber = 11;
674 	mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION;
675 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
676 	r = _config_request(ioc, &mpi_request, mpi_reply,
677 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
678 	if (r)
679 		goto out;
680 
681 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
682 	r = _config_request(ioc, &mpi_request, mpi_reply,
683 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
684 	    sizeof(*config_page));
685 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
686 	r = _config_request(ioc, &mpi_request, mpi_reply,
687 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
688 	    sizeof(*config_page));
689  out:
690 	return r;
691 }
692 
693 /**
694  * mpt3sas_config_get_bios_pg2 - obtain bios page 2
695  * @ioc: per adapter object
696  * @mpi_reply: reply mf payload returned from firmware
697  * @config_page: contents of the config page
698  * Context: sleep.
699  *
700  * Returns 0 for success, non-zero for failure.
701  */
702 int
703 mpt3sas_config_get_bios_pg2(struct MPT3SAS_ADAPTER *ioc,
704 	Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage2_t *config_page)
705 {
706 	Mpi2ConfigRequest_t mpi_request;
707 	int r;
708 
709 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
710 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
711 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
712 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
713 	mpi_request.Header.PageNumber = 2;
714 	mpi_request.Header.PageVersion = MPI2_BIOSPAGE2_PAGEVERSION;
715 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
716 	r = _config_request(ioc, &mpi_request, mpi_reply,
717 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
718 	if (r)
719 		goto out;
720 
721 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
722 	r = _config_request(ioc, &mpi_request, mpi_reply,
723 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
724 	    sizeof(*config_page));
725  out:
726 	return r;
727 }
728 
729 /**
730  * mpt3sas_config_get_bios_pg3 - obtain bios page 3
731  * @ioc: per adapter object
732  * @mpi_reply: reply mf payload returned from firmware
733  * @config_page: contents of the config page
734  * Context: sleep.
735  *
736  * Returns 0 for success, non-zero for failure.
737  */
738 int
739 mpt3sas_config_get_bios_pg3(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
740 	*mpi_reply, Mpi2BiosPage3_t *config_page)
741 {
742 	Mpi2ConfigRequest_t mpi_request;
743 	int r;
744 
745 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
746 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
747 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
748 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
749 	mpi_request.Header.PageNumber = 3;
750 	mpi_request.Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
751 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
752 	r = _config_request(ioc, &mpi_request, mpi_reply,
753 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
754 	if (r)
755 		goto out;
756 
757 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
758 	r = _config_request(ioc, &mpi_request, mpi_reply,
759 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
760 	    sizeof(*config_page));
761  out:
762 	return r;
763 }
764 
765 /**
766  * mpt3sas_config_get_iounit_pg0 - obtain iounit page 0
767  * @ioc: per adapter object
768  * @mpi_reply: reply mf payload returned from firmware
769  * @config_page: contents of the config page
770  * Context: sleep.
771  *
772  * Returns 0 for success, non-zero for failure.
773  */
774 int
775 mpt3sas_config_get_iounit_pg0(struct MPT3SAS_ADAPTER *ioc,
776 	Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage0_t *config_page)
777 {
778 	Mpi2ConfigRequest_t mpi_request;
779 	int r;
780 
781 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
782 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
783 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
784 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
785 	mpi_request.Header.PageNumber = 0;
786 	mpi_request.Header.PageVersion = MPI2_IOUNITPAGE0_PAGEVERSION;
787 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
788 	r = _config_request(ioc, &mpi_request, mpi_reply,
789 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
790 	if (r)
791 		goto out;
792 
793 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
794 	r = _config_request(ioc, &mpi_request, mpi_reply,
795 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
796 	    sizeof(*config_page));
797  out:
798 	return r;
799 }
800 
801 /**
802  * mpt3sas_config_get_iounit_pg1 - obtain iounit page 1
803  * @ioc: per adapter object
804  * @mpi_reply: reply mf payload returned from firmware
805  * @config_page: contents of the config page
806  * Context: sleep.
807  *
808  * Returns 0 for success, non-zero for failure.
809  */
810 int
811 mpt3sas_config_get_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
812 	Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page)
813 {
814 	Mpi2ConfigRequest_t mpi_request;
815 	int r;
816 
817 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
818 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
819 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
820 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
821 	mpi_request.Header.PageNumber = 1;
822 	mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION;
823 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
824 	r = _config_request(ioc, &mpi_request, mpi_reply,
825 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
826 	if (r)
827 		goto out;
828 
829 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
830 	r = _config_request(ioc, &mpi_request, mpi_reply,
831 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
832 	    sizeof(*config_page));
833  out:
834 	return r;
835 }
836 
837 /**
838  * mpt3sas_config_set_iounit_pg1 - set iounit page 1
839  * @ioc: per adapter object
840  * @mpi_reply: reply mf payload returned from firmware
841  * @config_page: contents of the config page
842  * Context: sleep.
843  *
844  * Returns 0 for success, non-zero for failure.
845  */
846 int
847 mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
848 	Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page)
849 {
850 	Mpi2ConfigRequest_t mpi_request;
851 	int r;
852 
853 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
854 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
855 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
856 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
857 	mpi_request.Header.PageNumber = 1;
858 	mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION;
859 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
860 	r = _config_request(ioc, &mpi_request, mpi_reply,
861 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
862 	if (r)
863 		goto out;
864 
865 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
866 	r = _config_request(ioc, &mpi_request, mpi_reply,
867 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
868 	    sizeof(*config_page));
869  out:
870 	return r;
871 }
872 
873 /**
874  * mpt3sas_config_get_ioc_pg8 - obtain ioc page 8
875  * @ioc: per adapter object
876  * @mpi_reply: reply mf payload returned from firmware
877  * @config_page: contents of the config page
878  * Context: sleep.
879  *
880  * Returns 0 for success, non-zero for failure.
881  */
882 int
883 mpt3sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc,
884 	Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page)
885 {
886 	Mpi2ConfigRequest_t mpi_request;
887 	int r;
888 
889 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
890 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
891 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
892 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
893 	mpi_request.Header.PageNumber = 8;
894 	mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
895 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
896 	r = _config_request(ioc, &mpi_request, mpi_reply,
897 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
898 	if (r)
899 		goto out;
900 
901 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
902 	r = _config_request(ioc, &mpi_request, mpi_reply,
903 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
904 	    sizeof(*config_page));
905  out:
906 	return r;
907 }
908 
909 /**
910  * mpt3sas_config_get_sas_device_pg0 - obtain sas device page 0
911  * @ioc: per adapter object
912  * @mpi_reply: reply mf payload returned from firmware
913  * @config_page: contents of the config page
914  * @form: GET_NEXT_HANDLE or HANDLE
915  * @handle: device handle
916  * Context: sleep.
917  *
918  * Returns 0 for success, non-zero for failure.
919  */
920 int
921 mpt3sas_config_get_sas_device_pg0(struct MPT3SAS_ADAPTER *ioc,
922 	Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage0_t *config_page,
923 	u32 form, u32 handle)
924 {
925 	Mpi2ConfigRequest_t mpi_request;
926 	int r;
927 
928 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
929 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
930 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
931 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
932 	mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
933 	mpi_request.Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
934 	mpi_request.Header.PageNumber = 0;
935 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
936 	r = _config_request(ioc, &mpi_request, mpi_reply,
937 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
938 	if (r)
939 		goto out;
940 
941 	mpi_request.PageAddress = cpu_to_le32(form | handle);
942 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
943 	r = _config_request(ioc, &mpi_request, mpi_reply,
944 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
945 	    sizeof(*config_page));
946  out:
947 	return r;
948 }
949 
950 /**
951  * mpt3sas_config_get_sas_device_pg1 - obtain sas device page 1
952  * @ioc: per adapter object
953  * @mpi_reply: reply mf payload returned from firmware
954  * @config_page: contents of the config page
955  * @form: GET_NEXT_HANDLE or HANDLE
956  * @handle: device handle
957  * Context: sleep.
958  *
959  * Returns 0 for success, non-zero for failure.
960  */
961 int
962 mpt3sas_config_get_sas_device_pg1(struct MPT3SAS_ADAPTER *ioc,
963 	Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage1_t *config_page,
964 	u32 form, u32 handle)
965 {
966 	Mpi2ConfigRequest_t mpi_request;
967 	int r;
968 
969 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
970 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
971 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
972 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
973 	mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
974 	mpi_request.Header.PageVersion = MPI2_SASDEVICE1_PAGEVERSION;
975 	mpi_request.Header.PageNumber = 1;
976 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
977 	r = _config_request(ioc, &mpi_request, mpi_reply,
978 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
979 	if (r)
980 		goto out;
981 
982 	mpi_request.PageAddress = cpu_to_le32(form | handle);
983 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
984 	r = _config_request(ioc, &mpi_request, mpi_reply,
985 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
986 	    sizeof(*config_page));
987  out:
988 	return r;
989 }
990 
991 /**
992  * mpt3sas_config_get_number_hba_phys - obtain number of phys on the host
993  * @ioc: per adapter object
994  * @num_phys: pointer returned with the number of phys
995  * Context: sleep.
996  *
997  * Returns 0 for success, non-zero for failure.
998  */
999 int
1000 mpt3sas_config_get_number_hba_phys(struct MPT3SAS_ADAPTER *ioc, u8 *num_phys)
1001 {
1002 	Mpi2ConfigRequest_t mpi_request;
1003 	int r;
1004 	u16 ioc_status;
1005 	Mpi2ConfigReply_t mpi_reply;
1006 	Mpi2SasIOUnitPage0_t config_page;
1007 
1008 	*num_phys = 0;
1009 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1010 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1011 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1012 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
1013 	mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1014 	mpi_request.Header.PageNumber = 0;
1015 	mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION;
1016 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1017 	r = _config_request(ioc, &mpi_request, &mpi_reply,
1018 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1019 	if (r)
1020 		goto out;
1021 
1022 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1023 	r = _config_request(ioc, &mpi_request, &mpi_reply,
1024 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page,
1025 	    sizeof(Mpi2SasIOUnitPage0_t));
1026 	if (!r) {
1027 		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1028 		    MPI2_IOCSTATUS_MASK;
1029 		if (ioc_status == MPI2_IOCSTATUS_SUCCESS)
1030 			*num_phys = config_page.NumPhys;
1031 	}
1032  out:
1033 	return r;
1034 }
1035 
1036 /**
1037  * mpt3sas_config_get_sas_iounit_pg0 - obtain sas iounit page 0
1038  * @ioc: per adapter object
1039  * @mpi_reply: reply mf payload returned from firmware
1040  * @config_page: contents of the config page
1041  * @sz: size of buffer passed in config_page
1042  * Context: sleep.
1043  *
1044  * Calling function should call config_get_number_hba_phys prior to
1045  * this function, so enough memory is allocated for config_page.
1046  *
1047  * Returns 0 for success, non-zero for failure.
1048  */
1049 int
1050 mpt3sas_config_get_sas_iounit_pg0(struct MPT3SAS_ADAPTER *ioc,
1051 	Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage0_t *config_page,
1052 	u16 sz)
1053 {
1054 	Mpi2ConfigRequest_t mpi_request;
1055 	int r;
1056 
1057 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1058 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1059 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1060 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
1061 	mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1062 	mpi_request.Header.PageNumber = 0;
1063 	mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION;
1064 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1065 	r = _config_request(ioc, &mpi_request, mpi_reply,
1066 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1067 	if (r)
1068 		goto out;
1069 
1070 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1071 	r = _config_request(ioc, &mpi_request, mpi_reply,
1072 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
1073  out:
1074 	return r;
1075 }
1076 
1077 /**
1078  * mpt3sas_config_get_sas_iounit_pg1 - obtain sas iounit page 1
1079  * @ioc: per adapter object
1080  * @mpi_reply: reply mf payload returned from firmware
1081  * @config_page: contents of the config page
1082  * @sz: size of buffer passed in config_page
1083  * Context: sleep.
1084  *
1085  * Calling function should call config_get_number_hba_phys prior to
1086  * this function, so enough memory is allocated for config_page.
1087  *
1088  * Returns 0 for success, non-zero for failure.
1089  */
1090 int
1091 mpt3sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
1092 	Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page,
1093 	u16 sz)
1094 {
1095 	Mpi2ConfigRequest_t mpi_request;
1096 	int r;
1097 
1098 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1099 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1100 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1101 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
1102 	mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1103 	mpi_request.Header.PageNumber = 1;
1104 	mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION;
1105 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1106 	r = _config_request(ioc, &mpi_request, mpi_reply,
1107 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1108 	if (r)
1109 		goto out;
1110 
1111 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1112 	r = _config_request(ioc, &mpi_request, mpi_reply,
1113 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
1114  out:
1115 	return r;
1116 }
1117 
1118 /**
1119  * mpt3sas_config_set_sas_iounit_pg1 - send sas iounit page 1
1120  * @ioc: per adapter object
1121  * @mpi_reply: reply mf payload returned from firmware
1122  * @config_page: contents of the config page
1123  * @sz: size of buffer passed in config_page
1124  * Context: sleep.
1125  *
1126  * Calling function should call config_get_number_hba_phys prior to
1127  * this function, so enough memory is allocated for config_page.
1128  *
1129  * Returns 0 for success, non-zero for failure.
1130  */
1131 int
1132 mpt3sas_config_set_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
1133 	Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page,
1134 	u16 sz)
1135 {
1136 	Mpi2ConfigRequest_t mpi_request;
1137 	int r;
1138 
1139 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1140 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1141 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1142 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
1143 	mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1144 	mpi_request.Header.PageNumber = 1;
1145 	mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION;
1146 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1147 	r = _config_request(ioc, &mpi_request, mpi_reply,
1148 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1149 	if (r)
1150 		goto out;
1151 
1152 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
1153 	_config_request(ioc, &mpi_request, mpi_reply,
1154 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
1155 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
1156 	r = _config_request(ioc, &mpi_request, mpi_reply,
1157 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
1158  out:
1159 	return r;
1160 }
1161 
1162 /**
1163  * mpt3sas_config_get_expander_pg0 - obtain expander page 0
1164  * @ioc: per adapter object
1165  * @mpi_reply: reply mf payload returned from firmware
1166  * @config_page: contents of the config page
1167  * @form: GET_NEXT_HANDLE or HANDLE
1168  * @handle: expander handle
1169  * Context: sleep.
1170  *
1171  * Returns 0 for success, non-zero for failure.
1172  */
1173 int
1174 mpt3sas_config_get_expander_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
1175 	*mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle)
1176 {
1177 	Mpi2ConfigRequest_t mpi_request;
1178 	int r;
1179 
1180 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1181 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1182 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1183 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
1184 	mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1185 	mpi_request.Header.PageNumber = 0;
1186 	mpi_request.Header.PageVersion = MPI2_SASEXPANDER0_PAGEVERSION;
1187 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1188 	r = _config_request(ioc, &mpi_request, mpi_reply,
1189 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1190 	if (r)
1191 		goto out;
1192 
1193 	mpi_request.PageAddress = cpu_to_le32(form | handle);
1194 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1195 	r = _config_request(ioc, &mpi_request, mpi_reply,
1196 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
1197 	    sizeof(*config_page));
1198  out:
1199 	return r;
1200 }
1201 
1202 /**
1203  * mpt3sas_config_get_expander_pg1 - obtain expander page 1
1204  * @ioc: per adapter object
1205  * @mpi_reply: reply mf payload returned from firmware
1206  * @config_page: contents of the config page
1207  * @phy_number: phy number
1208  * @handle: expander handle
1209  * Context: sleep.
1210  *
1211  * Returns 0 for success, non-zero for failure.
1212  */
1213 int
1214 mpt3sas_config_get_expander_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
1215 	*mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number,
1216 	u16 handle)
1217 {
1218 	Mpi2ConfigRequest_t mpi_request;
1219 	int r;
1220 
1221 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1222 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1223 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1224 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
1225 	mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1226 	mpi_request.Header.PageNumber = 1;
1227 	mpi_request.Header.PageVersion = MPI2_SASEXPANDER1_PAGEVERSION;
1228 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1229 	r = _config_request(ioc, &mpi_request, mpi_reply,
1230 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1231 	if (r)
1232 		goto out;
1233 
1234 	mpi_request.PageAddress =
1235 	    cpu_to_le32(MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
1236 	    (phy_number << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | handle);
1237 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1238 	r = _config_request(ioc, &mpi_request, mpi_reply,
1239 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
1240 	    sizeof(*config_page));
1241  out:
1242 	return r;
1243 }
1244 
1245 /**
1246  * mpt3sas_config_get_enclosure_pg0 - obtain enclosure page 0
1247  * @ioc: per adapter object
1248  * @mpi_reply: reply mf payload returned from firmware
1249  * @config_page: contents of the config page
1250  * @form: GET_NEXT_HANDLE or HANDLE
1251  * @handle: expander handle
1252  * Context: sleep.
1253  *
1254  * Returns 0 for success, non-zero for failure.
1255  */
1256 int
1257 mpt3sas_config_get_enclosure_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
1258 	*mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle)
1259 {
1260 	Mpi2ConfigRequest_t mpi_request;
1261 	int r;
1262 
1263 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1264 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1265 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1266 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
1267 	mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE;
1268 	mpi_request.Header.PageNumber = 0;
1269 	mpi_request.Header.PageVersion = MPI2_SASENCLOSURE0_PAGEVERSION;
1270 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1271 	r = _config_request(ioc, &mpi_request, mpi_reply,
1272 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1273 	if (r)
1274 		goto out;
1275 
1276 	mpi_request.PageAddress = cpu_to_le32(form | handle);
1277 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1278 	r = _config_request(ioc, &mpi_request, mpi_reply,
1279 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
1280 	    sizeof(*config_page));
1281  out:
1282 	return r;
1283 }
1284 
1285 /**
1286  * mpt3sas_config_get_phy_pg0 - obtain phy page 0
1287  * @ioc: per adapter object
1288  * @mpi_reply: reply mf payload returned from firmware
1289  * @config_page: contents of the config page
1290  * @phy_number: phy number
1291  * Context: sleep.
1292  *
1293  * Returns 0 for success, non-zero for failure.
1294  */
1295 int
1296 mpt3sas_config_get_phy_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
1297 	*mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number)
1298 {
1299 	Mpi2ConfigRequest_t mpi_request;
1300 	int r;
1301 
1302 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1303 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1304 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1305 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
1306 	mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY;
1307 	mpi_request.Header.PageNumber = 0;
1308 	mpi_request.Header.PageVersion = MPI2_SASPHY0_PAGEVERSION;
1309 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1310 	r = _config_request(ioc, &mpi_request, mpi_reply,
1311 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1312 	if (r)
1313 		goto out;
1314 
1315 	mpi_request.PageAddress =
1316 	    cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number);
1317 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1318 	r = _config_request(ioc, &mpi_request, mpi_reply,
1319 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
1320 	    sizeof(*config_page));
1321  out:
1322 	return r;
1323 }
1324 
1325 /**
1326  * mpt3sas_config_get_phy_pg1 - obtain phy page 1
1327  * @ioc: per adapter object
1328  * @mpi_reply: reply mf payload returned from firmware
1329  * @config_page: contents of the config page
1330  * @phy_number: phy number
1331  * Context: sleep.
1332  *
1333  * Returns 0 for success, non-zero for failure.
1334  */
1335 int
1336 mpt3sas_config_get_phy_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
1337 	*mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number)
1338 {
1339 	Mpi2ConfigRequest_t mpi_request;
1340 	int r;
1341 
1342 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1343 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1344 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1345 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
1346 	mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY;
1347 	mpi_request.Header.PageNumber = 1;
1348 	mpi_request.Header.PageVersion = MPI2_SASPHY1_PAGEVERSION;
1349 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1350 	r = _config_request(ioc, &mpi_request, mpi_reply,
1351 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1352 	if (r)
1353 		goto out;
1354 
1355 	mpi_request.PageAddress =
1356 	    cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number);
1357 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1358 	r = _config_request(ioc, &mpi_request, mpi_reply,
1359 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
1360 	    sizeof(*config_page));
1361  out:
1362 	return r;
1363 }
1364 
1365 /**
1366  * mpt3sas_config_get_raid_volume_pg1 - obtain raid volume page 1
1367  * @ioc: per adapter object
1368  * @mpi_reply: reply mf payload returned from firmware
1369  * @config_page: contents of the config page
1370  * @form: GET_NEXT_HANDLE or HANDLE
1371  * @handle: volume handle
1372  * Context: sleep.
1373  *
1374  * Returns 0 for success, non-zero for failure.
1375  */
1376 int
1377 mpt3sas_config_get_raid_volume_pg1(struct MPT3SAS_ADAPTER *ioc,
1378 	Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form,
1379 	u32 handle)
1380 {
1381 	Mpi2ConfigRequest_t mpi_request;
1382 	int r;
1383 
1384 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1385 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1386 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1387 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1388 	mpi_request.Header.PageNumber = 1;
1389 	mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION;
1390 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1391 	r = _config_request(ioc, &mpi_request, mpi_reply,
1392 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1393 	if (r)
1394 		goto out;
1395 
1396 	mpi_request.PageAddress = cpu_to_le32(form | handle);
1397 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1398 	r = _config_request(ioc, &mpi_request, mpi_reply,
1399 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
1400 	    sizeof(*config_page));
1401  out:
1402 	return r;
1403 }
1404 
1405 /**
1406  * mpt3sas_config_get_number_pds - obtain number of phys disk assigned to volume
1407  * @ioc: per adapter object
1408  * @handle: volume handle
1409  * @num_pds: returns pds count
1410  * Context: sleep.
1411  *
1412  * Returns 0 for success, non-zero for failure.
1413  */
1414 int
1415 mpt3sas_config_get_number_pds(struct MPT3SAS_ADAPTER *ioc, u16 handle,
1416 	u8 *num_pds)
1417 {
1418 	Mpi2ConfigRequest_t mpi_request;
1419 	Mpi2RaidVolPage0_t config_page;
1420 	Mpi2ConfigReply_t mpi_reply;
1421 	int r;
1422 	u16 ioc_status;
1423 
1424 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1425 	*num_pds = 0;
1426 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1427 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1428 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1429 	mpi_request.Header.PageNumber = 0;
1430 	mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
1431 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1432 	r = _config_request(ioc, &mpi_request, &mpi_reply,
1433 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1434 	if (r)
1435 		goto out;
1436 
1437 	mpi_request.PageAddress =
1438 	    cpu_to_le32(MPI2_RAID_VOLUME_PGAD_FORM_HANDLE | handle);
1439 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1440 	r = _config_request(ioc, &mpi_request, &mpi_reply,
1441 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page,
1442 	    sizeof(Mpi2RaidVolPage0_t));
1443 	if (!r) {
1444 		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1445 		    MPI2_IOCSTATUS_MASK;
1446 		if (ioc_status == MPI2_IOCSTATUS_SUCCESS)
1447 			*num_pds = config_page.NumPhysDisks;
1448 	}
1449 
1450  out:
1451 	return r;
1452 }
1453 
1454 /**
1455  * mpt3sas_config_get_raid_volume_pg0 - obtain raid volume page 0
1456  * @ioc: per adapter object
1457  * @mpi_reply: reply mf payload returned from firmware
1458  * @config_page: contents of the config page
1459  * @form: GET_NEXT_HANDLE or HANDLE
1460  * @handle: volume handle
1461  * @sz: size of buffer passed in config_page
1462  * Context: sleep.
1463  *
1464  * Returns 0 for success, non-zero for failure.
1465  */
1466 int
1467 mpt3sas_config_get_raid_volume_pg0(struct MPT3SAS_ADAPTER *ioc,
1468 	Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form,
1469 	u32 handle, u16 sz)
1470 {
1471 	Mpi2ConfigRequest_t mpi_request;
1472 	int r;
1473 
1474 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1475 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1476 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1477 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1478 	mpi_request.Header.PageNumber = 0;
1479 	mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
1480 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1481 	r = _config_request(ioc, &mpi_request, mpi_reply,
1482 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1483 	if (r)
1484 		goto out;
1485 
1486 	mpi_request.PageAddress = cpu_to_le32(form | handle);
1487 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1488 	r = _config_request(ioc, &mpi_request, mpi_reply,
1489 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
1490  out:
1491 	return r;
1492 }
1493 
1494 /**
1495  * mpt3sas_config_get_phys_disk_pg0 - obtain phys disk page 0
1496  * @ioc: per adapter object
1497  * @mpi_reply: reply mf payload returned from firmware
1498  * @config_page: contents of the config page
1499  * @form: GET_NEXT_PHYSDISKNUM, PHYSDISKNUM, DEVHANDLE
1500  * @form_specific: specific to the form
1501  * Context: sleep.
1502  *
1503  * Returns 0 for success, non-zero for failure.
1504  */
1505 int
1506 mpt3sas_config_get_phys_disk_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
1507 	*mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form,
1508 	u32 form_specific)
1509 {
1510 	Mpi2ConfigRequest_t mpi_request;
1511 	int r;
1512 
1513 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1514 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1515 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1516 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
1517 	mpi_request.Header.PageNumber = 0;
1518 	mpi_request.Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION;
1519 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1520 	r = _config_request(ioc, &mpi_request, mpi_reply,
1521 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1522 	if (r)
1523 		goto out;
1524 
1525 	mpi_request.PageAddress = cpu_to_le32(form | form_specific);
1526 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1527 	r = _config_request(ioc, &mpi_request, mpi_reply,
1528 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
1529 	    sizeof(*config_page));
1530  out:
1531 	return r;
1532 }
1533 
1534 /**
1535  * mpt3sas_config_get_volume_handle - returns volume handle for give hidden
1536  * raid components
1537  * @ioc: per adapter object
1538  * @pd_handle: phys disk handle
1539  * @volume_handle: volume handle
1540  * Context: sleep.
1541  *
1542  * Returns 0 for success, non-zero for failure.
1543  */
1544 int
1545 mpt3sas_config_get_volume_handle(struct MPT3SAS_ADAPTER *ioc, u16 pd_handle,
1546 	u16 *volume_handle)
1547 {
1548 	Mpi2RaidConfigurationPage0_t *config_page = NULL;
1549 	Mpi2ConfigRequest_t mpi_request;
1550 	Mpi2ConfigReply_t mpi_reply;
1551 	int r, i, config_page_sz;
1552 	u16 ioc_status;
1553 	int config_num;
1554 	u16 element_type;
1555 	u16 phys_disk_dev_handle;
1556 
1557 	*volume_handle = 0;
1558 	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
1559 	mpi_request.Function = MPI2_FUNCTION_CONFIG;
1560 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1561 	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
1562 	mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG;
1563 	mpi_request.Header.PageVersion = MPI2_RAIDCONFIG0_PAGEVERSION;
1564 	mpi_request.Header.PageNumber = 0;
1565 	ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
1566 	r = _config_request(ioc, &mpi_request, &mpi_reply,
1567 	    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
1568 	if (r)
1569 		goto out;
1570 
1571 	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1572 	config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4);
1573 	config_page = kmalloc(config_page_sz, GFP_KERNEL);
1574 	if (!config_page) {
1575 		r = -1;
1576 		goto out;
1577 	}
1578 
1579 	config_num = 0xff;
1580 	while (1) {
1581 		mpi_request.PageAddress = cpu_to_le32(config_num +
1582 		    MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM);
1583 		r = _config_request(ioc, &mpi_request, &mpi_reply,
1584 		    MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
1585 		    config_page_sz);
1586 		if (r)
1587 			goto out;
1588 		r = -1;
1589 		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1590 		    MPI2_IOCSTATUS_MASK;
1591 		if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
1592 			goto out;
1593 		for (i = 0; i < config_page->NumElements; i++) {
1594 			element_type = le16_to_cpu(config_page->
1595 			    ConfigElement[i].ElementFlags) &
1596 			    MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE;
1597 			if (element_type ==
1598 			    MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT ||
1599 			    element_type ==
1600 			    MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT) {
1601 				phys_disk_dev_handle =
1602 				    le16_to_cpu(config_page->ConfigElement[i].
1603 				    PhysDiskDevHandle);
1604 				if (phys_disk_dev_handle == pd_handle) {
1605 					*volume_handle =
1606 					    le16_to_cpu(config_page->
1607 					    ConfigElement[i].VolDevHandle);
1608 					r = 0;
1609 					goto out;
1610 				}
1611 			} else if (element_type ==
1612 			    MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT) {
1613 				*volume_handle = 0;
1614 				r = 0;
1615 				goto out;
1616 			}
1617 		}
1618 		config_num = config_page->ConfigNum;
1619 	}
1620  out:
1621 	kfree(config_page);
1622 	return r;
1623 }
1624 
1625 /**
1626  * mpt3sas_config_get_volume_wwid - returns wwid given the volume handle
1627  * @ioc: per adapter object
1628  * @volume_handle: volume handle
1629  * @wwid: volume wwid
1630  * Context: sleep.
1631  *
1632  * Returns 0 for success, non-zero for failure.
1633  */
1634 int
1635 mpt3sas_config_get_volume_wwid(struct MPT3SAS_ADAPTER *ioc, u16 volume_handle,
1636 	u64 *wwid)
1637 {
1638 	Mpi2ConfigReply_t mpi_reply;
1639 	Mpi2RaidVolPage1_t raid_vol_pg1;
1640 
1641 	*wwid = 0;
1642 	if (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
1643 	    &raid_vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE,
1644 	    volume_handle))) {
1645 		*wwid = le64_to_cpu(raid_vol_pg1.WWID);
1646 		return 0;
1647 	} else
1648 		return -1;
1649 }
1650