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