xref: /freebsd/sys/dev/mpt/mpt_raid.c (revision c87e3f833c6b6efcebeeb51abc182c9f3e556071)
1b0a2fdeeSScott Long /*-
2b0a2fdeeSScott Long  * Routines for handling the integrated RAID features LSI MPT Fusion adapters.
3b0a2fdeeSScott Long  *
4b0a2fdeeSScott Long  * Copyright (c) 2005, WHEEL Sp. z o.o.
5b0a2fdeeSScott Long  * Copyright (c) 2005 Justin T. Gibbs.
6b0a2fdeeSScott Long  * All rights reserved.
7b0a2fdeeSScott Long  *
8b0a2fdeeSScott Long  * Redistribution and use in source and binary forms, with or without
9b0a2fdeeSScott Long  * modification, are permitted provided that the following conditions are
10b0a2fdeeSScott Long  * met:
11b0a2fdeeSScott Long  * 1. Redistributions of source code must retain the above copyright
12b0a2fdeeSScott Long  *    notice, this list of conditions and the following disclaimer.
13b0a2fdeeSScott Long  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14b0a2fdeeSScott Long  *    substantially similar to the "NO WARRANTY" disclaimer below
15b0a2fdeeSScott Long  *    ("Disclaimer") and any redistribution must be conditioned upon including
16b0a2fdeeSScott Long  *    a substantially similar Disclaimer requirement for further binary
17b0a2fdeeSScott Long  *    redistribution.
18286e947fSJustin T. Gibbs  * 3. Neither the names of the above listed copyright holders nor the names
19286e947fSJustin T. Gibbs  *    of any contributors may be used to endorse or promote products derived
20286e947fSJustin T. Gibbs  *    from this software without specific prior written permission.
21b0a2fdeeSScott Long  *
22b0a2fdeeSScott Long  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23b0a2fdeeSScott Long  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24b0a2fdeeSScott Long  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25b0a2fdeeSScott Long  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26b0a2fdeeSScott Long  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27b0a2fdeeSScott Long  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28b0a2fdeeSScott Long  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29b0a2fdeeSScott Long  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30b0a2fdeeSScott Long  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31b0a2fdeeSScott Long  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT
32b0a2fdeeSScott Long  * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33b0a2fdeeSScott Long  */
34b0a2fdeeSScott Long 
35b0a2fdeeSScott Long #include <sys/cdefs.h>
36b0a2fdeeSScott Long __FBSDID("$FreeBSD$");
37b0a2fdeeSScott Long 
38b0a2fdeeSScott Long #include <dev/mpt/mpt.h>
39b0a2fdeeSScott Long #include <dev/mpt/mpt_raid.h>
40b0a2fdeeSScott Long 
41b0a2fdeeSScott Long #include "dev/mpt/mpilib/mpi_ioc.h" /* XXX Fix Event Handling!!! */
42b0a2fdeeSScott Long #include "dev/mpt/mpilib/mpi_raid.h"
43b0a2fdeeSScott Long 
44b0a2fdeeSScott Long #include <cam/cam.h>
45b0a2fdeeSScott Long #include <cam/cam_ccb.h>
46b0a2fdeeSScott Long #include <cam/cam_sim.h>
47b0a2fdeeSScott Long #include <cam/cam_xpt_sim.h>
48b0a2fdeeSScott Long 
49c87e3f83SMatt Jacob #if __FreeBSD_version < 500000
50c87e3f83SMatt Jacob #include <sys/devicestat.h>
51c87e3f83SMatt Jacob #define	GIANT_REQUIRED
52c87e3f83SMatt Jacob #endif
53b0a2fdeeSScott Long #include <cam/cam_periph.h>
54b0a2fdeeSScott Long 
55b0a2fdeeSScott Long #include <sys/callout.h>
56b0a2fdeeSScott Long #include <sys/kthread.h>
57b0a2fdeeSScott Long #include <sys/sysctl.h>
58b0a2fdeeSScott Long 
59b0a2fdeeSScott Long #include <machine/stdarg.h>
60b0a2fdeeSScott Long 
61b0a2fdeeSScott Long struct mpt_raid_action_result
62b0a2fdeeSScott Long {
63b0a2fdeeSScott Long 	union {
64b0a2fdeeSScott Long 		MPI_RAID_VOL_INDICATOR	indicator_struct;
65b0a2fdeeSScott Long 		uint32_t		new_settings;
66b0a2fdeeSScott Long 		uint8_t			phys_disk_num;
67b0a2fdeeSScott Long 	} action_data;
68b0a2fdeeSScott Long 	uint16_t			action_status;
69b0a2fdeeSScott Long };
70b0a2fdeeSScott Long 
71b0a2fdeeSScott Long #define REQ_TO_RAID_ACTION_RESULT(req) ((struct mpt_raid_action_result *) \
72b0a2fdeeSScott Long 	(((MSG_RAID_ACTION_REQUEST *)(req->req_vbuf)) + 1))
73b0a2fdeeSScott Long 
74b0a2fdeeSScott Long #define REQ_IOCSTATUS(req) ((req)->IOCStatus & MPI_IOCSTATUS_MASK)
75b0a2fdeeSScott Long 
76b0a2fdeeSScott Long 
77b0a2fdeeSScott Long static mpt_probe_handler_t	mpt_raid_probe;
78b0a2fdeeSScott Long static mpt_attach_handler_t	mpt_raid_attach;
79b0a2fdeeSScott Long static mpt_event_handler_t	mpt_raid_event;
80b0a2fdeeSScott Long static mpt_shutdown_handler_t	mpt_raid_shutdown;
81b0a2fdeeSScott Long static mpt_reset_handler_t	mpt_raid_ioc_reset;
82b0a2fdeeSScott Long static mpt_detach_handler_t	mpt_raid_detach;
83b0a2fdeeSScott Long 
84b0a2fdeeSScott Long static struct mpt_personality mpt_raid_personality =
85b0a2fdeeSScott Long {
86b0a2fdeeSScott Long 	.name		= "mpt_raid",
87b0a2fdeeSScott Long 	.probe		= mpt_raid_probe,
88b0a2fdeeSScott Long 	.attach		= mpt_raid_attach,
89b0a2fdeeSScott Long 	.event		= mpt_raid_event,
90b0a2fdeeSScott Long 	.reset		= mpt_raid_ioc_reset,
91b0a2fdeeSScott Long 	.shutdown	= mpt_raid_shutdown,
92b0a2fdeeSScott Long 	.detach		= mpt_raid_detach,
93b0a2fdeeSScott Long };
94b0a2fdeeSScott Long 
95b0a2fdeeSScott Long DECLARE_MPT_PERSONALITY(mpt_raid, SI_ORDER_THIRD);
96b0a2fdeeSScott Long MPT_PERSONALITY_DEPEND(mpt_raid, mpt_cam, 1, 1, 1);
97b0a2fdeeSScott Long 
98b0a2fdeeSScott Long static mpt_reply_handler_t mpt_raid_reply_handler;
99b0a2fdeeSScott Long static int mpt_raid_reply_frame_handler(struct mpt_softc *mpt, request_t *req,
100b0a2fdeeSScott Long 					MSG_DEFAULT_REPLY *reply_frame);
101b0a2fdeeSScott Long static int mpt_spawn_raid_thread(struct mpt_softc *mpt);
102b0a2fdeeSScott Long static void mpt_terminate_raid_thread(struct mpt_softc *mpt);
103b0a2fdeeSScott Long static void mpt_raid_thread(void *arg);
104b0a2fdeeSScott Long static timeout_t mpt_raid_timer;
105b0a2fdeeSScott Long static timeout_t mpt_raid_quiesce_timeout;
106f4e98881SRuslan Ermilov #if 0
107b0a2fdeeSScott Long static void mpt_enable_vol(struct mpt_softc *mpt,
108b0a2fdeeSScott Long 			   struct mpt_raid_volume *mpt_vol, int enable);
109b0a2fdeeSScott Long #endif
110b0a2fdeeSScott Long static void mpt_verify_mwce(struct mpt_softc *mpt,
111b0a2fdeeSScott Long 			    struct mpt_raid_volume *mpt_vol);
112b0a2fdeeSScott Long static void mpt_adjust_queue_depth(struct mpt_softc *mpt,
113b0a2fdeeSScott Long 				   struct mpt_raid_volume *mpt_vol,
114b0a2fdeeSScott Long 				   struct cam_path *path);
115b0a2fdeeSScott Long static void mpt_raid_sysctl_attach(struct mpt_softc *mpt);
116b0a2fdeeSScott Long 
117b0a2fdeeSScott Long static uint32_t raid_handler_id = MPT_HANDLER_ID_NONE;
118b0a2fdeeSScott Long 
119b0a2fdeeSScott Long const char *
120b0a2fdeeSScott Long mpt_vol_type(struct mpt_raid_volume *vol)
121b0a2fdeeSScott Long {
122b0a2fdeeSScott Long 	switch (vol->config_page->VolumeType) {
123b0a2fdeeSScott Long 	case MPI_RAID_VOL_TYPE_IS:
124b0a2fdeeSScott Long 		return ("RAID-0");
125b0a2fdeeSScott Long 	case MPI_RAID_VOL_TYPE_IME:
126b0a2fdeeSScott Long 		return ("RAID-1E");
127b0a2fdeeSScott Long 	case MPI_RAID_VOL_TYPE_IM:
128b0a2fdeeSScott Long 		return ("RAID-1");
129b0a2fdeeSScott Long 	default:
130b0a2fdeeSScott Long 		return ("Unknown");
131b0a2fdeeSScott Long 	}
132b0a2fdeeSScott Long }
133b0a2fdeeSScott Long 
134b0a2fdeeSScott Long const char *
135b0a2fdeeSScott Long mpt_vol_state(struct mpt_raid_volume *vol)
136b0a2fdeeSScott Long {
137b0a2fdeeSScott Long 	switch (vol->config_page->VolumeStatus.State) {
138b0a2fdeeSScott Long 	case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
139b0a2fdeeSScott Long 		return ("Optimal");
140b0a2fdeeSScott Long 	case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
141b0a2fdeeSScott Long 		return ("Degraded");
142b0a2fdeeSScott Long 	case MPI_RAIDVOL0_STATUS_STATE_FAILED:
143b0a2fdeeSScott Long 		return ("Failed");
144b0a2fdeeSScott Long 	default:
145b0a2fdeeSScott Long 		return ("Unknown");
146b0a2fdeeSScott Long 	}
147b0a2fdeeSScott Long }
148b0a2fdeeSScott Long 
149b0a2fdeeSScott Long const char *
150b0a2fdeeSScott Long mpt_disk_state(struct mpt_raid_disk *disk)
151b0a2fdeeSScott Long {
152b0a2fdeeSScott Long 	switch (disk->config_page.PhysDiskStatus.State) {
153b0a2fdeeSScott Long 	case MPI_PHYSDISK0_STATUS_ONLINE:
154b0a2fdeeSScott Long 		return ("Online");
155b0a2fdeeSScott Long 	case MPI_PHYSDISK0_STATUS_MISSING:
156b0a2fdeeSScott Long 		return ("Missing");
157b0a2fdeeSScott Long 	case MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE:
158b0a2fdeeSScott Long 		return ("Incompatible");
159b0a2fdeeSScott Long 	case MPI_PHYSDISK0_STATUS_FAILED:
160b0a2fdeeSScott Long 		return ("Failed");
161b0a2fdeeSScott Long 	case MPI_PHYSDISK0_STATUS_INITIALIZING:
162b0a2fdeeSScott Long 		return ("Initializing");
163b0a2fdeeSScott Long 	case MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED:
164b0a2fdeeSScott Long 		return ("Offline Requested");
165b0a2fdeeSScott Long 	case MPI_PHYSDISK0_STATUS_FAILED_REQUESTED:
166b0a2fdeeSScott Long 		return ("Failed per Host Request");
167b0a2fdeeSScott Long 	case MPI_PHYSDISK0_STATUS_OTHER_OFFLINE:
168b0a2fdeeSScott Long 		return ("Offline");
169b0a2fdeeSScott Long 	default:
170b0a2fdeeSScott Long 		return ("Unknown");
171b0a2fdeeSScott Long 	}
172b0a2fdeeSScott Long }
173b0a2fdeeSScott Long 
174b0a2fdeeSScott Long void
175b0a2fdeeSScott Long mpt_vol_prt(struct mpt_softc *mpt, struct mpt_raid_volume *vol,
176b0a2fdeeSScott Long 	    const char *fmt, ...)
177b0a2fdeeSScott Long {
178b0a2fdeeSScott Long 	va_list ap;
179b0a2fdeeSScott Long 
180b0a2fdeeSScott Long 	printf("%s:vol%d(%s:%d:%d): ", device_get_nameunit(mpt->dev),
181b0a2fdeeSScott Long 	       (u_int)(vol - mpt->raid_volumes), device_get_nameunit(mpt->dev),
182b0a2fdeeSScott Long 	       vol->config_page->VolumeBus, vol->config_page->VolumeID);
183b0a2fdeeSScott Long 	va_start(ap, fmt);
184b0a2fdeeSScott Long 	vprintf(fmt, ap);
185b0a2fdeeSScott Long 	va_end(ap);
186b0a2fdeeSScott Long }
187b0a2fdeeSScott Long 
188b0a2fdeeSScott Long void
189b0a2fdeeSScott Long mpt_disk_prt(struct mpt_softc *mpt, struct mpt_raid_disk *disk,
190b0a2fdeeSScott Long 	     const char *fmt, ...)
191b0a2fdeeSScott Long {
192b0a2fdeeSScott Long 	va_list ap;
193b0a2fdeeSScott Long 
194b0a2fdeeSScott Long 	if (disk->volume != NULL) {
195b0a2fdeeSScott Long 		printf("(%s:vol%d:%d): ",
196b0a2fdeeSScott Long 		       device_get_nameunit(mpt->dev),
197b0a2fdeeSScott Long 		       disk->volume->config_page->VolumeID,
198b0a2fdeeSScott Long 		       disk->member_number);
199b0a2fdeeSScott Long 	} else {
200b0a2fdeeSScott Long 		printf("(%s:%d:%d): ", device_get_nameunit(mpt->dev),
201b0a2fdeeSScott Long 		       disk->config_page.PhysDiskBus,
202b0a2fdeeSScott Long 		       disk->config_page.PhysDiskID);
203b0a2fdeeSScott Long 	}
204b0a2fdeeSScott Long 	va_start(ap, fmt);
205b0a2fdeeSScott Long 	vprintf(fmt, ap);
206b0a2fdeeSScott Long 	va_end(ap);
207b0a2fdeeSScott Long }
208b0a2fdeeSScott Long 
209b0a2fdeeSScott Long static void
210b0a2fdeeSScott Long mpt_raid_async(void *callback_arg, u_int32_t code,
211b0a2fdeeSScott Long 	       struct cam_path *path, void *arg)
212b0a2fdeeSScott Long {
213b0a2fdeeSScott Long 	struct mpt_softc *mpt;
214b0a2fdeeSScott Long 
215b0a2fdeeSScott Long 	mpt = (struct mpt_softc*)callback_arg;
216b0a2fdeeSScott Long 	switch (code) {
217b0a2fdeeSScott Long 	case AC_FOUND_DEVICE:
218b0a2fdeeSScott Long 	{
219b0a2fdeeSScott Long 		struct ccb_getdev *cgd;
220b0a2fdeeSScott Long 		struct mpt_raid_volume *mpt_vol;
221b0a2fdeeSScott Long 
222b0a2fdeeSScott Long 		cgd = (struct ccb_getdev *)arg;
223b0a2fdeeSScott Long 		if (cgd == NULL)
224b0a2fdeeSScott Long 			break;
225b0a2fdeeSScott Long 
226b0a2fdeeSScott Long 		mpt_lprt(mpt, MPT_PRT_DEBUG, " Callback for %d\n",
227b0a2fdeeSScott Long 			 cgd->ccb_h.target_id);
228b0a2fdeeSScott Long 
229b0a2fdeeSScott Long 		RAID_VOL_FOREACH(mpt, mpt_vol) {
230b0a2fdeeSScott Long 			if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0)
231b0a2fdeeSScott Long 				continue;
232b0a2fdeeSScott Long 
233b0a2fdeeSScott Long 			if (mpt_vol->config_page->VolumeID
234b0a2fdeeSScott Long 			 == cgd->ccb_h.target_id) {
235b0a2fdeeSScott Long 				mpt_adjust_queue_depth(mpt, mpt_vol, path);
236b0a2fdeeSScott Long 				break;
237b0a2fdeeSScott Long 			}
238b0a2fdeeSScott Long 		}
239b0a2fdeeSScott Long 	}
240b0a2fdeeSScott Long 	default:
241b0a2fdeeSScott Long 		break;
242b0a2fdeeSScott Long 	}
243b0a2fdeeSScott Long }
244b0a2fdeeSScott Long 
245b0a2fdeeSScott Long int
246b0a2fdeeSScott Long mpt_raid_probe(struct mpt_softc *mpt)
247b0a2fdeeSScott Long {
248c87e3f83SMatt Jacob 	if (mpt->ioc_page2 == NULL || mpt->ioc_page2->MaxPhysDisks == 0) {
249b0a2fdeeSScott Long 		return (ENODEV);
250c87e3f83SMatt Jacob 	}
251b0a2fdeeSScott Long 	return (0);
252b0a2fdeeSScott Long }
253b0a2fdeeSScott Long 
254b0a2fdeeSScott Long int
255b0a2fdeeSScott Long mpt_raid_attach(struct mpt_softc *mpt)
256b0a2fdeeSScott Long {
257b0a2fdeeSScott Long 	struct ccb_setasync csa;
258b0a2fdeeSScott Long 	mpt_handler_t	 handler;
259b0a2fdeeSScott Long 	int		 error;
260b0a2fdeeSScott Long 
261b0a2fdeeSScott Long 	mpt_callout_init(&mpt->raid_timer);
262b0a2fdeeSScott Long 
263b0a2fdeeSScott Long 	handler.reply_handler = mpt_raid_reply_handler;
264b0a2fdeeSScott Long 	error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler,
265b0a2fdeeSScott Long 				     &raid_handler_id);
266b0a2fdeeSScott Long 	if (error != 0)
267b0a2fdeeSScott Long 		goto cleanup;
268b0a2fdeeSScott Long 
269b0a2fdeeSScott Long 	error = mpt_spawn_raid_thread(mpt);
270b0a2fdeeSScott Long 	if (error != 0) {
271b0a2fdeeSScott Long 		mpt_prt(mpt, "Unable to spawn RAID thread!\n");
272b0a2fdeeSScott Long 		goto cleanup;
273b0a2fdeeSScott Long 	}
274b0a2fdeeSScott Long 
275b0a2fdeeSScott Long 	xpt_setup_ccb(&csa.ccb_h, mpt->path, /*priority*/5);
276b0a2fdeeSScott Long 	csa.ccb_h.func_code = XPT_SASYNC_CB;
277b0a2fdeeSScott Long 	csa.event_enable = AC_FOUND_DEVICE;
278b0a2fdeeSScott Long 	csa.callback = mpt_raid_async;
279b0a2fdeeSScott Long 	csa.callback_arg = mpt;
280b0a2fdeeSScott Long 	xpt_action((union ccb *)&csa);
281b0a2fdeeSScott Long 	if (csa.ccb_h.status != CAM_REQ_CMP) {
282b0a2fdeeSScott Long 		mpt_prt(mpt, "mpt_raid_attach: Unable to register "
283b0a2fdeeSScott Long 			"CAM async handler.\n");
284b0a2fdeeSScott Long 	}
285b0a2fdeeSScott Long 
286b0a2fdeeSScott Long 	mpt_raid_sysctl_attach(mpt);
287b0a2fdeeSScott Long 	return (0);
288b0a2fdeeSScott Long cleanup:
289b0a2fdeeSScott Long 	mpt_raid_detach(mpt);
290b0a2fdeeSScott Long 	return (error);
291b0a2fdeeSScott Long }
292b0a2fdeeSScott Long 
293b0a2fdeeSScott Long void
294b0a2fdeeSScott Long mpt_raid_detach(struct mpt_softc *mpt)
295b0a2fdeeSScott Long {
296b0a2fdeeSScott Long 	struct ccb_setasync csa;
297b0a2fdeeSScott Long 	mpt_handler_t handler;
298b0a2fdeeSScott Long 
299b0a2fdeeSScott Long 	callout_stop(&mpt->raid_timer);
300b0a2fdeeSScott Long 	mpt_terminate_raid_thread(mpt);
301b0a2fdeeSScott Long 
302b0a2fdeeSScott Long 	handler.reply_handler = mpt_raid_reply_handler;
303b0a2fdeeSScott Long 	mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
304b0a2fdeeSScott Long 			       raid_handler_id);
305b0a2fdeeSScott Long 	xpt_setup_ccb(&csa.ccb_h, mpt->path, /*priority*/5);
306b0a2fdeeSScott Long 	csa.ccb_h.func_code = XPT_SASYNC_CB;
307b0a2fdeeSScott Long 	csa.event_enable = 0;
308b0a2fdeeSScott Long 	csa.callback = mpt_raid_async;
309b0a2fdeeSScott Long 	csa.callback_arg = mpt;
310b0a2fdeeSScott Long 	xpt_action((union ccb *)&csa);
311b0a2fdeeSScott Long }
312b0a2fdeeSScott Long 
313b0a2fdeeSScott Long static void
314b0a2fdeeSScott Long mpt_raid_ioc_reset(struct mpt_softc *mpt, int type)
315b0a2fdeeSScott Long {
316b0a2fdeeSScott Long 	/* Nothing to do yet. */
317b0a2fdeeSScott Long }
318b0a2fdeeSScott Long 
319b0a2fdeeSScott Long static const char *raid_event_txt[] =
320b0a2fdeeSScott Long {
321b0a2fdeeSScott Long 	"Volume Created",
322b0a2fdeeSScott Long 	"Volume Deleted",
323b0a2fdeeSScott Long 	"Volume Settings Changed",
324b0a2fdeeSScott Long 	"Volume Status Changed",
325b0a2fdeeSScott Long 	"Volume Physical Disk Membership Changed",
326b0a2fdeeSScott Long 	"Physical Disk Created",
327b0a2fdeeSScott Long 	"Physical Disk Deleted",
328b0a2fdeeSScott Long 	"Physical Disk Settings Changed",
329b0a2fdeeSScott Long 	"Physical Disk Status Changed",
330b0a2fdeeSScott Long 	"Domain Validation Required",
331b0a2fdeeSScott Long 	"SMART Data Received",
332b0a2fdeeSScott Long 	"Replace Action Started",
333b0a2fdeeSScott Long };
334b0a2fdeeSScott Long 
335b0a2fdeeSScott Long static int
336b0a2fdeeSScott Long mpt_raid_event(struct mpt_softc *mpt, request_t *req,
337b0a2fdeeSScott Long 	       MSG_EVENT_NOTIFY_REPLY *msg)
338b0a2fdeeSScott Long {
339b0a2fdeeSScott Long 	EVENT_DATA_RAID *raid_event;
340b0a2fdeeSScott Long 	struct mpt_raid_volume *mpt_vol;
341b0a2fdeeSScott Long 	struct mpt_raid_disk *mpt_disk;
342b0a2fdeeSScott Long 	CONFIG_PAGE_RAID_VOL_0 *vol_pg;
343b0a2fdeeSScott Long 	int i;
344b0a2fdeeSScott Long 	int print_event;
345b0a2fdeeSScott Long 
346b0a2fdeeSScott Long 	if (msg->Event != MPI_EVENT_INTEGRATED_RAID)
347b0a2fdeeSScott Long 		return (/*handled*/0);
348b0a2fdeeSScott Long 
349b0a2fdeeSScott Long 	raid_event = (EVENT_DATA_RAID *)&msg->Data;
350b0a2fdeeSScott Long 
351b0a2fdeeSScott Long 	mpt_vol = NULL;
352b0a2fdeeSScott Long 	vol_pg = NULL;
353b0a2fdeeSScott Long 	if (mpt->raid_volumes != NULL && mpt->ioc_page2 != NULL) {
354b0a2fdeeSScott Long 		for (i = 0; i < mpt->ioc_page2->MaxVolumes; i++) {
355b0a2fdeeSScott Long 			mpt_vol = &mpt->raid_volumes[i];
356b0a2fdeeSScott Long 			vol_pg = mpt_vol->config_page;
357b0a2fdeeSScott Long 
358b0a2fdeeSScott Long 			if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0)
359b0a2fdeeSScott Long 				continue;
360b0a2fdeeSScott Long 
361b0a2fdeeSScott Long 			if (vol_pg->VolumeID == raid_event->VolumeID
362b0a2fdeeSScott Long 			 && vol_pg->VolumeBus == raid_event->VolumeBus)
363b0a2fdeeSScott Long 				break;
364b0a2fdeeSScott Long 		}
365b0a2fdeeSScott Long 		if (i >= mpt->ioc_page2->MaxVolumes) {
366b0a2fdeeSScott Long 			mpt_vol = NULL;
367b0a2fdeeSScott Long 			vol_pg = NULL;
368b0a2fdeeSScott Long 		}
369b0a2fdeeSScott Long 	}
370b0a2fdeeSScott Long 
371b0a2fdeeSScott Long 	mpt_disk = NULL;
372b0a2fdeeSScott Long 	if (raid_event->PhysDiskNum != 0xFF
373b0a2fdeeSScott Long 	 && mpt->raid_disks != NULL) {
374b0a2fdeeSScott Long 		mpt_disk = mpt->raid_disks
375b0a2fdeeSScott Long 			 + raid_event->PhysDiskNum;
376b0a2fdeeSScott Long 		if ((mpt_disk->flags & MPT_RDF_ACTIVE) == 0)
377b0a2fdeeSScott Long 			mpt_disk = NULL;
378b0a2fdeeSScott Long 	}
379b0a2fdeeSScott Long 
380b0a2fdeeSScott Long 	print_event = 1;
381b0a2fdeeSScott Long 	switch(raid_event->ReasonCode) {
382b0a2fdeeSScott Long 	case MPI_EVENT_RAID_RC_VOLUME_CREATED:
383b0a2fdeeSScott Long 	case MPI_EVENT_RAID_RC_VOLUME_DELETED:
384b0a2fdeeSScott Long 		break;
385b0a2fdeeSScott Long 	case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
386b0a2fdeeSScott Long 		if (mpt_vol != NULL) {
387b0a2fdeeSScott Long 			if ((mpt_vol->flags & MPT_RVF_UP2DATE) != 0) {
388b0a2fdeeSScott Long 				mpt_vol->flags &= ~MPT_RVF_UP2DATE;
389b0a2fdeeSScott Long 			} else {
390b0a2fdeeSScott Long 				/*
391b0a2fdeeSScott Long 				 * Coalesce status messages into one
392b0a2fdeeSScott Long 				 * per background run of our RAID thread.
393b0a2fdeeSScott Long 				 * This removes "spurious" status messages
394b0a2fdeeSScott Long 				 * from our output.
395b0a2fdeeSScott Long 				 */
396b0a2fdeeSScott Long 				print_event = 0;
397b0a2fdeeSScott Long 			}
398b0a2fdeeSScott Long 		}
399b0a2fdeeSScott Long 		break;
400b0a2fdeeSScott Long 	case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
401b0a2fdeeSScott Long 	case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
402b0a2fdeeSScott Long 		mpt->raid_rescan++;
403b0a2fdeeSScott Long 		if (mpt_vol != NULL)
404b0a2fdeeSScott Long 			mpt_vol->flags &= ~(MPT_RVF_UP2DATE|MPT_RVF_ANNOUNCED);
405b0a2fdeeSScott Long 		break;
406b0a2fdeeSScott Long 	case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
407b0a2fdeeSScott Long 	case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
408b0a2fdeeSScott Long 		mpt->raid_rescan++;
409b0a2fdeeSScott Long 		break;
410b0a2fdeeSScott Long 	case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
411b0a2fdeeSScott Long 	case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
412b0a2fdeeSScott Long 		mpt->raid_rescan++;
413b0a2fdeeSScott Long 		if (mpt_disk != NULL)
414b0a2fdeeSScott Long 			mpt_disk->flags &= ~MPT_RDF_UP2DATE;
415b0a2fdeeSScott Long 		break;
416b0a2fdeeSScott Long 	case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
417b0a2fdeeSScott Long 		mpt->raid_rescan++;
418b0a2fdeeSScott Long 		break;
419b0a2fdeeSScott Long 	case MPI_EVENT_RAID_RC_SMART_DATA:
420b0a2fdeeSScott Long 	case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
421b0a2fdeeSScott Long 		break;
422b0a2fdeeSScott Long 	}
423b0a2fdeeSScott Long 
424b0a2fdeeSScott Long 	if (print_event) {
425b0a2fdeeSScott Long 		if (mpt_disk != NULL) {
426b0a2fdeeSScott Long 			mpt_disk_prt(mpt, mpt_disk, "");
427b0a2fdeeSScott Long 		} else if (mpt_vol != NULL) {
428b0a2fdeeSScott Long 			mpt_vol_prt(mpt, mpt_vol, "");
429b0a2fdeeSScott Long 		} else {
430b0a2fdeeSScott Long 			mpt_prt(mpt, "Volume(%d:%d", raid_event->VolumeBus,
431b0a2fdeeSScott Long 				raid_event->VolumeID);
432b0a2fdeeSScott Long 
433b0a2fdeeSScott Long 			if (raid_event->PhysDiskNum != 0xFF)
434b0a2fdeeSScott Long 				mpt_prtc(mpt, ":%d): ",
435b0a2fdeeSScott Long 					 raid_event->PhysDiskNum);
436b0a2fdeeSScott Long 			else
437b0a2fdeeSScott Long 				mpt_prtc(mpt, "): ");
438b0a2fdeeSScott Long 		}
439b0a2fdeeSScott Long 
440b0a2fdeeSScott Long 		if (raid_event->ReasonCode >= NUM_ELEMENTS(raid_event_txt))
441b0a2fdeeSScott Long 			mpt_prtc(mpt, "Unhandled RaidEvent %#x\n",
442b0a2fdeeSScott Long 				 raid_event->ReasonCode);
443b0a2fdeeSScott Long 		else
444b0a2fdeeSScott Long 			mpt_prtc(mpt, "%s\n",
445b0a2fdeeSScott Long 				 raid_event_txt[raid_event->ReasonCode]);
446b0a2fdeeSScott Long 	}
447b0a2fdeeSScott Long 
448b0a2fdeeSScott Long 	if (raid_event->ReasonCode == MPI_EVENT_RAID_RC_SMART_DATA) {
449b0a2fdeeSScott Long 		/* XXX Use CAM's print sense for this... */
450b0a2fdeeSScott Long 		if (mpt_disk != NULL)
451b0a2fdeeSScott Long 			mpt_disk_prt(mpt, mpt_disk, "");
452b0a2fdeeSScott Long 		else
453c87e3f83SMatt Jacob 			mpt_prt(mpt, "Volume(%d:%d:%d: ",
454c87e3f83SMatt Jacob 			    raid_event->VolumeBus, raid_event->VolumeID,
455c87e3f83SMatt Jacob 			    raid_event->PhysDiskNum);
456c87e3f83SMatt Jacob 		mpt_prtc(mpt, "ASC 0x%x, ASCQ 0x%x)\n",
457b0a2fdeeSScott Long 			 raid_event->ASC, raid_event->ASCQ);
458b0a2fdeeSScott Long 	}
459b0a2fdeeSScott Long 
460b0a2fdeeSScott Long 	mpt_raid_wakeup(mpt);
461b0a2fdeeSScott Long 	return (/*handled*/1);
462b0a2fdeeSScott Long }
463b0a2fdeeSScott Long 
464b0a2fdeeSScott Long static void
465b0a2fdeeSScott Long mpt_raid_shutdown(struct mpt_softc *mpt)
466b0a2fdeeSScott Long {
467b0a2fdeeSScott Long 	struct mpt_raid_volume *mpt_vol;
468b0a2fdeeSScott Long 
469c87e3f83SMatt Jacob 	if (mpt->raid_mwce_setting != MPT_RAID_MWCE_REBUILD_ONLY) {
470b0a2fdeeSScott Long 		return;
471c87e3f83SMatt Jacob 	}
472b0a2fdeeSScott Long 
473b0a2fdeeSScott Long 	mpt->raid_mwce_setting = MPT_RAID_MWCE_OFF;
474b0a2fdeeSScott Long 	RAID_VOL_FOREACH(mpt, mpt_vol) {
475b0a2fdeeSScott Long 		mpt_verify_mwce(mpt, mpt_vol);
476b0a2fdeeSScott Long 	}
477b0a2fdeeSScott Long }
478b0a2fdeeSScott Long 
479b0a2fdeeSScott Long static int
480b0a2fdeeSScott Long mpt_raid_reply_handler(struct mpt_softc *mpt, request_t *req,
481c87e3f83SMatt Jacob     uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame)
482b0a2fdeeSScott Long {
483b0a2fdeeSScott Long 	int free_req;
484b0a2fdeeSScott Long 
485b0a2fdeeSScott Long 	if (req == NULL)
486b0a2fdeeSScott Long 		return (/*free_reply*/TRUE);
487b0a2fdeeSScott Long 
488b0a2fdeeSScott Long 	free_req = TRUE;
489b0a2fdeeSScott Long 	if (reply_frame != NULL)
490b0a2fdeeSScott Long 		free_req = mpt_raid_reply_frame_handler(mpt, req, reply_frame);
491f4e98881SRuslan Ermilov #ifdef NOTYET
492b0a2fdeeSScott Long 	else if (req->ccb != NULL) {
493b0a2fdeeSScott Long 		/* Complete Quiesce CCB with error... */
494b0a2fdeeSScott Long 	}
495b0a2fdeeSScott Long #endif
496b0a2fdeeSScott Long 
497b0a2fdeeSScott Long 	req->state &= ~REQ_STATE_QUEUED;
498b0a2fdeeSScott Long 	req->state |= REQ_STATE_DONE;
499b0a2fdeeSScott Long 	TAILQ_REMOVE(&mpt->request_pending_list, req, links);
500b0a2fdeeSScott Long 
501b0a2fdeeSScott Long 	if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) {
502b0a2fdeeSScott Long 		wakeup(req);
503b0a2fdeeSScott Long 	} else if (free_req) {
504b0a2fdeeSScott Long 		mpt_free_request(mpt, req);
505b0a2fdeeSScott Long 	}
506b0a2fdeeSScott Long 
507b0a2fdeeSScott Long 	return (/*free_reply*/TRUE);
508b0a2fdeeSScott Long }
509b0a2fdeeSScott Long 
510b0a2fdeeSScott Long /*
511b0a2fdeeSScott Long  * Parse additional completion information in the reply
512b0a2fdeeSScott Long  * frame for RAID I/O requests.
513b0a2fdeeSScott Long  */
514b0a2fdeeSScott Long static int
515b0a2fdeeSScott Long mpt_raid_reply_frame_handler(struct mpt_softc *mpt, request_t *req,
516b0a2fdeeSScott Long 			     MSG_DEFAULT_REPLY *reply_frame)
517b0a2fdeeSScott Long {
518b0a2fdeeSScott Long 	MSG_RAID_ACTION_REPLY *reply;
519b0a2fdeeSScott Long 	struct mpt_raid_action_result *action_result;
520b0a2fdeeSScott Long 	MSG_RAID_ACTION_REQUEST *rap;
521b0a2fdeeSScott Long 
522b0a2fdeeSScott Long 	reply = (MSG_RAID_ACTION_REPLY *)reply_frame;
523b0a2fdeeSScott Long 	req->IOCStatus = le16toh(reply->IOCStatus);
524b0a2fdeeSScott Long 	rap = (MSG_RAID_ACTION_REQUEST *)req->req_vbuf;
525b0a2fdeeSScott Long 
526b0a2fdeeSScott Long 	switch (rap->Action) {
527b0a2fdeeSScott Long 	case MPI_RAID_ACTION_QUIESCE_PHYS_IO:
528b0a2fdeeSScott Long 		/*
529b0a2fdeeSScott Long 		 * Parse result, call mpt_start with ccb,
530b0a2fdeeSScott Long 		 * release device queue.
531b0a2fdeeSScott Long 		 * COWWWWW
532b0a2fdeeSScott Long 		 */
533b0a2fdeeSScott Long 		break;
534b0a2fdeeSScott Long 	case MPI_RAID_ACTION_ENABLE_PHYS_IO:
535b0a2fdeeSScott Long 		/*
536b0a2fdeeSScott Long 		 * Need additional state for transition to enabled to
537b0a2fdeeSScott Long 		 * protect against attempts to disable??
538b0a2fdeeSScott Long 		 */
539b0a2fdeeSScott Long 		break;
540b0a2fdeeSScott Long 	default:
541b0a2fdeeSScott Long 		action_result = REQ_TO_RAID_ACTION_RESULT(req);
542b0a2fdeeSScott Long 		memcpy(&action_result->action_data, &reply->ActionData,
543b0a2fdeeSScott Long 		       sizeof(action_result->action_data));
544b0a2fdeeSScott Long 		action_result->action_status = reply->ActionStatus;
545b0a2fdeeSScott Long 		break;
546b0a2fdeeSScott Long 	}
547b0a2fdeeSScott Long 
548b0a2fdeeSScott Long 	return (/*Free Request*/TRUE);
549b0a2fdeeSScott Long }
550b0a2fdeeSScott Long 
551b0a2fdeeSScott Long /*
552b0a2fdeeSScott Long  * Utiltity routine to perform a RAID action command;
553b0a2fdeeSScott Long  */
554b0a2fdeeSScott Long int
555b0a2fdeeSScott Long mpt_issue_raid_req(struct mpt_softc *mpt, struct mpt_raid_volume *vol,
556b0a2fdeeSScott Long 		   struct mpt_raid_disk *disk, request_t *req, u_int Action,
557b0a2fdeeSScott Long 		   uint32_t ActionDataWord, bus_addr_t addr, bus_size_t len,
558b0a2fdeeSScott Long 		   int write, int wait)
559b0a2fdeeSScott Long {
560b0a2fdeeSScott Long 	MSG_RAID_ACTION_REQUEST *rap;
561b0a2fdeeSScott Long 	SGE_SIMPLE32 *se;
562b0a2fdeeSScott Long 
563b0a2fdeeSScott Long 	rap = req->req_vbuf;
564b0a2fdeeSScott Long 	memset(rap, 0, sizeof *rap);
565b0a2fdeeSScott Long 	rap->Action = Action;
566b0a2fdeeSScott Long 	rap->ActionDataWord = ActionDataWord;
567b0a2fdeeSScott Long 	rap->Function = MPI_FUNCTION_RAID_ACTION;
568b0a2fdeeSScott Long 	rap->VolumeID = vol->config_page->VolumeID;
569b0a2fdeeSScott Long 	rap->VolumeBus = vol->config_page->VolumeBus;
570b0a2fdeeSScott Long 	if (disk != 0)
571b0a2fdeeSScott Long 		rap->PhysDiskNum = disk->config_page.PhysDiskNum;
572b0a2fdeeSScott Long 	else
573b0a2fdeeSScott Long 		rap->PhysDiskNum = 0xFF;
574b0a2fdeeSScott Long 	se = (SGE_SIMPLE32 *)&rap->ActionDataSGE;
575b0a2fdeeSScott Long 	se->Address = addr;
576b0a2fdeeSScott Long 	MPI_pSGE_SET_LENGTH(se, len);
577b0a2fdeeSScott Long 	MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
578b0a2fdeeSScott Long 	    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
579b0a2fdeeSScott Long 	    MPI_SGE_FLAGS_END_OF_LIST |
580b0a2fdeeSScott Long 	    write ? MPI_SGE_FLAGS_HOST_TO_IOC : MPI_SGE_FLAGS_IOC_TO_HOST));
581b0a2fdeeSScott Long 	rap->MsgContext = htole32(req->index | raid_handler_id);
582b0a2fdeeSScott Long 
583b0a2fdeeSScott Long 	mpt_check_doorbell(mpt);
584b0a2fdeeSScott Long 	mpt_send_cmd(mpt, req);
585b0a2fdeeSScott Long 
586b0a2fdeeSScott Long 	if (wait) {
587b0a2fdeeSScott Long 		return (mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE,
588b0a2fdeeSScott Long 				     /*sleep_ok*/FALSE, /*time_ms*/2000));
589b0a2fdeeSScott Long 	} else {
590b0a2fdeeSScott Long 		return (0);
591b0a2fdeeSScott Long 	}
592b0a2fdeeSScott Long }
593b0a2fdeeSScott Long 
594b0a2fdeeSScott Long /*************************** RAID Status Monitoring ***************************/
595b0a2fdeeSScott Long static int
596b0a2fdeeSScott Long mpt_spawn_raid_thread(struct mpt_softc *mpt)
597b0a2fdeeSScott Long {
598b0a2fdeeSScott Long 	int error;
599b0a2fdeeSScott Long 
600b0a2fdeeSScott Long 	/*
601b0a2fdeeSScott Long 	 * Freeze out any CAM transactions until our thread
602b0a2fdeeSScott Long 	 * is able to run at least once.  We need to update
603b0a2fdeeSScott Long 	 * our RAID pages before acception I/O or we may
604b0a2fdeeSScott Long 	 * reject I/O to an ID we later determine is for a
605b0a2fdeeSScott Long 	 * hidden physdisk.
606b0a2fdeeSScott Long 	 */
607b0a2fdeeSScott Long 	xpt_freeze_simq(mpt->phydisk_sim, 1);
608b0a2fdeeSScott Long 	error = mpt_kthread_create(mpt_raid_thread, mpt,
609b0a2fdeeSScott Long 	    &mpt->raid_thread, /*flags*/0, /*altstack*/0,
610b0a2fdeeSScott Long 	    "mpt_raid%d", mpt->unit);
611b0a2fdeeSScott Long 	if (error != 0)
612b0a2fdeeSScott Long 		xpt_release_simq(mpt->phydisk_sim, /*run_queue*/FALSE);
613b0a2fdeeSScott Long 	return (error);
614b0a2fdeeSScott Long }
615b0a2fdeeSScott Long 
616b0a2fdeeSScott Long static void
617b0a2fdeeSScott Long mpt_terminate_raid_thread(struct mpt_softc *mpt)
618b0a2fdeeSScott Long {
619b0a2fdeeSScott Long 
620b0a2fdeeSScott Long 	if (mpt->raid_thread == NULL) {
621b0a2fdeeSScott Long 		return;
622b0a2fdeeSScott Long 	}
623b0a2fdeeSScott Long 	mpt->shutdwn_raid = 1;
624b0a2fdeeSScott Long 	wakeup(mpt->raid_volumes);
625b0a2fdeeSScott Long 	/*
626b0a2fdeeSScott Long 	 * Sleep on a slightly different location
627b0a2fdeeSScott Long 	 * for this interlock just for added safety.
628b0a2fdeeSScott Long 	 */
629b0a2fdeeSScott Long 	mpt_sleep(mpt, &mpt->raid_thread, PUSER, "thtrm", 0);
630b0a2fdeeSScott Long }
631b0a2fdeeSScott Long 
632b0a2fdeeSScott Long static void
633b0a2fdeeSScott Long mpt_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb)
634b0a2fdeeSScott Long {
635b0a2fdeeSScott Long 	xpt_free_path(ccb->ccb_h.path);
636b0a2fdeeSScott Long 	free(ccb, M_DEVBUF);
637b0a2fdeeSScott Long }
638b0a2fdeeSScott Long 
639b0a2fdeeSScott Long static void
640b0a2fdeeSScott Long mpt_raid_thread(void *arg)
641b0a2fdeeSScott Long {
642b0a2fdeeSScott Long 	struct mpt_softc *mpt;
643b0a2fdeeSScott Long 	int firstrun;
644b0a2fdeeSScott Long 
645b0a2fdeeSScott Long #if __FreeBSD_version >= 500000
646b0a2fdeeSScott Long 	mtx_lock(&Giant);
647b0a2fdeeSScott Long #endif
648b0a2fdeeSScott Long 	mpt = (struct mpt_softc *)arg;
649b0a2fdeeSScott Long 	firstrun = 1;
650b0a2fdeeSScott Long 	MPT_LOCK(mpt);
651b0a2fdeeSScott Long 	while (mpt->shutdwn_raid == 0) {
652b0a2fdeeSScott Long 
653b0a2fdeeSScott Long 		if (mpt->raid_wakeup == 0) {
654b0a2fdeeSScott Long 			mpt_sleep(mpt, &mpt->raid_volumes, PUSER, "idle", 0);
655b0a2fdeeSScott Long 			continue;
656b0a2fdeeSScott Long 		}
657b0a2fdeeSScott Long 
658b0a2fdeeSScott Long 		mpt->raid_wakeup = 0;
659b0a2fdeeSScott Long 
660b0a2fdeeSScott Long 		mpt_refresh_raid_data(mpt);
661b0a2fdeeSScott Long 
662b0a2fdeeSScott Long 		/*
663b0a2fdeeSScott Long 		 * Now that we have our first snapshot of RAID data,
664b0a2fdeeSScott Long 		 * allow CAM to access our physical disk bus.
665b0a2fdeeSScott Long 		 */
666b0a2fdeeSScott Long 		if (firstrun) {
667b0a2fdeeSScott Long 			firstrun = 0;
668b0a2fdeeSScott Long 			xpt_release_simq(mpt->phydisk_sim, /*run_queue*/TRUE);
669b0a2fdeeSScott Long 		}
670b0a2fdeeSScott Long 
671b0a2fdeeSScott Long 		if (mpt->raid_rescan != 0) {
672b0a2fdeeSScott Long 			union ccb *ccb;
673b0a2fdeeSScott Long 			struct cam_path *path;
674b0a2fdeeSScott Long 			int error;
675b0a2fdeeSScott Long 
676b0a2fdeeSScott Long 			mpt->raid_rescan = 0;
677b0a2fdeeSScott Long 
678b0a2fdeeSScott Long 			ccb = malloc(sizeof(*ccb), M_DEVBUF, M_WAITOK);
679b0a2fdeeSScott Long 			error = xpt_create_path(&path, xpt_periph,
680b0a2fdeeSScott Long 						cam_sim_path(mpt->phydisk_sim),
681b0a2fdeeSScott Long 						CAM_TARGET_WILDCARD,
682b0a2fdeeSScott Long 						CAM_LUN_WILDCARD);
683b0a2fdeeSScott Long 			if (error != CAM_REQ_CMP) {
684b0a2fdeeSScott Long 				free(ccb, M_DEVBUF);
685b0a2fdeeSScott Long 				mpt_prt(mpt, "Unable to rescan RAID Bus!\n");
686b0a2fdeeSScott Long 			} else {
687b0a2fdeeSScott Long 				xpt_setup_ccb(&ccb->ccb_h, path, /*priority*/5);
688b0a2fdeeSScott Long 				ccb->ccb_h.func_code = XPT_SCAN_BUS;
689b0a2fdeeSScott Long 				ccb->ccb_h.cbfcnp = mpt_cam_rescan_callback;
690b0a2fdeeSScott Long 				ccb->crcn.flags = CAM_FLAG_NONE;
691b0a2fdeeSScott Long 				xpt_action(ccb);
692b0a2fdeeSScott Long 			}
693b0a2fdeeSScott Long 		}
694b0a2fdeeSScott Long 	}
695b0a2fdeeSScott Long 	mpt->raid_thread = NULL;
696b0a2fdeeSScott Long 	wakeup(&mpt->raid_thread);
697b0a2fdeeSScott Long 	MPT_UNLOCK(mpt);
698b0a2fdeeSScott Long #if __FreeBSD_version >= 500000
699b0a2fdeeSScott Long 	mtx_unlock(&Giant);
700b0a2fdeeSScott Long #endif
701b0a2fdeeSScott Long 	kthread_exit(0);
702b0a2fdeeSScott Long }
703b0a2fdeeSScott Long 
704b0a2fdeeSScott Long cam_status
705b0a2fdeeSScott Long mpt_raid_quiesce_disk(struct mpt_softc *mpt, struct mpt_raid_disk *mpt_disk,
706b0a2fdeeSScott Long 		      request_t *req)
707b0a2fdeeSScott Long {
708b0a2fdeeSScott Long 	union ccb *ccb;
709b0a2fdeeSScott Long 
710b0a2fdeeSScott Long 	ccb = req->ccb;
711b0a2fdeeSScott Long 	if ((mpt_disk->flags & MPT_RDF_QUIESCED) != 0)
712b0a2fdeeSScott Long 		return (CAM_REQ_CMP);
713b0a2fdeeSScott Long 
714b0a2fdeeSScott Long 	if ((mpt_disk->flags & MPT_RDF_QUIESCING) == 0) {
715b0a2fdeeSScott Long 		int rv;
716b0a2fdeeSScott Long 
717b0a2fdeeSScott Long 		mpt_disk->flags |= MPT_RDF_QUIESCING;
718b0a2fdeeSScott Long 		xpt_freeze_devq(ccb->ccb_h.path, 1);
719b0a2fdeeSScott Long 
720b0a2fdeeSScott Long 		rv = mpt_issue_raid_req(mpt, mpt_disk->volume, mpt_disk, req,
721b0a2fdeeSScott Long 					MPI_RAID_ACTION_QUIESCE_PHYS_IO,
722b0a2fdeeSScott Long 					/*ActionData*/0, /*addr*/0,
723b0a2fdeeSScott Long 					/*len*/0, /*write*/FALSE,
724b0a2fdeeSScott Long 					/*wait*/FALSE);
725b0a2fdeeSScott Long 		if (rv != 0)
726b0a2fdeeSScott Long 			return (CAM_REQ_CMP_ERR);
727b0a2fdeeSScott Long 
728b0a2fdeeSScott Long 		ccb->ccb_h.timeout_ch =
729b0a2fdeeSScott Long 			timeout(mpt_raid_quiesce_timeout, (caddr_t)ccb, 5 * hz);
730b0a2fdeeSScott Long #if 0
731b0a2fdeeSScott Long 		if (rv == ETIMEDOUT) {
732b0a2fdeeSScott Long 			mpt_disk_prt(mpt, mpt_disk, "mpt_raid_quiesce_disk: "
733b0a2fdeeSScott Long 				     "Quiece Timed-out\n");
734b0a2fdeeSScott Long 			xpt_release_devq(ccb->ccb_h.path, 1, /*run*/0);
735b0a2fdeeSScott Long 			return (CAM_REQ_CMP_ERR);
736b0a2fdeeSScott Long 		}
737b0a2fdeeSScott Long 
738b0a2fdeeSScott Long 		ar = REQ_TO_RAID_ACTION_RESULT(req);
739b0a2fdeeSScott Long 		if (rv != 0
740b0a2fdeeSScott Long 		 || REQ_IOCSTATUS(req) != MPI_IOCSTATUS_SUCCESS
741b0a2fdeeSScott Long 		 || (ar->action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS)) {
742b0a2fdeeSScott Long 			mpt_disk_prt(mpt, mpt_disk, "Quiece Failed"
743b0a2fdeeSScott Long 				    "%d:%x:%x\n", rv, req->IOCStatus,
744b0a2fdeeSScott Long 				    ar->action_status);
745b0a2fdeeSScott Long 			xpt_release_devq(ccb->ccb_h.path, 1, /*run*/0);
746b0a2fdeeSScott Long 			return (CAM_REQ_CMP_ERR);
747b0a2fdeeSScott Long 		}
748b0a2fdeeSScott Long #endif
749b0a2fdeeSScott Long 		return (CAM_REQ_INPROG);
750b0a2fdeeSScott Long 	}
751b0a2fdeeSScott Long 	return (CAM_REQUEUE_REQ);
752b0a2fdeeSScott Long }
753b0a2fdeeSScott Long 
754b0a2fdeeSScott Long /* XXX Ignores that there may be multiple busses/IOCs involved. */
755b0a2fdeeSScott Long cam_status
756b0a2fdeeSScott Long mpt_map_physdisk(struct mpt_softc *mpt, union ccb *ccb, u_int *tgt)
757b0a2fdeeSScott Long {
758b0a2fdeeSScott Long 	struct mpt_raid_disk *mpt_disk;
759b0a2fdeeSScott Long 
760b0a2fdeeSScott Long 	mpt_disk = mpt->raid_disks + ccb->ccb_h.target_id;
761b0a2fdeeSScott Long 	if (ccb->ccb_h.target_id < mpt->raid_max_disks
762b0a2fdeeSScott Long 	 && (mpt_disk->flags & MPT_RDF_ACTIVE) != 0) {
763b0a2fdeeSScott Long 
764b0a2fdeeSScott Long 		*tgt = mpt_disk->config_page.PhysDiskID;
765b0a2fdeeSScott Long 		return (0);
766b0a2fdeeSScott Long 	}
767b0a2fdeeSScott Long 	mpt_lprt(mpt, MPT_PRT_DEBUG, "mpt_map_physdisk(%d) - Not Active\n",
768b0a2fdeeSScott Long 		 ccb->ccb_h.target_id);
769b0a2fdeeSScott Long 	return (-1);
770b0a2fdeeSScott Long }
771b0a2fdeeSScott Long 
772f4e98881SRuslan Ermilov #if 0
773b0a2fdeeSScott Long static void
774b0a2fdeeSScott Long mpt_enable_vol(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol,
775b0a2fdeeSScott Long 	       int enable)
776b0a2fdeeSScott Long {
777b0a2fdeeSScott Long 	request_t *req;
778b0a2fdeeSScott Long 	struct mpt_raid_action_result *ar;
779b0a2fdeeSScott Long 	CONFIG_PAGE_RAID_VOL_0 *vol_pg;
780b0a2fdeeSScott Long 	int enabled;
781b0a2fdeeSScott Long 	int rv;
782b0a2fdeeSScott Long 
783b0a2fdeeSScott Long 	vol_pg = mpt_vol->config_page;
784b0a2fdeeSScott Long 	enabled = vol_pg->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED;
785b0a2fdeeSScott Long 
786b0a2fdeeSScott Long 	/*
787b0a2fdeeSScott Long 	 * If the setting matches the configuration,
788b0a2fdeeSScott Long 	 * there is nothing to do.
789b0a2fdeeSScott Long 	 */
790b0a2fdeeSScott Long 	if ((enabled && enable)
791b0a2fdeeSScott Long 	 || (!enabled && !enable))
792b0a2fdeeSScott Long 		return;
793b0a2fdeeSScott Long 
794b0a2fdeeSScott Long 	req = mpt_get_request(mpt, /*sleep_ok*/TRUE);
795b0a2fdeeSScott Long 	if (req == NULL) {
796b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol,
797b0a2fdeeSScott Long 			    "mpt_enable_vol: Get request failed!\n");
798b0a2fdeeSScott Long 		return;
799b0a2fdeeSScott Long 	}
800b0a2fdeeSScott Long 
801b0a2fdeeSScott Long 	rv = mpt_issue_raid_req(mpt, mpt_vol, /*disk*/NULL, req,
802b0a2fdeeSScott Long 				enable ? MPI_RAID_ACTION_ENABLE_VOLUME
803b0a2fdeeSScott Long 				       : MPI_RAID_ACTION_DISABLE_VOLUME,
804b0a2fdeeSScott Long 				/*data*/0, /*addr*/0, /*len*/0,
805b0a2fdeeSScott Long 				/*write*/FALSE, /*wait*/TRUE);
806b0a2fdeeSScott Long 	if (rv == ETIMEDOUT) {
807b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol, "mpt_enable_vol: "
808b0a2fdeeSScott Long 			    "%s Volume Timed-out\n",
809b0a2fdeeSScott Long 			    enable ? "Enable" : "Disable");
810b0a2fdeeSScott Long 		return;
811b0a2fdeeSScott Long 	}
812b0a2fdeeSScott Long 	ar = REQ_TO_RAID_ACTION_RESULT(req);
813b0a2fdeeSScott Long 	if (rv != 0
814b0a2fdeeSScott Long 	 || REQ_IOCSTATUS(req) != MPI_IOCSTATUS_SUCCESS
815b0a2fdeeSScott Long 	 || (ar->action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS)) {
816b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol, "%s Volume Failed: %d:%x:%x\n",
817b0a2fdeeSScott Long 			    enable ? "Enable" : "Disable",
818b0a2fdeeSScott Long 			    rv, req->IOCStatus, ar->action_status);
819b0a2fdeeSScott Long 	}
820b0a2fdeeSScott Long 
821b0a2fdeeSScott Long 	mpt_free_request(mpt, req);
822b0a2fdeeSScott Long }
823b0a2fdeeSScott Long #endif
824b0a2fdeeSScott Long 
825b0a2fdeeSScott Long static void
826b0a2fdeeSScott Long mpt_verify_mwce(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol)
827b0a2fdeeSScott Long {
828b0a2fdeeSScott Long 	request_t *req;
829b0a2fdeeSScott Long 	struct mpt_raid_action_result *ar;
830b0a2fdeeSScott Long 	CONFIG_PAGE_RAID_VOL_0 *vol_pg;
831b0a2fdeeSScott Long 	uint32_t data;
832b0a2fdeeSScott Long 	int rv;
833b0a2fdeeSScott Long 	int resyncing;
834b0a2fdeeSScott Long 	int mwce;
835b0a2fdeeSScott Long 
836b0a2fdeeSScott Long 	vol_pg = mpt_vol->config_page;
837b0a2fdeeSScott Long 	resyncing = vol_pg->VolumeStatus.Flags
838b0a2fdeeSScott Long 		  & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS;
839b0a2fdeeSScott Long 	mwce = vol_pg->VolumeSettings.Settings
840b0a2fdeeSScott Long 	     & MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
841b0a2fdeeSScott Long 
842b0a2fdeeSScott Long 	/*
843b0a2fdeeSScott Long 	 * If the setting matches the configuration,
844b0a2fdeeSScott Long 	 * there is nothing to do.
845b0a2fdeeSScott Long 	 */
846b0a2fdeeSScott Long 	switch (mpt->raid_mwce_setting) {
847b0a2fdeeSScott Long 	case MPT_RAID_MWCE_REBUILD_ONLY:
848c87e3f83SMatt Jacob 		if ((resyncing && mwce) || (!resyncing && !mwce)) {
849b0a2fdeeSScott Long 			return;
850c87e3f83SMatt Jacob 		}
851b0a2fdeeSScott Long 		mpt_vol->flags ^= MPT_RVF_WCE_CHANGED;
852b0a2fdeeSScott Long 		if ((mpt_vol->flags & MPT_RVF_WCE_CHANGED) == 0) {
853b0a2fdeeSScott Long 			/*
854b0a2fdeeSScott Long 			 * Wait one more status update to see if
855b0a2fdeeSScott Long 			 * resyncing gets enabled.  It gets disabled
856b0a2fdeeSScott Long 			 * temporarilly when WCE is changed.
857b0a2fdeeSScott Long 			 */
858b0a2fdeeSScott Long 			return;
859b0a2fdeeSScott Long 		}
860b0a2fdeeSScott Long 		break;
861b0a2fdeeSScott Long 	case MPT_RAID_MWCE_ON:
862b0a2fdeeSScott Long 		if (mwce)
863b0a2fdeeSScott Long 			return;
864b0a2fdeeSScott Long 		break;
865b0a2fdeeSScott Long 	case MPT_RAID_MWCE_OFF:
866b0a2fdeeSScott Long 		if (!mwce)
867b0a2fdeeSScott Long 			return;
868b0a2fdeeSScott Long 		break;
869b0a2fdeeSScott Long 	case MPT_RAID_MWCE_NC:
870b0a2fdeeSScott Long 		return;
871b0a2fdeeSScott Long 	}
872b0a2fdeeSScott Long 
873b0a2fdeeSScott Long 	req = mpt_get_request(mpt, /*sleep_ok*/TRUE);
874b0a2fdeeSScott Long 	if (req == NULL) {
875b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol,
876b0a2fdeeSScott Long 			    "mpt_verify_mwce: Get request failed!\n");
877b0a2fdeeSScott Long 		return;
878b0a2fdeeSScott Long 	}
879b0a2fdeeSScott Long 
880b0a2fdeeSScott Long 	vol_pg->VolumeSettings.Settings ^=
881b0a2fdeeSScott Long 	    MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
882b0a2fdeeSScott Long 	memcpy(&data, &vol_pg->VolumeSettings, sizeof(data));
883b0a2fdeeSScott Long 	vol_pg->VolumeSettings.Settings ^=
884b0a2fdeeSScott Long 	    MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
885b0a2fdeeSScott Long 	rv = mpt_issue_raid_req(mpt, mpt_vol, /*disk*/NULL, req,
886b0a2fdeeSScott Long 				MPI_RAID_ACTION_CHANGE_VOLUME_SETTINGS,
887b0a2fdeeSScott Long 				data, /*addr*/0, /*len*/0,
888b0a2fdeeSScott Long 				/*write*/FALSE, /*wait*/TRUE);
889b0a2fdeeSScott Long 	if (rv == ETIMEDOUT) {
890b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol, "mpt_verify_mwce: "
891b0a2fdeeSScott Long 			    "Write Cache Enable Timed-out\n");
892b0a2fdeeSScott Long 		return;
893b0a2fdeeSScott Long 	}
894b0a2fdeeSScott Long 	ar = REQ_TO_RAID_ACTION_RESULT(req);
895b0a2fdeeSScott Long 	if (rv != 0
896b0a2fdeeSScott Long 	 || REQ_IOCSTATUS(req) != MPI_IOCSTATUS_SUCCESS
897b0a2fdeeSScott Long 	 || (ar->action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS)) {
898b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol, "Write Cache Enable Failed: "
899b0a2fdeeSScott Long 			    "%d:%x:%x\n", rv, req->IOCStatus,
900b0a2fdeeSScott Long 			    ar->action_status);
901b0a2fdeeSScott Long 	} else {
902b0a2fdeeSScott Long 		vol_pg->VolumeSettings.Settings ^=
903b0a2fdeeSScott Long 		    MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
904b0a2fdeeSScott Long 	}
905b0a2fdeeSScott Long 	mpt_free_request(mpt, req);
906b0a2fdeeSScott Long }
907b0a2fdeeSScott Long 
908b0a2fdeeSScott Long static void
909b0a2fdeeSScott Long mpt_verify_resync_rate(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol)
910b0a2fdeeSScott Long {
911b0a2fdeeSScott Long 	request_t *req;
912b0a2fdeeSScott Long 	struct mpt_raid_action_result *ar;
913b0a2fdeeSScott Long 	CONFIG_PAGE_RAID_VOL_0	*vol_pg;
914b0a2fdeeSScott Long 	u_int prio;
915b0a2fdeeSScott Long 	int rv;
916b0a2fdeeSScott Long 
917b0a2fdeeSScott Long 	vol_pg = mpt_vol->config_page;
918b0a2fdeeSScott Long 
919b0a2fdeeSScott Long 	if (mpt->raid_resync_rate == MPT_RAID_RESYNC_RATE_NC)
920b0a2fdeeSScott Long 		return;
921b0a2fdeeSScott Long 
922b0a2fdeeSScott Long 	/*
923b0a2fdeeSScott Long 	 * If the current RAID resync rate does not
924b0a2fdeeSScott Long 	 * match our configured rate, update it.
925b0a2fdeeSScott Long 	 */
926b0a2fdeeSScott Long 	prio = vol_pg->VolumeSettings.Settings
927b0a2fdeeSScott Long 	     & MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC;
928b0a2fdeeSScott Long 	if (vol_pg->ResyncRate != 0
929b0a2fdeeSScott Long 	 && vol_pg->ResyncRate != mpt->raid_resync_rate) {
930b0a2fdeeSScott Long 
931b0a2fdeeSScott Long 		req = mpt_get_request(mpt, /*sleep_ok*/TRUE);
932b0a2fdeeSScott Long 		if (req == NULL) {
933b0a2fdeeSScott Long 			mpt_vol_prt(mpt, mpt_vol, "mpt_verify_resync_rate: "
934b0a2fdeeSScott Long 				    "Get request failed!\n");
935b0a2fdeeSScott Long 			return;
936b0a2fdeeSScott Long 		}
937b0a2fdeeSScott Long 
938b0a2fdeeSScott Long 		rv = mpt_issue_raid_req(mpt, mpt_vol, /*disk*/NULL, req,
939b0a2fdeeSScott Long 					MPI_RAID_ACTION_SET_RESYNC_RATE,
940b0a2fdeeSScott Long 					mpt->raid_resync_rate, /*addr*/0,
941b0a2fdeeSScott Long 					/*len*/0, /*write*/FALSE, /*wait*/TRUE);
942b0a2fdeeSScott Long 		if (rv == ETIMEDOUT) {
943b0a2fdeeSScott Long 			mpt_vol_prt(mpt, mpt_vol, "mpt_refresh_raid_data: "
944b0a2fdeeSScott Long 				    "Resync Rate Setting Timed-out\n");
945b0a2fdeeSScott Long 			return;
946b0a2fdeeSScott Long 		}
947b0a2fdeeSScott Long 
948b0a2fdeeSScott Long 		ar = REQ_TO_RAID_ACTION_RESULT(req);
949b0a2fdeeSScott Long 		if (rv != 0
950b0a2fdeeSScott Long 		 || REQ_IOCSTATUS(req) != MPI_IOCSTATUS_SUCCESS
951b0a2fdeeSScott Long 		 || (ar->action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS)) {
952b0a2fdeeSScott Long 			mpt_vol_prt(mpt, mpt_vol, "Resync Rate Setting Failed: "
953b0a2fdeeSScott Long 				    "%d:%x:%x\n", rv, req->IOCStatus,
954b0a2fdeeSScott Long 				    ar->action_status);
955b0a2fdeeSScott Long 		} else
956b0a2fdeeSScott Long 			vol_pg->ResyncRate = mpt->raid_resync_rate;
957b0a2fdeeSScott Long 		mpt_free_request(mpt, req);
958b0a2fdeeSScott Long 	} else if ((prio && mpt->raid_resync_rate < 128)
959b0a2fdeeSScott Long 		|| (!prio && mpt->raid_resync_rate >= 128)) {
960b0a2fdeeSScott Long 		uint32_t data;
961b0a2fdeeSScott Long 
962b0a2fdeeSScott Long 		req = mpt_get_request(mpt, /*sleep_ok*/TRUE);
963b0a2fdeeSScott Long 		if (req == NULL) {
964b0a2fdeeSScott Long 			mpt_vol_prt(mpt, mpt_vol, "mpt_verify_resync_rate: "
965b0a2fdeeSScott Long 				    "Get request failed!\n");
966b0a2fdeeSScott Long 			return;
967b0a2fdeeSScott Long 		}
968b0a2fdeeSScott Long 
969b0a2fdeeSScott Long 		vol_pg->VolumeSettings.Settings ^=
970b0a2fdeeSScott Long 		    MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC;
971b0a2fdeeSScott Long 		memcpy(&data, &vol_pg->VolumeSettings, sizeof(data));
972b0a2fdeeSScott Long 		vol_pg->VolumeSettings.Settings ^=
973b0a2fdeeSScott Long 		    MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC;
974b0a2fdeeSScott Long 		rv = mpt_issue_raid_req(mpt, mpt_vol, /*disk*/NULL, req,
975b0a2fdeeSScott Long 					MPI_RAID_ACTION_CHANGE_VOLUME_SETTINGS,
976b0a2fdeeSScott Long 					data, /*addr*/0, /*len*/0,
977b0a2fdeeSScott Long 					/*write*/FALSE, /*wait*/TRUE);
978b0a2fdeeSScott Long 		if (rv == ETIMEDOUT) {
979b0a2fdeeSScott Long 			mpt_vol_prt(mpt, mpt_vol, "mpt_refresh_raid_data: "
980b0a2fdeeSScott Long 				    "Resync Rate Setting Timed-out\n");
981b0a2fdeeSScott Long 			return;
982b0a2fdeeSScott Long 		}
983b0a2fdeeSScott Long 		ar = REQ_TO_RAID_ACTION_RESULT(req);
984b0a2fdeeSScott Long 		if (rv != 0
985b0a2fdeeSScott Long 		 || REQ_IOCSTATUS(req) != MPI_IOCSTATUS_SUCCESS
986b0a2fdeeSScott Long 		 || (ar->action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS)) {
987b0a2fdeeSScott Long 			mpt_vol_prt(mpt, mpt_vol, "Resync Rate Setting Failed: "
988b0a2fdeeSScott Long 				    "%d:%x:%x\n", rv, req->IOCStatus,
989b0a2fdeeSScott Long 				    ar->action_status);
990b0a2fdeeSScott Long 		} else {
991b0a2fdeeSScott Long 			vol_pg->VolumeSettings.Settings ^=
992b0a2fdeeSScott Long 			    MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC;
993b0a2fdeeSScott Long 		}
994b0a2fdeeSScott Long 
995b0a2fdeeSScott Long 		mpt_free_request(mpt, req);
996b0a2fdeeSScott Long 	}
997b0a2fdeeSScott Long }
998b0a2fdeeSScott Long 
999b0a2fdeeSScott Long static void
1000b0a2fdeeSScott Long mpt_adjust_queue_depth(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol,
1001b0a2fdeeSScott Long 		       struct cam_path *path)
1002b0a2fdeeSScott Long {
1003b0a2fdeeSScott Long 	struct ccb_relsim crs;
1004b0a2fdeeSScott Long 
1005b0a2fdeeSScott Long 	xpt_setup_ccb(&crs.ccb_h, path, /*priority*/5);
1006b0a2fdeeSScott Long 	crs.ccb_h.func_code = XPT_REL_SIMQ;
1007b0a2fdeeSScott Long 	crs.release_flags = RELSIM_ADJUST_OPENINGS;
1008b0a2fdeeSScott Long 	crs.openings = mpt->raid_queue_depth;
1009b0a2fdeeSScott Long 	xpt_action((union ccb *)&crs);
1010b0a2fdeeSScott Long 	if (crs.ccb_h.status != CAM_REQ_CMP)
1011b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol, "mpt_adjust_queue_depth failed "
1012b0a2fdeeSScott Long 			    "with CAM status %#x\n", crs.ccb_h.status);
1013b0a2fdeeSScott Long }
1014b0a2fdeeSScott Long 
1015b0a2fdeeSScott Long static void
1016b0a2fdeeSScott Long mpt_announce_vol(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol)
1017b0a2fdeeSScott Long {
1018b0a2fdeeSScott Long 	CONFIG_PAGE_RAID_VOL_0 *vol_pg;
1019b0a2fdeeSScott Long 	u_int i;
1020b0a2fdeeSScott Long 
1021b0a2fdeeSScott Long 	vol_pg = mpt_vol->config_page;
1022b0a2fdeeSScott Long 	mpt_vol_prt(mpt, mpt_vol, "Settings (");
1023b0a2fdeeSScott Long 	for (i = 1; i <= 0x8000; i <<= 1) {
1024b0a2fdeeSScott Long 		switch (vol_pg->VolumeSettings.Settings & i) {
1025b0a2fdeeSScott Long 		case MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE:
1026b0a2fdeeSScott Long 			mpt_prtc(mpt, " Member-WCE");
1027b0a2fdeeSScott Long 			break;
1028b0a2fdeeSScott Long 		case MPI_RAIDVOL0_SETTING_OFFLINE_ON_SMART:
1029b0a2fdeeSScott Long 			mpt_prtc(mpt, " Offline-On-SMART-Err");
1030b0a2fdeeSScott Long 			break;
1031b0a2fdeeSScott Long 		case MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE:
1032b0a2fdeeSScott Long 			mpt_prtc(mpt, " Hot-Plug-Spares");
1033b0a2fdeeSScott Long 			break;
1034b0a2fdeeSScott Long 		case MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC:
1035b0a2fdeeSScott Long 			mpt_prtc(mpt, " High-Priority-ReSync");
1036b0a2fdeeSScott Long 			break;
1037b0a2fdeeSScott Long 		default:
1038b0a2fdeeSScott Long 			break;
1039b0a2fdeeSScott Long 		}
1040b0a2fdeeSScott Long 	}
1041b0a2fdeeSScott Long 	mpt_prtc(mpt, " )\n");
1042b0a2fdeeSScott Long 	if (vol_pg->VolumeSettings.HotSparePool != 0) {
1043b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol, "Using Spare Pool%s",
1044b0a2fdeeSScott Long 			    powerof2(vol_pg->VolumeSettings.HotSparePool)
1045b0a2fdeeSScott Long 			  ? ":" : "s:");
1046b0a2fdeeSScott Long 		for (i = 0; i < 8; i++) {
1047b0a2fdeeSScott Long 			u_int mask;
1048b0a2fdeeSScott Long 
1049b0a2fdeeSScott Long 			mask = 0x1 << i;
1050b0a2fdeeSScott Long 			if ((vol_pg->VolumeSettings.HotSparePool & mask) == 0)
1051b0a2fdeeSScott Long 				continue;
1052b0a2fdeeSScott Long 			mpt_prtc(mpt, " %d", i);
1053b0a2fdeeSScott Long 		}
1054b0a2fdeeSScott Long 		mpt_prtc(mpt, "\n");
1055b0a2fdeeSScott Long 	}
1056b0a2fdeeSScott Long 	mpt_vol_prt(mpt, mpt_vol, "%d Members:\n", vol_pg->NumPhysDisks);
1057b0a2fdeeSScott Long 	for (i = 0; i < vol_pg->NumPhysDisks; i++){
1058b0a2fdeeSScott Long 		struct mpt_raid_disk *mpt_disk;
1059b0a2fdeeSScott Long 		CONFIG_PAGE_RAID_PHYS_DISK_0 *disk_pg;
1060b0a2fdeeSScott Long 
1061b0a2fdeeSScott Long 		mpt_disk = mpt->raid_disks
1062b0a2fdeeSScott Long 			 + vol_pg->PhysDisk[i].PhysDiskNum;
1063b0a2fdeeSScott Long 		disk_pg = &mpt_disk->config_page;
1064b0a2fdeeSScott Long 		mpt_prtc(mpt, "      ");
1065b0a2fdeeSScott Long 		mpt_prtc(mpt, "(%s:%d:%d): ", device_get_nameunit(mpt->dev),
1066b0a2fdeeSScott Long 			 disk_pg->PhysDiskBus, disk_pg->PhysDiskID);
1067b0a2fdeeSScott Long 		if (vol_pg->VolumeType == MPI_RAID_VOL_TYPE_IM)
1068b0a2fdeeSScott Long 			mpt_prtc(mpt, "%s\n",
1069b0a2fdeeSScott Long 				 mpt_disk->member_number == 0
1070b0a2fdeeSScott Long 			       ? "Primary" : "Secondary");
1071b0a2fdeeSScott Long 		else
1072b0a2fdeeSScott Long 			mpt_prtc(mpt, "Stripe Position %d\n",
1073b0a2fdeeSScott Long 				 mpt_disk->member_number);
1074b0a2fdeeSScott Long 	}
1075b0a2fdeeSScott Long }
1076b0a2fdeeSScott Long 
1077b0a2fdeeSScott Long static void
1078b0a2fdeeSScott Long mpt_announce_disk(struct mpt_softc *mpt, struct mpt_raid_disk *mpt_disk)
1079b0a2fdeeSScott Long {
1080b0a2fdeeSScott Long 	CONFIG_PAGE_RAID_PHYS_DISK_0 *disk_pg;
1081b0a2fdeeSScott Long 	u_int i;
1082b0a2fdeeSScott Long 
1083b0a2fdeeSScott Long 	disk_pg = &mpt_disk->config_page;
1084b0a2fdeeSScott Long 	mpt_disk_prt(mpt, mpt_disk,
1085b0a2fdeeSScott Long 		     "Physical (%s:%d:%d), Pass-thru (%s:%d:%d)\n",
1086b0a2fdeeSScott Long 		     device_get_nameunit(mpt->dev), disk_pg->PhysDiskBus,
1087b0a2fdeeSScott Long 		     disk_pg->PhysDiskID, device_get_nameunit(mpt->dev),
1088b0a2fdeeSScott Long 		     /*bus*/1, mpt_disk - mpt->raid_disks);
1089b0a2fdeeSScott Long 
1090b0a2fdeeSScott Long 	if (disk_pg->PhysDiskSettings.HotSparePool == 0)
1091b0a2fdeeSScott Long 		return;
1092b0a2fdeeSScott Long 	mpt_disk_prt(mpt, mpt_disk, "Member of Hot Spare Pool%s",
1093b0a2fdeeSScott Long 		     powerof2(disk_pg->PhysDiskSettings.HotSparePool)
1094b0a2fdeeSScott Long 		   ? ":" : "s:");
1095b0a2fdeeSScott Long 	for (i = 0; i < 8; i++) {
1096b0a2fdeeSScott Long 		u_int mask;
1097b0a2fdeeSScott Long 
1098b0a2fdeeSScott Long 		mask = 0x1 << i;
1099b0a2fdeeSScott Long 		if ((disk_pg->PhysDiskSettings.HotSparePool & mask) == 0)
1100b0a2fdeeSScott Long 			continue;
1101b0a2fdeeSScott Long 		mpt_prtc(mpt, " %d", i);
1102b0a2fdeeSScott Long 	}
1103b0a2fdeeSScott Long 	mpt_prtc(mpt, "\n");
1104b0a2fdeeSScott Long }
1105b0a2fdeeSScott Long 
1106b0a2fdeeSScott Long static void
1107b0a2fdeeSScott Long mpt_refresh_raid_disk(struct mpt_softc *mpt, struct mpt_raid_disk *mpt_disk,
1108b0a2fdeeSScott Long 		      IOC_3_PHYS_DISK *ioc_disk)
1109b0a2fdeeSScott Long {
1110b0a2fdeeSScott Long 	int rv;
1111b0a2fdeeSScott Long 
1112b0a2fdeeSScott Long 	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK,
1113b0a2fdeeSScott Long 				 /*PageNumber*/0, ioc_disk->PhysDiskNum,
1114b0a2fdeeSScott Long 				 &mpt_disk->config_page.Header,
1115b0a2fdeeSScott Long 				 /*sleep_ok*/TRUE, /*timeout_ms*/5000);
1116b0a2fdeeSScott Long 	if (rv != 0) {
1117b0a2fdeeSScott Long 		mpt_prt(mpt, "mpt_refresh_raid_disk: "
1118b0a2fdeeSScott Long 			"Failed to read RAID Disk Hdr(%d)\n",
1119b0a2fdeeSScott Long 		 	ioc_disk->PhysDiskNum);
1120b0a2fdeeSScott Long 		return;
1121b0a2fdeeSScott Long 	}
1122b0a2fdeeSScott Long 	rv = mpt_read_cur_cfg_page(mpt, ioc_disk->PhysDiskNum,
1123b0a2fdeeSScott Long 				   &mpt_disk->config_page.Header,
1124b0a2fdeeSScott Long 				   sizeof(mpt_disk->config_page),
1125b0a2fdeeSScott Long 				   /*sleep_ok*/TRUE, /*timeout_ms*/5000);
1126b0a2fdeeSScott Long 	if (rv != 0)
1127b0a2fdeeSScott Long 		mpt_prt(mpt, "mpt_refresh_raid_disk: "
1128b0a2fdeeSScott Long 			"Failed to read RAID Disk Page(%d)\n",
1129b0a2fdeeSScott Long 		 	ioc_disk->PhysDiskNum);
1130b0a2fdeeSScott Long }
1131b0a2fdeeSScott Long 
1132b0a2fdeeSScott Long static void
1133b0a2fdeeSScott Long mpt_refresh_raid_vol(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol,
1134b0a2fdeeSScott Long 		     CONFIG_PAGE_IOC_2_RAID_VOL *ioc_vol)
1135b0a2fdeeSScott Long {
1136b0a2fdeeSScott Long 	CONFIG_PAGE_RAID_VOL_0 *vol_pg;
1137b0a2fdeeSScott Long 	struct mpt_raid_action_result *ar;
1138b0a2fdeeSScott Long 	request_t *req;
1139b0a2fdeeSScott Long 	int rv;
1140b0a2fdeeSScott Long 	int i;
1141b0a2fdeeSScott Long 
1142b0a2fdeeSScott Long 	vol_pg = mpt_vol->config_page;
1143b0a2fdeeSScott Long 	mpt_vol->flags &= ~MPT_RVF_UP2DATE;
1144b0a2fdeeSScott Long 	rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_RAID_VOLUME,
1145b0a2fdeeSScott Long 				 /*PageNumber*/0, ioc_vol->VolumePageNumber,
1146b0a2fdeeSScott Long 				 &vol_pg->Header, /*sleep_ok*/TRUE,
1147b0a2fdeeSScott Long 				 /*timeout_ms*/5000);
1148b0a2fdeeSScott Long 	if (rv != 0) {
1149b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol, "mpt_refresh_raid_vol: "
1150b0a2fdeeSScott Long 			    "Failed to read RAID Vol Hdr(%d)\n",
1151b0a2fdeeSScott Long 			    ioc_vol->VolumePageNumber);
1152b0a2fdeeSScott Long 		return;
1153b0a2fdeeSScott Long 	}
1154b0a2fdeeSScott Long 	rv = mpt_read_cur_cfg_page(mpt, ioc_vol->VolumePageNumber,
1155b0a2fdeeSScott Long 				   &vol_pg->Header, mpt->raid_page0_len,
1156b0a2fdeeSScott Long 				   /*sleep_ok*/TRUE, /*timeout_ms*/5000);
1157b0a2fdeeSScott Long 	if (rv != 0) {
1158b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol, "mpt_refresh_raid_vol: "
1159b0a2fdeeSScott Long 			    "Failed to read RAID Vol Page(%d)\n",
1160b0a2fdeeSScott Long 			    ioc_vol->VolumePageNumber);
1161b0a2fdeeSScott Long 		return;
1162b0a2fdeeSScott Long 	}
1163b0a2fdeeSScott Long 	mpt_vol->flags |= MPT_RVF_ACTIVE;
1164b0a2fdeeSScott Long 
1165b0a2fdeeSScott Long 	/* Update disk entry array data. */
1166b0a2fdeeSScott Long 	for (i = 0; i < vol_pg->NumPhysDisks; i++) {
1167b0a2fdeeSScott Long 		struct mpt_raid_disk *mpt_disk;
1168b0a2fdeeSScott Long 
1169b0a2fdeeSScott Long 		mpt_disk = mpt->raid_disks + vol_pg->PhysDisk[i].PhysDiskNum;
1170b0a2fdeeSScott Long 		mpt_disk->volume = mpt_vol;
1171b0a2fdeeSScott Long 		mpt_disk->member_number = vol_pg->PhysDisk[i].PhysDiskMap;
1172b0a2fdeeSScott Long 		if (vol_pg->VolumeType == MPI_RAID_VOL_TYPE_IM)
1173b0a2fdeeSScott Long 			mpt_disk->member_number--;
1174b0a2fdeeSScott Long 	}
1175b0a2fdeeSScott Long 
1176b0a2fdeeSScott Long 	if ((vol_pg->VolumeStatus.Flags
1177b0a2fdeeSScott Long 	   & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) == 0)
1178b0a2fdeeSScott Long 		return;
1179b0a2fdeeSScott Long 
1180b0a2fdeeSScott Long 	req = mpt_get_request(mpt, /*sleep_ok*/TRUE);
1181b0a2fdeeSScott Long 	if (req == NULL) {
1182b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol,
1183b0a2fdeeSScott Long 			    "mpt_refresh_raid_vol: Get request failed!\n");
1184b0a2fdeeSScott Long 		return;
1185b0a2fdeeSScott Long 	}
1186b0a2fdeeSScott Long 	rv = mpt_issue_raid_req(mpt, mpt_vol, /*disk*/NULL, req,
1187b0a2fdeeSScott Long 				MPI_RAID_ACTION_INDICATOR_STRUCT,
1188b0a2fdeeSScott Long 				/*ActionWord*/0, /*addr*/0, /*len*/0,
1189b0a2fdeeSScott Long 				/*write*/FALSE, /*wait*/TRUE);
1190b0a2fdeeSScott Long 	if (rv == ETIMEDOUT) {
1191b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol, "mpt_refresh_raid_vol: "
1192b0a2fdeeSScott Long 			    "Progress indicator fetch timedout!\n");
1193b0a2fdeeSScott Long 		return;
1194b0a2fdeeSScott Long 	}
1195b0a2fdeeSScott Long 
1196b0a2fdeeSScott Long 	ar = REQ_TO_RAID_ACTION_RESULT(req);
1197b0a2fdeeSScott Long 	if (rv == 0
1198b0a2fdeeSScott Long 	 && ar->action_status == MPI_RAID_ACTION_ASTATUS_SUCCESS
1199b0a2fdeeSScott Long 	 && REQ_IOCSTATUS(req) == MPI_IOCSTATUS_SUCCESS) {
1200b0a2fdeeSScott Long 		memcpy(&mpt_vol->sync_progress,
1201b0a2fdeeSScott Long 		       &ar->action_data.indicator_struct,
1202b0a2fdeeSScott Long 		       sizeof(mpt_vol->sync_progress));
1203b0a2fdeeSScott Long 	} else {
1204b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol, "mpt_refresh_raid_vol: "
1205b0a2fdeeSScott Long 			    "Progress indicator fetch failed!\n");
1206b0a2fdeeSScott Long 	}
1207b0a2fdeeSScott Long 	mpt_free_request(mpt, req);
1208b0a2fdeeSScott Long }
1209b0a2fdeeSScott Long 
1210b0a2fdeeSScott Long /*
1211b0a2fdeeSScott Long  * Update in-core information about RAID support.  We update any entries
1212b0a2fdeeSScott Long  * that didn't previously exists or have been marked as needing to
1213b0a2fdeeSScott Long  * be updated by our event handler.  Interesting changes are displayed
1214b0a2fdeeSScott Long  * to the console.
1215b0a2fdeeSScott Long  */
1216b0a2fdeeSScott Long void
1217b0a2fdeeSScott Long mpt_refresh_raid_data(struct mpt_softc *mpt)
1218b0a2fdeeSScott Long {
1219b0a2fdeeSScott Long 	CONFIG_PAGE_IOC_2_RAID_VOL *ioc_vol;
1220b0a2fdeeSScott Long 	CONFIG_PAGE_IOC_2_RAID_VOL *ioc_last_vol;
1221b0a2fdeeSScott Long 	IOC_3_PHYS_DISK *ioc_disk;
1222b0a2fdeeSScott Long 	IOC_3_PHYS_DISK *ioc_last_disk;
1223b0a2fdeeSScott Long 	CONFIG_PAGE_RAID_VOL_0	*vol_pg;
1224b0a2fdeeSScott Long 	size_t len;
1225b0a2fdeeSScott Long 	int rv;
1226b0a2fdeeSScott Long 	int i;
12275cc0208aSAlexander Kabaev 	u_int nonopt_volumes;
1228b0a2fdeeSScott Long 
1229c87e3f83SMatt Jacob 	if (mpt->ioc_page2 == NULL || mpt->ioc_page3 == NULL) {
1230b0a2fdeeSScott Long 		return;
1231c87e3f83SMatt Jacob 	}
1232b0a2fdeeSScott Long 
1233b0a2fdeeSScott Long 	/*
1234c87e3f83SMatt Jacob 	 * Mark all items as unreferenced by the configuration.
1235b0a2fdeeSScott Long 	 * This allows us to find, report, and discard stale
1236b0a2fdeeSScott Long 	 * entries.
1237b0a2fdeeSScott Long 	 */
1238c87e3f83SMatt Jacob 	for (i = 0; i < mpt->ioc_page2->MaxPhysDisks; i++) {
1239b0a2fdeeSScott Long 		mpt->raid_disks[i].flags &= ~MPT_RDF_REFERENCED;
1240c87e3f83SMatt Jacob 	}
1241c87e3f83SMatt Jacob 	for (i = 0; i < mpt->ioc_page2->MaxVolumes; i++) {
1242b0a2fdeeSScott Long 		mpt->raid_volumes[i].flags &= ~MPT_RVF_REFERENCED;
1243c87e3f83SMatt Jacob 	}
1244b0a2fdeeSScott Long 
1245b0a2fdeeSScott Long 	/*
1246b0a2fdeeSScott Long 	 * Get Physical Disk information.
1247b0a2fdeeSScott Long 	 */
1248b0a2fdeeSScott Long 	len = mpt->ioc_page3->Header.PageLength * sizeof(uint32_t);
1249b0a2fdeeSScott Long 	rv = mpt_read_cur_cfg_page(mpt, /*PageAddress*/0,
1250b0a2fdeeSScott Long 				   &mpt->ioc_page3->Header, len,
1251b0a2fdeeSScott Long 				   /*sleep_ok*/TRUE, /*timeout_ms*/5000);
1252b0a2fdeeSScott Long 	if (rv) {
1253b0a2fdeeSScott Long 		mpt_prt(mpt, "mpt_refresh_raid_data: "
1254b0a2fdeeSScott Long 			"Failed to read IOC Page 3\n");
1255b0a2fdeeSScott Long 		return;
1256b0a2fdeeSScott Long 	}
1257b0a2fdeeSScott Long 
1258b0a2fdeeSScott Long 	ioc_disk = mpt->ioc_page3->PhysDisk;
1259b0a2fdeeSScott Long 	ioc_last_disk = ioc_disk + mpt->ioc_page3->NumPhysDisks;
1260b0a2fdeeSScott Long 	for (; ioc_disk != ioc_last_disk; ioc_disk++) {
1261b0a2fdeeSScott Long 		struct mpt_raid_disk *mpt_disk;
1262b0a2fdeeSScott Long 
1263b0a2fdeeSScott Long 		mpt_disk = mpt->raid_disks + ioc_disk->PhysDiskNum;
1264b0a2fdeeSScott Long 		mpt_disk->flags |= MPT_RDF_REFERENCED;
1265b0a2fdeeSScott Long 		if ((mpt_disk->flags & (MPT_RDF_ACTIVE|MPT_RDF_UP2DATE))
1266b0a2fdeeSScott Long 		 != (MPT_RDF_ACTIVE|MPT_RDF_UP2DATE)) {
1267b0a2fdeeSScott Long 
1268b0a2fdeeSScott Long 			mpt_refresh_raid_disk(mpt, mpt_disk, ioc_disk);
1269b0a2fdeeSScott Long 
1270b0a2fdeeSScott Long 		}
1271b0a2fdeeSScott Long 		mpt_disk->flags |= MPT_RDF_ACTIVE;
1272b0a2fdeeSScott Long 		mpt->raid_rescan++;
1273b0a2fdeeSScott Long 	}
1274b0a2fdeeSScott Long 
1275b0a2fdeeSScott Long 	/*
1276b0a2fdeeSScott Long 	 * Refresh volume data.
1277b0a2fdeeSScott Long 	 */
1278b0a2fdeeSScott Long 	len = mpt->ioc_page2->Header.PageLength * sizeof(uint32_t);
1279b0a2fdeeSScott Long 	rv = mpt_read_cur_cfg_page(mpt, /*PageAddress*/0,
1280b0a2fdeeSScott Long 				   &mpt->ioc_page2->Header, len,
1281b0a2fdeeSScott Long 				   /*sleep_ok*/TRUE, /*timeout_ms*/5000);
1282b0a2fdeeSScott Long 	if (rv) {
1283b0a2fdeeSScott Long 		mpt_prt(mpt, "mpt_refresh_raid_data: "
1284b0a2fdeeSScott Long 			"Failed to read IOC Page 2\n");
1285b0a2fdeeSScott Long 		return;
1286b0a2fdeeSScott Long 	}
1287b0a2fdeeSScott Long 
1288b0a2fdeeSScott Long 	ioc_vol = mpt->ioc_page2->RaidVolume;
1289b0a2fdeeSScott Long 	ioc_last_vol = ioc_vol + mpt->ioc_page2->NumActiveVolumes;
1290b0a2fdeeSScott Long 	for (;ioc_vol != ioc_last_vol; ioc_vol++) {
1291b0a2fdeeSScott Long 		struct mpt_raid_volume *mpt_vol;
1292b0a2fdeeSScott Long 
1293b0a2fdeeSScott Long 		mpt_vol = mpt->raid_volumes + ioc_vol->VolumePageNumber;
1294b0a2fdeeSScott Long 		mpt_vol->flags |= MPT_RVF_REFERENCED;
1295b0a2fdeeSScott Long 		vol_pg = mpt_vol->config_page;
1296b0a2fdeeSScott Long 		if (vol_pg == NULL)
1297b0a2fdeeSScott Long 			continue;
1298b0a2fdeeSScott Long 		if (((mpt_vol->flags & (MPT_RVF_ACTIVE|MPT_RVF_UP2DATE))
1299b0a2fdeeSScott Long 		  != (MPT_RVF_ACTIVE|MPT_RVF_UP2DATE))
1300b0a2fdeeSScott Long 		 || (vol_pg->VolumeStatus.Flags
1301b0a2fdeeSScott Long 		   & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) != 0) {
1302b0a2fdeeSScott Long 
1303b0a2fdeeSScott Long 			mpt_refresh_raid_vol(mpt, mpt_vol, ioc_vol);
1304b0a2fdeeSScott Long 		}
1305b0a2fdeeSScott Long 		mpt_vol->flags |= MPT_RVF_ACTIVE;
1306b0a2fdeeSScott Long 	}
1307b0a2fdeeSScott Long 
13085cc0208aSAlexander Kabaev 	nonopt_volumes = 0;
1309b0a2fdeeSScott Long 	for (i = 0; i < mpt->ioc_page2->MaxVolumes; i++) {
1310b0a2fdeeSScott Long 		struct mpt_raid_volume *mpt_vol;
1311b0a2fdeeSScott Long 		uint64_t total;
1312b0a2fdeeSScott Long 		uint64_t left;
1313b0a2fdeeSScott Long 		int m;
1314b0a2fdeeSScott Long 		u_int prio;
1315b0a2fdeeSScott Long 
1316b0a2fdeeSScott Long 		mpt_vol = &mpt->raid_volumes[i];
1317b0a2fdeeSScott Long 
1318b0a2fdeeSScott Long 		if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0)
1319b0a2fdeeSScott Long 			continue;
1320b0a2fdeeSScott Long 
1321b0a2fdeeSScott Long 		vol_pg = mpt_vol->config_page;
1322b0a2fdeeSScott Long 		if ((mpt_vol->flags & (MPT_RVF_REFERENCED|MPT_RVF_ANNOUNCED))
1323b0a2fdeeSScott Long 		 == MPT_RVF_ANNOUNCED) {
1324b0a2fdeeSScott Long 			mpt_vol_prt(mpt, mpt_vol, "No longer configured\n");
1325b0a2fdeeSScott Long 			mpt_vol->flags = 0;
1326b0a2fdeeSScott Long 			continue;
1327b0a2fdeeSScott Long 		}
1328b0a2fdeeSScott Long 
1329b0a2fdeeSScott Long 		if ((mpt_vol->flags & MPT_RVF_ANNOUNCED) == 0) {
1330b0a2fdeeSScott Long 
1331b0a2fdeeSScott Long 			mpt_announce_vol(mpt, mpt_vol);
1332b0a2fdeeSScott Long 			mpt_vol->flags |= MPT_RVF_ANNOUNCED;
1333b0a2fdeeSScott Long 		}
1334b0a2fdeeSScott Long 
13355cc0208aSAlexander Kabaev 		if (vol_pg->VolumeStatus.State !=
13365cc0208aSAlexander Kabaev 		    MPI_RAIDVOL0_STATUS_STATE_OPTIMAL)
13375cc0208aSAlexander Kabaev 			nonopt_volumes++;
13385cc0208aSAlexander Kabaev 
1339b0a2fdeeSScott Long 		if ((mpt_vol->flags & MPT_RVF_UP2DATE) != 0)
1340b0a2fdeeSScott Long 			continue;
1341b0a2fdeeSScott Long 
1342b0a2fdeeSScott Long 		mpt_vol->flags |= MPT_RVF_UP2DATE;
1343b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol, "%s - %s\n",
1344b0a2fdeeSScott Long 			    mpt_vol_type(mpt_vol), mpt_vol_state(mpt_vol));
1345b0a2fdeeSScott Long 		mpt_verify_mwce(mpt, mpt_vol);
1346b0a2fdeeSScott Long 
1347b0a2fdeeSScott Long 		if (vol_pg->VolumeStatus.Flags == 0)
1348b0a2fdeeSScott Long 			continue;
1349b0a2fdeeSScott Long 
1350b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol, "Status (");
1351b0a2fdeeSScott Long 		for (m = 1; m <= 0x80; m <<= 1) {
1352b0a2fdeeSScott Long 			switch (vol_pg->VolumeStatus.Flags & m) {
1353b0a2fdeeSScott Long 			case MPI_RAIDVOL0_STATUS_FLAG_ENABLED:
1354b0a2fdeeSScott Long 				mpt_prtc(mpt, " Enabled");
1355b0a2fdeeSScott Long 				break;
1356b0a2fdeeSScott Long 			case MPI_RAIDVOL0_STATUS_FLAG_QUIESCED:
1357b0a2fdeeSScott Long 				mpt_prtc(mpt, " Quiesced");
1358b0a2fdeeSScott Long 				break;
1359b0a2fdeeSScott Long 			case MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS:
1360b0a2fdeeSScott Long 				mpt_prtc(mpt, " Re-Syncing");
1361b0a2fdeeSScott Long 				break;
1362b0a2fdeeSScott Long 			case MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE:
1363b0a2fdeeSScott Long 				mpt_prtc(mpt, " Inactive");
1364b0a2fdeeSScott Long 				break;
1365b0a2fdeeSScott Long 			default:
1366b0a2fdeeSScott Long 				break;
1367b0a2fdeeSScott Long 			}
1368b0a2fdeeSScott Long 		}
1369b0a2fdeeSScott Long 		mpt_prtc(mpt, " )\n");
1370b0a2fdeeSScott Long 
1371b0a2fdeeSScott Long 		if ((vol_pg->VolumeStatus.Flags
1372b0a2fdeeSScott Long 		   & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) == 0)
1373b0a2fdeeSScott Long 			continue;
1374b0a2fdeeSScott Long 
1375b0a2fdeeSScott Long 		mpt_verify_resync_rate(mpt, mpt_vol);
1376b0a2fdeeSScott Long 
1377b0a2fdeeSScott Long 		left = u64toh(mpt_vol->sync_progress.BlocksRemaining);
1378b0a2fdeeSScott Long 		total = u64toh(mpt_vol->sync_progress.TotalBlocks);
1379b0a2fdeeSScott Long 		if (vol_pg->ResyncRate != 0) {
1380b0a2fdeeSScott Long 
1381b0a2fdeeSScott Long 			prio = ((u_int)vol_pg->ResyncRate * 100000) / 0xFF;
1382b0a2fdeeSScott Long 			mpt_vol_prt(mpt, mpt_vol, "Rate %d.%d%%\n",
1383b0a2fdeeSScott Long 			    prio / 1000, prio % 1000);
1384b0a2fdeeSScott Long 		} else {
1385b0a2fdeeSScott Long 			prio = vol_pg->VolumeSettings.Settings
1386b0a2fdeeSScott Long 			     & MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC;
1387b0a2fdeeSScott Long 			mpt_vol_prt(mpt, mpt_vol, "%s Priority Re-Sync\n",
1388b0a2fdeeSScott Long 			    prio ? "High" : "Low");
1389b0a2fdeeSScott Long 		}
1390c87e3f83SMatt Jacob #if __FreeBSD_version >= 500000
1391b0a2fdeeSScott Long 		mpt_vol_prt(mpt, mpt_vol, "%ju of %ju "
1392b0a2fdeeSScott Long 			    "blocks remaining\n", (uintmax_t)left,
1393b0a2fdeeSScott Long 			    (uintmax_t)total);
1394c87e3f83SMatt Jacob #else
1395c87e3f83SMatt Jacob 		mpt_vol_prt(mpt, mpt_vol, "%llu of %llu "
1396c87e3f83SMatt Jacob 			    "blocks remaining\n", (uint64_t)left,
1397c87e3f83SMatt Jacob 			    (uint64_t)total);
1398c87e3f83SMatt Jacob #endif
1399b0a2fdeeSScott Long 
1400b0a2fdeeSScott Long 		/* Periodically report on sync progress. */
1401b0a2fdeeSScott Long 		mpt_schedule_raid_refresh(mpt);
1402b0a2fdeeSScott Long 	}
1403b0a2fdeeSScott Long 
1404b0a2fdeeSScott Long 	for (i = 0; i < mpt->ioc_page2->MaxPhysDisks; i++) {
1405b0a2fdeeSScott Long 		struct mpt_raid_disk *mpt_disk;
1406b0a2fdeeSScott Long 		CONFIG_PAGE_RAID_PHYS_DISK_0 *disk_pg;
1407b0a2fdeeSScott Long 		int m;
1408b0a2fdeeSScott Long 
1409b0a2fdeeSScott Long 		mpt_disk = &mpt->raid_disks[i];
1410b0a2fdeeSScott Long 		disk_pg = &mpt_disk->config_page;
1411b0a2fdeeSScott Long 
1412b0a2fdeeSScott Long 		if ((mpt_disk->flags & MPT_RDF_ACTIVE) == 0)
1413b0a2fdeeSScott Long 			continue;
1414b0a2fdeeSScott Long 
1415b0a2fdeeSScott Long 		if ((mpt_disk->flags & (MPT_RDF_REFERENCED|MPT_RDF_ANNOUNCED))
1416b0a2fdeeSScott Long 		 == MPT_RDF_ANNOUNCED) {
1417b0a2fdeeSScott Long 			mpt_disk_prt(mpt, mpt_disk, "No longer configured\n");
1418b0a2fdeeSScott Long 			mpt_disk->flags = 0;
1419b0a2fdeeSScott Long 			mpt->raid_rescan++;
1420b0a2fdeeSScott Long 			continue;
1421b0a2fdeeSScott Long 		}
1422b0a2fdeeSScott Long 
1423b0a2fdeeSScott Long 		if ((mpt_disk->flags & MPT_RDF_ANNOUNCED) == 0) {
1424b0a2fdeeSScott Long 
1425b0a2fdeeSScott Long 			mpt_announce_disk(mpt, mpt_disk);
1426b0a2fdeeSScott Long 			mpt_disk->flags |= MPT_RVF_ANNOUNCED;
1427b0a2fdeeSScott Long 		}
1428b0a2fdeeSScott Long 
1429b0a2fdeeSScott Long 		if ((mpt_disk->flags & MPT_RDF_UP2DATE) != 0)
1430b0a2fdeeSScott Long 			continue;
1431b0a2fdeeSScott Long 
1432b0a2fdeeSScott Long 		mpt_disk->flags |= MPT_RDF_UP2DATE;
1433b0a2fdeeSScott Long 		mpt_disk_prt(mpt, mpt_disk, "%s\n", mpt_disk_state(mpt_disk));
1434b0a2fdeeSScott Long 		if (disk_pg->PhysDiskStatus.Flags == 0)
1435b0a2fdeeSScott Long 			continue;
1436b0a2fdeeSScott Long 
1437b0a2fdeeSScott Long 		mpt_disk_prt(mpt, mpt_disk, "Status (");
1438b0a2fdeeSScott Long 		for (m = 1; m <= 0x80; m <<= 1) {
1439b0a2fdeeSScott Long 			switch (disk_pg->PhysDiskStatus.Flags & m) {
1440b0a2fdeeSScott Long 			case MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC:
1441b0a2fdeeSScott Long 				mpt_prtc(mpt, " Out-Of-Sync");
1442b0a2fdeeSScott Long 				break;
1443b0a2fdeeSScott Long 			case MPI_PHYSDISK0_STATUS_FLAG_QUIESCED:
1444b0a2fdeeSScott Long 				mpt_prtc(mpt, " Quiesced");
1445b0a2fdeeSScott Long 				break;
1446b0a2fdeeSScott Long 			default:
1447b0a2fdeeSScott Long 				break;
1448b0a2fdeeSScott Long 			}
1449b0a2fdeeSScott Long 		}
1450b0a2fdeeSScott Long 		mpt_prtc(mpt, " )\n");
1451b0a2fdeeSScott Long 	}
14525cc0208aSAlexander Kabaev 
14535cc0208aSAlexander Kabaev 	mpt->raid_nonopt_volumes = nonopt_volumes;
1454b0a2fdeeSScott Long }
1455b0a2fdeeSScott Long 
1456b0a2fdeeSScott Long static void
1457b0a2fdeeSScott Long mpt_raid_timer(void *arg)
1458b0a2fdeeSScott Long {
1459b0a2fdeeSScott Long 	struct mpt_softc *mpt;
1460b0a2fdeeSScott Long 
1461b0a2fdeeSScott Long 	mpt = (struct mpt_softc *)arg;
1462b0a2fdeeSScott Long 	MPT_LOCK(mpt);
1463b0a2fdeeSScott Long 	mpt_raid_wakeup(mpt);
1464b0a2fdeeSScott Long 	MPT_UNLOCK(mpt);
1465b0a2fdeeSScott Long }
1466b0a2fdeeSScott Long 
1467b0a2fdeeSScott Long static void
1468b0a2fdeeSScott Long mpt_raid_quiesce_timeout(void *arg)
1469b0a2fdeeSScott Long {
1470b0a2fdeeSScott Long 	/* Complete the CCB with error */
1471b0a2fdeeSScott Long 	/* COWWWW */
1472b0a2fdeeSScott Long }
1473b0a2fdeeSScott Long 
1474b0a2fdeeSScott Long void
1475b0a2fdeeSScott Long mpt_schedule_raid_refresh(struct mpt_softc *mpt)
1476b0a2fdeeSScott Long {
1477b0a2fdeeSScott Long 	callout_reset(&mpt->raid_timer, MPT_RAID_SYNC_REPORT_INTERVAL,
1478b0a2fdeeSScott Long 		      mpt_raid_timer, mpt);
1479b0a2fdeeSScott Long }
1480b0a2fdeeSScott Long 
1481b0a2fdeeSScott Long static int
1482b0a2fdeeSScott Long mpt_raid_set_vol_resync_rate(struct mpt_softc *mpt, u_int rate)
1483b0a2fdeeSScott Long {
1484b0a2fdeeSScott Long 	struct mpt_raid_volume *mpt_vol;
1485b0a2fdeeSScott Long 
1486b0a2fdeeSScott Long 	if ((rate > MPT_RAID_RESYNC_RATE_MAX
1487b0a2fdeeSScott Long 	  || rate < MPT_RAID_RESYNC_RATE_MIN)
1488b0a2fdeeSScott Long 	 && rate != MPT_RAID_RESYNC_RATE_NC)
1489b0a2fdeeSScott Long 		return (EINVAL);
1490b0a2fdeeSScott Long 
1491b0a2fdeeSScott Long 	MPT_LOCK(mpt);
1492b0a2fdeeSScott Long 	mpt->raid_resync_rate = rate;
1493b0a2fdeeSScott Long 	RAID_VOL_FOREACH(mpt, mpt_vol) {
1494c87e3f83SMatt Jacob 		if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0) {
1495b0a2fdeeSScott Long 			continue;
1496c87e3f83SMatt Jacob 		}
1497b0a2fdeeSScott Long 		mpt_verify_resync_rate(mpt, mpt_vol);
1498b0a2fdeeSScott Long 	}
1499b0a2fdeeSScott Long 	MPT_UNLOCK(mpt);
1500b0a2fdeeSScott Long 	return (0);
1501b0a2fdeeSScott Long }
1502b0a2fdeeSScott Long 
1503b0a2fdeeSScott Long static int
1504b0a2fdeeSScott Long mpt_raid_set_vol_queue_depth(struct mpt_softc *mpt, u_int vol_queue_depth)
1505b0a2fdeeSScott Long {
1506b0a2fdeeSScott Long 	struct mpt_raid_volume *mpt_vol;
1507b0a2fdeeSScott Long 
1508c87e3f83SMatt Jacob 	if (vol_queue_depth > 255 || vol_queue_depth < 1)
1509b0a2fdeeSScott Long 		return (EINVAL);
1510b0a2fdeeSScott Long 
1511b0a2fdeeSScott Long 	MPT_LOCK(mpt);
1512b0a2fdeeSScott Long 	mpt->raid_queue_depth = vol_queue_depth;
1513b0a2fdeeSScott Long 	RAID_VOL_FOREACH(mpt, mpt_vol) {
1514b0a2fdeeSScott Long 		struct cam_path *path;
1515b0a2fdeeSScott Long 		int error;
1516b0a2fdeeSScott Long 
1517b0a2fdeeSScott Long 		if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0)
1518b0a2fdeeSScott Long 			continue;
1519b0a2fdeeSScott Long 
1520b0a2fdeeSScott Long 		mpt->raid_rescan = 0;
1521b0a2fdeeSScott Long 
1522b0a2fdeeSScott Long 		error = xpt_create_path(&path, xpt_periph,
1523b0a2fdeeSScott Long 					cam_sim_path(mpt->sim),
1524b0a2fdeeSScott Long 					mpt_vol->config_page->VolumeID,
1525b0a2fdeeSScott Long 					/*lun*/0);
1526b0a2fdeeSScott Long 		if (error != CAM_REQ_CMP) {
1527b0a2fdeeSScott Long 			mpt_vol_prt(mpt, mpt_vol, "Unable to allocate path!\n");
1528b0a2fdeeSScott Long 			continue;
1529b0a2fdeeSScott Long 		}
1530b0a2fdeeSScott Long 		mpt_adjust_queue_depth(mpt, mpt_vol, path);
1531b0a2fdeeSScott Long 		xpt_free_path(path);
1532b0a2fdeeSScott Long 	}
1533b0a2fdeeSScott Long 	MPT_UNLOCK(mpt);
1534b0a2fdeeSScott Long 	return (0);
1535b0a2fdeeSScott Long }
1536b0a2fdeeSScott Long 
1537b0a2fdeeSScott Long static int
1538b0a2fdeeSScott Long mpt_raid_set_vol_mwce(struct mpt_softc *mpt, mpt_raid_mwce_t mwce)
1539b0a2fdeeSScott Long {
1540b0a2fdeeSScott Long 	struct mpt_raid_volume *mpt_vol;
1541b0a2fdeeSScott Long 	int force_full_resync;
1542b0a2fdeeSScott Long 
1543b0a2fdeeSScott Long 	MPT_LOCK(mpt);
1544b0a2fdeeSScott Long 	if (mwce == mpt->raid_mwce_setting) {
1545b0a2fdeeSScott Long 		MPT_UNLOCK(mpt);
1546b0a2fdeeSScott Long 		return (0);
1547b0a2fdeeSScott Long 	}
1548b0a2fdeeSScott Long 
1549b0a2fdeeSScott Long 	/*
1550b0a2fdeeSScott Long 	 * Catch MWCE being left on due to a failed shutdown.  Since
1551b0a2fdeeSScott Long 	 * sysctls cannot be set by the loader, we treat the first
1552b0a2fdeeSScott Long 	 * setting of this varible specially and force a full volume
1553b0a2fdeeSScott Long 	 * resync if MWCE is enabled and a resync is in progress.
1554b0a2fdeeSScott Long 	 */
1555b0a2fdeeSScott Long 	force_full_resync = 0;
1556b0a2fdeeSScott Long 	if (mpt->raid_mwce_set == 0
1557b0a2fdeeSScott Long 	 && mpt->raid_mwce_setting == MPT_RAID_MWCE_NC
1558b0a2fdeeSScott Long 	 && mwce == MPT_RAID_MWCE_REBUILD_ONLY)
1559b0a2fdeeSScott Long 		force_full_resync = 1;
1560b0a2fdeeSScott Long 
1561b0a2fdeeSScott Long 	mpt->raid_mwce_setting = mwce;
1562b0a2fdeeSScott Long 	RAID_VOL_FOREACH(mpt, mpt_vol) {
1563b0a2fdeeSScott Long 		CONFIG_PAGE_RAID_VOL_0 *vol_pg;
1564b0a2fdeeSScott Long 		int resyncing;
1565b0a2fdeeSScott Long 		int mwce;
1566b0a2fdeeSScott Long 
1567b0a2fdeeSScott Long 		if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0)
1568b0a2fdeeSScott Long 			continue;
1569b0a2fdeeSScott Long 
1570b0a2fdeeSScott Long 		vol_pg = mpt_vol->config_page;
1571b0a2fdeeSScott Long 		resyncing = vol_pg->VolumeStatus.Flags
1572b0a2fdeeSScott Long 			  & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS;
1573b0a2fdeeSScott Long 		mwce = vol_pg->VolumeSettings.Settings
1574b0a2fdeeSScott Long 		     & MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
1575b0a2fdeeSScott Long 		if (force_full_resync && resyncing && mwce) {
1576b0a2fdeeSScott Long 
1577b0a2fdeeSScott Long 			/*
1578b0a2fdeeSScott Long 			 * XXX disable/enable volume should force a resync,
1579b0a2fdeeSScott Long 			 *     but we'll need to queice, drain, and restart
1580b0a2fdeeSScott Long 			 *     I/O to do that.
1581b0a2fdeeSScott Long 			 */
1582b0a2fdeeSScott Long 			mpt_vol_prt(mpt, mpt_vol, "WARNING - Unsafe shutdown "
1583b0a2fdeeSScott Long 				    "detected.  Suggest full resync.\n");
1584b0a2fdeeSScott Long 		}
1585b0a2fdeeSScott Long 		mpt_verify_mwce(mpt, mpt_vol);
1586b0a2fdeeSScott Long 	}
1587b0a2fdeeSScott Long 	mpt->raid_mwce_set = 1;
1588b0a2fdeeSScott Long 	MPT_UNLOCK(mpt);
1589b0a2fdeeSScott Long 	return (0);
1590b0a2fdeeSScott Long }
1591b0a2fdeeSScott Long 
1592b0a2fdeeSScott Long const char *mpt_vol_mwce_strs[] =
1593b0a2fdeeSScott Long {
1594b0a2fdeeSScott Long 	"On",
1595b0a2fdeeSScott Long 	"Off",
1596b0a2fdeeSScott Long 	"On-During-Rebuild",
1597b0a2fdeeSScott Long 	"NC"
1598b0a2fdeeSScott Long };
1599b0a2fdeeSScott Long 
1600b0a2fdeeSScott Long static int
1601b0a2fdeeSScott Long mpt_raid_sysctl_vol_member_wce(SYSCTL_HANDLER_ARGS)
1602b0a2fdeeSScott Long {
1603b0a2fdeeSScott Long 	char inbuf[20];
1604b0a2fdeeSScott Long 	struct mpt_softc *mpt;
1605b0a2fdeeSScott Long 	const char *str;
1606b0a2fdeeSScott Long 	int error;
1607b0a2fdeeSScott Long 	u_int size;
1608b0a2fdeeSScott Long 	u_int i;
1609b0a2fdeeSScott Long 
1610b0a2fdeeSScott Long 	GIANT_REQUIRED;
1611b0a2fdeeSScott Long 	mpt = (struct mpt_softc *)arg1;
1612b0a2fdeeSScott Long 	str = mpt_vol_mwce_strs[mpt->raid_mwce_setting];
1613b0a2fdeeSScott Long 	error = SYSCTL_OUT(req, str, strlen(str) + 1);
1614b0a2fdeeSScott Long 	if (error || !req->newptr)
1615b0a2fdeeSScott Long 		return (error);
1616b0a2fdeeSScott Long 
1617b0a2fdeeSScott Long 	size = req->newlen - req->newidx;
1618b0a2fdeeSScott Long 	if (size >= sizeof(inbuf))
1619b0a2fdeeSScott Long 		return (EINVAL);
1620b0a2fdeeSScott Long 
1621b0a2fdeeSScott Long 	error = SYSCTL_IN(req, inbuf, size);
1622b0a2fdeeSScott Long 	if (error)
1623b0a2fdeeSScott Long 		return (error);
1624b0a2fdeeSScott Long 	inbuf[size] = '\0';
1625b0a2fdeeSScott Long 	for (i = 0; i < NUM_ELEMENTS(mpt_vol_mwce_strs); i++) {
1626b0a2fdeeSScott Long 
1627b0a2fdeeSScott Long 		if (strcmp(mpt_vol_mwce_strs[i], inbuf) == 0)
1628b0a2fdeeSScott Long 			return (mpt_raid_set_vol_mwce(mpt, i));
1629b0a2fdeeSScott Long 	}
1630b0a2fdeeSScott Long 	return (EINVAL);
1631b0a2fdeeSScott Long }
1632b0a2fdeeSScott Long 
1633b0a2fdeeSScott Long static int
1634b0a2fdeeSScott Long mpt_raid_sysctl_vol_resync_rate(SYSCTL_HANDLER_ARGS)
1635b0a2fdeeSScott Long {
1636b0a2fdeeSScott Long 	struct mpt_softc *mpt;
1637b0a2fdeeSScott Long 	u_int raid_resync_rate;
1638b0a2fdeeSScott Long 	int error;
1639b0a2fdeeSScott Long 
1640b0a2fdeeSScott Long 	GIANT_REQUIRED;
1641b0a2fdeeSScott Long 	mpt = (struct mpt_softc *)arg1;
1642b0a2fdeeSScott Long 	raid_resync_rate = mpt->raid_resync_rate;
1643b0a2fdeeSScott Long 
1644b0a2fdeeSScott Long 	error = sysctl_handle_int(oidp, &raid_resync_rate, 0, req);
1645b0a2fdeeSScott Long 	if (error || !req->newptr)
1646b0a2fdeeSScott Long 		return error;
1647b0a2fdeeSScott Long 
1648b0a2fdeeSScott Long 	return (mpt_raid_set_vol_resync_rate(mpt, raid_resync_rate));
1649b0a2fdeeSScott Long }
1650b0a2fdeeSScott Long 
1651b0a2fdeeSScott Long static int
1652b0a2fdeeSScott Long mpt_raid_sysctl_vol_queue_depth(SYSCTL_HANDLER_ARGS)
1653b0a2fdeeSScott Long {
1654b0a2fdeeSScott Long 	struct mpt_softc *mpt;
1655b0a2fdeeSScott Long 	u_int raid_queue_depth;
1656b0a2fdeeSScott Long 	int error;
1657b0a2fdeeSScott Long 
1658b0a2fdeeSScott Long 	GIANT_REQUIRED;
1659b0a2fdeeSScott Long 	mpt = (struct mpt_softc *)arg1;
1660b0a2fdeeSScott Long 	raid_queue_depth = mpt->raid_queue_depth;
1661b0a2fdeeSScott Long 
1662b0a2fdeeSScott Long 	error = sysctl_handle_int(oidp, &raid_queue_depth, 0, req);
1663b0a2fdeeSScott Long 	if (error || !req->newptr)
1664b0a2fdeeSScott Long 		return error;
1665b0a2fdeeSScott Long 
1666b0a2fdeeSScott Long 	return (mpt_raid_set_vol_queue_depth(mpt, raid_queue_depth));
1667b0a2fdeeSScott Long }
1668b0a2fdeeSScott Long 
1669b0a2fdeeSScott Long static void
1670b0a2fdeeSScott Long mpt_raid_sysctl_attach(struct mpt_softc *mpt)
1671b0a2fdeeSScott Long {
1672c87e3f83SMatt Jacob #if __FreeBSD_version >= 500000
1673b0a2fdeeSScott Long 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(mpt->dev);
1674b0a2fdeeSScott Long 	struct sysctl_oid *tree = device_get_sysctl_tree(mpt->dev);
1675b0a2fdeeSScott Long 
1676b0a2fdeeSScott Long 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1677b0a2fdeeSScott Long 			"vol_member_wce", CTLTYPE_STRING | CTLFLAG_RW, mpt, 0,
1678b0a2fdeeSScott Long 			mpt_raid_sysctl_vol_member_wce, "A",
1679b0a2fdeeSScott Long 			"volume member WCE(On,Off,On-During-Rebuild,NC)");
1680b0a2fdeeSScott Long 
1681b0a2fdeeSScott Long 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1682b0a2fdeeSScott Long 			"vol_queue_depth", CTLTYPE_INT | CTLFLAG_RW, mpt, 0,
1683b0a2fdeeSScott Long 			mpt_raid_sysctl_vol_queue_depth, "I",
1684b0a2fdeeSScott Long 			"default volume queue depth");
1685b0a2fdeeSScott Long 
1686b0a2fdeeSScott Long 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1687b0a2fdeeSScott Long 			"vol_resync_rate", CTLTYPE_INT | CTLFLAG_RW, mpt, 0,
1688b0a2fdeeSScott Long 			mpt_raid_sysctl_vol_resync_rate, "I",
1689b0a2fdeeSScott Long 			"volume resync priority (0 == NC, 1 - 255)");
16905cc0208aSAlexander Kabaev 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
16915cc0208aSAlexander Kabaev 			"nonoptimal_volumes", CTLFLAG_RD,
16925cc0208aSAlexander Kabaev 			&mpt->raid_nonopt_volumes, 0,
16935cc0208aSAlexander Kabaev 			"number of nonoptimal volumes");
1694c87e3f83SMatt Jacob #endif
1695b0a2fdeeSScott Long }
1696