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