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