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