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