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