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