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