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