xref: /netbsd-src/sys/dev/ic/mlx.c (revision c71562d660be5e4ad22016bce45e96f08af190cc)
1 /*	$NetBSD: mlx.c,v 1.42 2006/04/14 21:06:47 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are 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 the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*-
40  * Copyright (c) 1999 Michael Smith
41  * All rights reserved.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  *
64  * from FreeBSD: mlx.c,v 1.14.2.3 2000/08/04 06:52:50 msmith Exp
65  */
66 
67 /*
68  * Driver for the Mylex DAC960 family of RAID controllers.
69  *
70  * TODO:
71  *
72  * o Test and enable channel pause.
73  * o SCSI pass-through.
74  */
75 
76 #include <sys/cdefs.h>
77 __KERNEL_RCSID(0, "$NetBSD: mlx.c,v 1.42 2006/04/14 21:06:47 christos Exp $");
78 
79 #include "ld.h"
80 
81 #include <sys/param.h>
82 #include <sys/systm.h>
83 #include <sys/kernel.h>
84 #include <sys/device.h>
85 #include <sys/queue.h>
86 #include <sys/proc.h>
87 #include <sys/buf.h>
88 #include <sys/bufq.h>
89 #include <sys/endian.h>
90 #include <sys/malloc.h>
91 #include <sys/conf.h>
92 #include <sys/kthread.h>
93 #include <sys/disk.h>
94 
95 #include <machine/vmparam.h>
96 #include <machine/bus.h>
97 
98 #include <uvm/uvm_extern.h>
99 
100 #include <dev/ldvar.h>
101 
102 #include <dev/ic/mlxreg.h>
103 #include <dev/ic/mlxio.h>
104 #include <dev/ic/mlxvar.h>
105 
106 #include "locators.h"
107 
108 #define	MLX_TIMEOUT	60
109 
110 #ifdef DIAGNOSTIC
111 #define	DPRINTF(x)	printf x
112 #else
113 #define	DPRINTF(x)
114 #endif
115 
116 static void	mlx_adjqparam(struct mlx_softc *, int, int);
117 static int	mlx_ccb_submit(struct mlx_softc *, struct mlx_ccb *);
118 static int	mlx_check(struct mlx_softc *, int);
119 static void	mlx_configure(struct mlx_softc *, int);
120 static void	mlx_describe(struct mlx_softc *);
121 static void	*mlx_enquire(struct mlx_softc *, int, size_t,
122 			     void (*)(struct mlx_ccb *), int);
123 static int	mlx_fw_message(struct mlx_softc *, int, int, int);
124 static void	mlx_pause_action(struct mlx_softc *);
125 static void	mlx_pause_done(struct mlx_ccb *);
126 static void	mlx_periodic(struct mlx_softc *);
127 static void	mlx_periodic_create(void *);
128 static void	mlx_periodic_enquiry(struct mlx_ccb *);
129 static void	mlx_periodic_eventlog_poll(struct mlx_softc *);
130 static void	mlx_periodic_eventlog_respond(struct mlx_ccb *);
131 static void	mlx_periodic_rebuild(struct mlx_ccb *);
132 static void	mlx_periodic_thread(void *);
133 static int	mlx_print(void *, const char *);
134 static int	mlx_rebuild(struct mlx_softc *, int, int);
135 static void	mlx_shutdown(void *);
136 static int	mlx_user_command(struct mlx_softc *, struct mlx_usercommand *);
137 
138 static inline time_t	mlx_curtime(void);
139 
140 dev_type_open(mlxopen);
141 dev_type_close(mlxclose);
142 dev_type_ioctl(mlxioctl);
143 
144 const struct cdevsw mlx_cdevsw = {
145 	mlxopen, mlxclose, noread, nowrite, mlxioctl,
146 	nostop, notty, nopoll, nommap, nokqfilter,
147 };
148 
149 extern struct	cfdriver mlx_cd;
150 static struct	proc *mlx_periodic_proc;
151 static void	*mlx_sdh;
152 
153 struct {
154 	int	hwid;
155 	const char	*name;
156 } static const mlx_cname[] = {
157 	{ 0x00, "960E/960M" },
158 	{ 0x01, "960P/PD" },
159 	{ 0x02,	"960PL" },
160 	{ 0x10, "960PG" },
161 	{ 0x11, "960PJ" },
162 	{ 0x12, "960PR" },
163 	{ 0x13,	"960PT" },
164 	{ 0x14, "960PTL0" },
165 	{ 0x15, "960PRL" },
166 	{ 0x16, "960PTL1" },
167 	{ 0x20, "1164PVX" },
168 };
169 
170 static const char * const mlx_sense_msgs[] = {
171 	"because write recovery failed",
172 	"because of SCSI bus reset failure",
173 	"because of double check condition",
174 	"because it was removed",
175 	"because of gross error on SCSI chip",
176 	"because of bad tag returned from drive",
177 	"because of timeout on SCSI command",
178 	"because of reset SCSI command issued from system",
179 	"because busy or parity error count exceeded limit",
180 	"because of 'kill drive' command from system",
181 	"because of selection timeout",
182 	"due to SCSI phase sequence error",
183 	"due to unknown status"
184 };
185 
186 static const char * const mlx_status_msgs[] = {
187 	"normal completion",				/* 0 */
188 	"irrecoverable data error",			/* 1 */
189 	"drive does not exist, or is offline",		/* 2 */
190 	"attempt to write beyond end of drive",		/* 3 */
191 	"bad data encountered",				/* 4 */
192 	"invalid log entry request",			/* 5 */
193 	"attempt to rebuild online drive",		/* 6 */
194 	"new disk failed during rebuild",		/* 7 */
195 	"invalid channel/target",			/* 8 */
196 	"rebuild/check already in progress",		/* 9 */
197 	"one or more disks are dead",			/* 10 */
198 	"invalid or non-redundant drive",		/* 11 */
199 	"channel is busy",				/* 12 */
200 	"channel is not stopped",			/* 13 */
201 	"rebuild successfully terminated",		/* 14 */
202 	"unsupported command",				/* 15 */
203 	"check condition received",			/* 16 */
204 	"device is busy",				/* 17 */
205 	"selection or command timeout",			/* 18 */
206 	"command terminated abnormally",		/* 19 */
207 	"controller wedged",				/* 20 */
208 	"software timeout",				/* 21 */
209 	"command busy (?)",				/* 22 */
210 };
211 
212 struct {
213 	u_char	command;
214 	u_char	msg;		/* Index into mlx_status_msgs[]. */
215 	u_short	status;
216 } static const mlx_msgs[] = {
217 	{ MLX_CMD_READSG,	1,	0x0001 },
218 	{ MLX_CMD_READSG,	1,	0x0002 },
219 	{ MLX_CMD_READSG,	3,	0x0105 },
220 	{ MLX_CMD_READSG,	4,	0x010c },
221 	{ MLX_CMD_WRITESG,	1,	0x0001 },
222 	{ MLX_CMD_WRITESG,	1,	0x0002 },
223 	{ MLX_CMD_WRITESG,	3,	0x0105 },
224 	{ MLX_CMD_READSG_OLD,	1,	0x0001 },
225 	{ MLX_CMD_READSG_OLD,	1,	0x0002 },
226 	{ MLX_CMD_READSG_OLD,	3,	0x0105 },
227 	{ MLX_CMD_WRITESG_OLD,	1,	0x0001 },
228 	{ MLX_CMD_WRITESG_OLD,	1,	0x0002 },
229 	{ MLX_CMD_WRITESG_OLD,	3,	0x0105 },
230 	{ MLX_CMD_LOGOP,	5,	0x0105 },
231 	{ MLX_CMD_REBUILDASYNC,	6,	0x0002 },
232 	{ MLX_CMD_REBUILDASYNC,	7,	0x0004 },
233 	{ MLX_CMD_REBUILDASYNC,	8,	0x0105 },
234 	{ MLX_CMD_REBUILDASYNC,	9,	0x0106 },
235 	{ MLX_CMD_REBUILDASYNC,	14,	0x0107 },
236 	{ MLX_CMD_CHECKASYNC,	10,	0x0002 },
237 	{ MLX_CMD_CHECKASYNC,	11,	0x0105 },
238 	{ MLX_CMD_CHECKASYNC,	9,	0x0106 },
239 	{ MLX_CMD_STOPCHANNEL,	12,	0x0106 },
240 	{ MLX_CMD_STOPCHANNEL,	8,	0x0105 },
241 	{ MLX_CMD_STARTCHANNEL,	13,	0x0005 },
242 	{ MLX_CMD_STARTCHANNEL,	8,	0x0105 },
243 	{ MLX_CMD_DIRECT_CDB,	16,	0x0002 },
244 	{ MLX_CMD_DIRECT_CDB,	17,	0x0008 },
245 	{ MLX_CMD_DIRECT_CDB,	18,	0x000e },
246 	{ MLX_CMD_DIRECT_CDB,	19,	0x000f },
247 	{ MLX_CMD_DIRECT_CDB,	8,	0x0105 },
248 
249 	{ 0,			20,	MLX_STATUS_WEDGED },
250 	{ 0,			21,	MLX_STATUS_LOST },
251 	{ 0,			22,	MLX_STATUS_BUSY },
252 
253 	{ 0,			14,	0x0104 },
254 };
255 
256 /*
257  * Return the current time in seconds - we're not particularly interested in
258  * precision here.
259  */
260 static inline time_t
261 mlx_curtime(void)
262 {
263 	time_t rt;
264 	int s;
265 
266 	s = splclock();
267 	rt = mono_time.tv_sec;
268 	splx(s);
269 
270 	return (rt);
271 }
272 
273 /*
274  * Initialise the controller and our interface.
275  */
276 void
277 mlx_init(struct mlx_softc *mlx, const char *intrstr)
278 {
279 	struct mlx_ccb *mc;
280 	struct mlx_enquiry_old *meo;
281 	struct mlx_enquiry2 *me2;
282 	struct mlx_cinfo *ci;
283 	int rv, fwminor, hscode, hserr, hsparam1, hsparam2, hsmsg;
284 	int size, i, rseg;
285 	const char *wantfwstr;
286 	bus_dma_segment_t seg;
287 
288 	SIMPLEQ_INIT(&mlx->mlx_ccb_queue);
289 	SLIST_INIT(&mlx->mlx_ccb_freelist);
290 	TAILQ_INIT(&mlx->mlx_ccb_worklist);
291 
292 	if (intrstr != NULL)
293 		printf("%s: interrupting at %s\n", mlx->mlx_dv.dv_xname,
294 		    intrstr);
295 
296 	/*
297 	 * Allocate the scatter/gather lists.
298 	 */
299         size = MLX_SGL_SIZE * MLX_MAX_QUEUECNT;
300 
301 	if ((rv = bus_dmamem_alloc(mlx->mlx_dmat, size, PAGE_SIZE, 0, &seg, 1,
302 	    &rseg, BUS_DMA_NOWAIT)) != 0) {
303 		printf("%s: unable to allocate sglists, rv = %d\n",
304 		    mlx->mlx_dv.dv_xname, rv);
305 		return;
306 	}
307 
308 	if ((rv = bus_dmamem_map(mlx->mlx_dmat, &seg, rseg, size,
309 	    (caddr_t *)&mlx->mlx_sgls,
310 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
311 		printf("%s: unable to map sglists, rv = %d\n",
312 		    mlx->mlx_dv.dv_xname, rv);
313 		return;
314 	}
315 
316 	if ((rv = bus_dmamap_create(mlx->mlx_dmat, size, 1, size, 0,
317 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mlx->mlx_dmamap)) != 0) {
318 		printf("%s: unable to create sglist DMA map, rv = %d\n",
319 		    mlx->mlx_dv.dv_xname, rv);
320 		return;
321 	}
322 
323 	if ((rv = bus_dmamap_load(mlx->mlx_dmat, mlx->mlx_dmamap,
324 	    mlx->mlx_sgls, size, NULL, BUS_DMA_NOWAIT)) != 0) {
325 		printf("%s: unable to load sglist DMA map, rv = %d\n",
326 		    mlx->mlx_dv.dv_xname, rv);
327 		return;
328 	}
329 
330 	mlx->mlx_sgls_paddr = mlx->mlx_dmamap->dm_segs[0].ds_addr;
331 	memset(mlx->mlx_sgls, 0, size);
332 
333 	/*
334 	 * Allocate and initialize the CCBs.
335 	 */
336 	mc = malloc(sizeof(*mc) * MLX_MAX_QUEUECNT, M_DEVBUF, M_NOWAIT);
337 	mlx->mlx_ccbs = mc;
338 
339 	for (i = 0; i < MLX_MAX_QUEUECNT; i++, mc++) {
340 		mc->mc_ident = i;
341 		rv = bus_dmamap_create(mlx->mlx_dmat, MLX_MAX_XFER,
342 		    MLX_MAX_SEGS, MLX_MAX_XFER, 0,
343 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
344 		    &mc->mc_xfer_map);
345 		if (rv != 0)
346 			break;
347 		mlx->mlx_nccbs++;
348 		mlx_ccb_free(mlx, mc);
349 	}
350 	if (mlx->mlx_nccbs != MLX_MAX_QUEUECNT)
351 		printf("%s: %d/%d CCBs usable\n", mlx->mlx_dv.dv_xname,
352 		    mlx->mlx_nccbs, MLX_MAX_QUEUECNT);
353 
354 	/* Disable interrupts before we start talking to the controller */
355 	(*mlx->mlx_intaction)(mlx, 0);
356 
357 	/* If we've got a reset routine, then reset the controller now. */
358 	if (mlx->mlx_reset != NULL) {
359 		printf("%s: resetting controller...\n", mlx->mlx_dv.dv_xname);
360 		if ((*mlx->mlx_reset)(mlx) != 0) {
361 			printf("%s: reset failed\n", mlx->mlx_dv.dv_xname);
362 			return;
363 		}
364 	}
365 
366 	/*
367 	 * Wait for the controller to come ready, handshaking with the
368 	 * firmware if required.  This is typically only necessary on
369 	 * platforms where the controller BIOS does not run.
370 	 */
371 	hsmsg = 0;
372 
373 	for (;;) {
374 		hscode = (*mlx->mlx_fw_handshake)(mlx, &hserr, &hsparam1,
375 		    &hsparam2);
376 		if (hscode == 0) {
377 			if (hsmsg != 0)
378 				printf("%s: initialization complete\n",
379 				    mlx->mlx_dv.dv_xname);
380 			break;
381 		}
382 
383 		/* Report first time around... */
384 		if (hsmsg == 0) {
385 			printf("%s: initializing (may take some time)...\n",
386 			    mlx->mlx_dv.dv_xname);
387 			hsmsg = 1;
388 		}
389 
390 		/* Did we get a real message? */
391 		if (hscode == 2) {
392 			hscode = mlx_fw_message(mlx, hserr, hsparam1, hsparam2);
393 
394 			/* Fatal initialisation error? */
395 			if (hscode != 0)
396 				return;
397 		}
398 	}
399 
400 	/*
401 	 * Do quirk/feature related things.
402 	 */
403 	ci = &mlx->mlx_ci;
404 
405 	if (ci->ci_iftype > 1) {
406 		me2 = mlx_enquire(mlx, MLX_CMD_ENQUIRY2,
407 		    sizeof(struct mlx_enquiry2), NULL, 0);
408 		if (me2 == NULL) {
409 			printf("%s: ENQUIRY2 failed\n", mlx->mlx_dv.dv_xname);
410 			return;
411 		}
412 
413 		ci->ci_firmware_id[0] = me2->me_firmware_id[0];
414 		ci->ci_firmware_id[1] = me2->me_firmware_id[1];
415 		ci->ci_firmware_id[2] = me2->me_firmware_id[2];
416 		ci->ci_firmware_id[3] = me2->me_firmware_id[3];
417 		ci->ci_hardware_id = me2->me_hardware_id[0];
418 		ci->ci_mem_size = le32toh(me2->me_mem_size);
419 		ci->ci_max_sg = le16toh(me2->me_max_sg);
420 		ci->ci_max_commands = le16toh(me2->me_max_commands);
421 		ci->ci_nchan = me2->me_actual_channels;
422 
423 		free(me2, M_DEVBUF);
424 	}
425 
426 	if (ci->ci_iftype <= 2) {
427 		/*
428 		 * These controllers may not report the firmware version in
429 		 * the ENQUIRY2 response, or may not even support it.
430 		 */
431 		meo = mlx_enquire(mlx, MLX_CMD_ENQUIRY_OLD,
432 		    sizeof(struct mlx_enquiry_old), NULL, 0);
433 		if (meo == NULL) {
434 			printf("%s: ENQUIRY_OLD failed\n", mlx->mlx_dv.dv_xname);
435 			return;
436 		}
437 		ci->ci_firmware_id[0] = meo->me_fwmajor;
438 		ci->ci_firmware_id[1] = meo->me_fwminor;
439 		ci->ci_firmware_id[2] = 0;
440 		ci->ci_firmware_id[3] = '0';
441 
442 		if (ci->ci_iftype == 1) {
443 			ci->ci_hardware_id = 0;	/* XXX */
444 			ci->ci_mem_size = 0;	/* XXX */
445 			ci->ci_max_sg = 17;	/* XXX */
446 			ci->ci_max_commands = meo->me_max_commands;
447 		}
448 
449 		free(meo, M_DEVBUF);
450 	}
451 
452 	wantfwstr = NULL;
453 	fwminor = ci->ci_firmware_id[1];
454 
455 	switch (ci->ci_firmware_id[0]) {
456 	case 2:
457 		if (ci->ci_iftype == 1) {
458 			if (fwminor < 14)
459 				wantfwstr = "2.14";
460 		} else if (fwminor < 42)
461 			wantfwstr = "2.42";
462 		break;
463 
464 	case 3:
465 		if (fwminor < 51)
466 			wantfwstr = "3.51";
467 		break;
468 
469 	case 4:
470 		if (fwminor < 6)
471 			wantfwstr = "4.06";
472 		break;
473 
474 	case 5:
475 		if (fwminor < 7)
476 			wantfwstr = "5.07";
477 		break;
478 	}
479 
480 	/* Print a little information about the controller. */
481 	mlx_describe(mlx);
482 
483 	if (wantfwstr != NULL) {
484 		printf("%s: WARNING: this f/w revision is not recommended\n",
485 		    mlx->mlx_dv.dv_xname);
486 		printf("%s: WARNING: use revision %s or later\n",
487 		    mlx->mlx_dv.dv_xname, wantfwstr);
488 	}
489 
490 	/* We don't (yet) know where the event log is up to. */
491 	mlx->mlx_currevent = -1;
492 
493 	/* No user-requested background operation is in progress. */
494 	mlx->mlx_bg = 0;
495 	mlx->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE;
496 
497 	/* Set maximum number of queued commands for `regular' operations. */
498 	mlx->mlx_max_queuecnt =
499 	    min(ci->ci_max_commands, MLX_MAX_QUEUECNT) -
500 	    MLX_NCCBS_CONTROL;
501 #ifdef DIAGNOSTIC
502 	if (mlx->mlx_max_queuecnt < MLX_NCCBS_CONTROL + MLX_MAX_DRIVES)
503 		printf("%s: WARNING: few CCBs available\n",
504 		    mlx->mlx_dv.dv_xname);
505 	if (ci->ci_max_sg < MLX_MAX_SEGS) {
506 		printf("%s: oops, not enough S/G segments\n",
507 		    mlx->mlx_dv.dv_xname);
508 		return;
509 	}
510 #endif
511 
512 	if (mlx_sdh == NULL) {
513 		/*
514 		 * Set our `shutdownhook' before we start any device
515 		 * activity.
516 		 */
517 		mlx_sdh = shutdownhook_establish(mlx_shutdown, NULL);
518 
519 		/* Arrange to create a status monitoring thread. */
520 		kthread_create(mlx_periodic_create, NULL);
521 	}
522 
523 	/* Finally, attach child devices and enable interrupts. */
524 	mlx_configure(mlx, 0);
525 	(*mlx->mlx_intaction)(mlx, 1);
526 
527 	mlx->mlx_flags |= MLXF_INITOK;
528 }
529 
530 /*
531  * Tell the world about the controller.
532  */
533 static void
534 mlx_describe(struct mlx_softc *mlx)
535 {
536 	struct mlx_cinfo *ci;
537 	static char tbuf[80];
538 	const char *model;
539 	int i;
540 
541 	model = NULL;
542 	ci = &mlx->mlx_ci;
543 
544 	for (i = 0; i < sizeof(mlx_cname) / sizeof(mlx_cname[0]); i++)
545 		if (ci->ci_hardware_id == mlx_cname[i].hwid) {
546 			model = mlx_cname[i].name;
547 			break;
548 		}
549 
550 	if (model == NULL) {
551 		snprintf(tbuf, sizeof(tbuf), " model 0x%x", ci->ci_hardware_id);
552 		model = tbuf;
553 	}
554 
555 	printf("%s: DAC%s, %d channel%s, firmware %d.%02d-%c-%02d",
556 	    mlx->mlx_dv.dv_xname, model, ci->ci_nchan,
557 	    ci->ci_nchan > 1 ? "s" : "",
558 	    ci->ci_firmware_id[0], ci->ci_firmware_id[1],
559 	    ci->ci_firmware_id[3], ci->ci_firmware_id[2]);
560 	if (ci->ci_mem_size != 0)
561 		printf(", %dMB RAM", ci->ci_mem_size >> 20);
562 	printf("\n");
563 }
564 
565 /*
566  * Locate disk resources and attach children to them.
567  */
568 static void
569 mlx_configure(struct mlx_softc *mlx, int waitok)
570 {
571 	struct mlx_enquiry *me;
572 	struct mlx_enquiry_old *meo;
573 	struct mlx_enq_sys_drive *mes;
574 	struct mlx_sysdrive *ms;
575 	struct mlx_attach_args mlxa;
576 	int i, nunits;
577 	u_int size;
578 	int locs[MLXCF_NLOCS];
579 
580 	mlx->mlx_flags |= MLXF_RESCANNING;
581 
582 	if (mlx->mlx_ci.ci_iftype <= 2) {
583 		meo = mlx_enquire(mlx, MLX_CMD_ENQUIRY_OLD,
584 		    sizeof(struct mlx_enquiry_old), NULL, waitok);
585 		if (meo == NULL) {
586 			printf("%s: ENQUIRY_OLD failed\n",
587 			    mlx->mlx_dv.dv_xname);
588 			goto out;
589 		}
590 		mlx->mlx_numsysdrives = meo->me_num_sys_drvs;
591 		free(meo, M_DEVBUF);
592 	} else {
593 		me = mlx_enquire(mlx, MLX_CMD_ENQUIRY,
594 		    sizeof(struct mlx_enquiry), NULL, waitok);
595 		if (me == NULL) {
596 			printf("%s: ENQUIRY failed\n", mlx->mlx_dv.dv_xname);
597 			goto out;
598 		}
599 		mlx->mlx_numsysdrives = me->me_num_sys_drvs;
600 		free(me, M_DEVBUF);
601 	}
602 
603 	mes = mlx_enquire(mlx, MLX_CMD_ENQSYSDRIVE,
604 	    sizeof(*mes) * MLX_MAX_DRIVES, NULL, waitok);
605 	if (mes == NULL) {
606 		printf("%s: error fetching drive status\n",
607 		    mlx->mlx_dv.dv_xname);
608 		goto out;
609 	}
610 
611 	/* Allow 1 queued command per unit while re-configuring. */
612 	mlx_adjqparam(mlx, 1, 0);
613 
614 	ms = &mlx->mlx_sysdrive[0];
615 	nunits = 0;
616 	for (i = 0; i < MLX_MAX_DRIVES; i++, ms++) {
617 		size = le32toh(mes[i].sd_size);
618 		ms->ms_state = mes[i].sd_state;
619 
620 		/*
621 		 * If an existing device has changed in some way (e.g. no
622 		 * longer present) then detach it.
623 		 */
624 		if (ms->ms_dv != NULL && (size != ms->ms_size ||
625 		    (mes[i].sd_raidlevel & 0xf) != ms->ms_raidlevel))
626 			config_detach(ms->ms_dv, DETACH_FORCE);
627 
628 		ms->ms_size = size;
629 		ms->ms_raidlevel = mes[i].sd_raidlevel & 0xf;
630 		ms->ms_state = mes[i].sd_state;
631 		ms->ms_dv = NULL;
632 
633 		if (i >= mlx->mlx_numsysdrives)
634 			continue;
635 		if (size == 0xffffffffU || size == 0)
636 			continue;
637 
638 		/*
639 		 * Attach a new device.
640 		 */
641 		mlxa.mlxa_unit = i;
642 
643 		locs[MLXCF_UNIT] = i;
644 
645 		ms->ms_dv = config_found_sm_loc(&mlx->mlx_dv, "mlx", locs,
646 				&mlxa, mlx_print, config_stdsubmatch);
647 		nunits += (ms->ms_dv != NULL);
648 	}
649 
650 	free(mes, M_DEVBUF);
651 
652 	if (nunits != 0)
653 		mlx_adjqparam(mlx, mlx->mlx_max_queuecnt / nunits,
654 		    mlx->mlx_max_queuecnt % nunits);
655  out:
656  	mlx->mlx_flags &= ~MLXF_RESCANNING;
657 }
658 
659 /*
660  * Print autoconfiguration message for a sub-device.
661  */
662 static int
663 mlx_print(void *aux, const char *pnp)
664 {
665 	struct mlx_attach_args *mlxa;
666 
667 	mlxa = (struct mlx_attach_args *)aux;
668 
669 	if (pnp != NULL)
670 		aprint_normal("block device at %s", pnp);
671 	aprint_normal(" unit %d", mlxa->mlxa_unit);
672 	return (UNCONF);
673 }
674 
675 /*
676  * Shut down all configured `mlx' devices.
677  */
678 static void
679 mlx_shutdown(void *cookie)
680 {
681 	struct mlx_softc *mlx;
682 	int i;
683 
684 	for (i = 0; i < mlx_cd.cd_ndevs; i++)
685 		if ((mlx = device_lookup(&mlx_cd, i)) != NULL)
686 			mlx_flush(mlx, 0);
687 }
688 
689 /*
690  * Adjust queue parameters for all child devices.
691  */
692 static void
693 mlx_adjqparam(struct mlx_softc *mlx, int mpu, int slop)
694 {
695 #if NLD > 0
696 	extern struct cfdriver ld_cd;
697 	struct ld_softc *ld;
698 	int i;
699 
700 	for (i = 0; i < ld_cd.cd_ndevs; i++) {
701 		if ((ld = device_lookup(&ld_cd, i)) == NULL)
702 			continue;
703 		if (device_parent(&ld->sc_dv) != &mlx->mlx_dv)
704 			continue;
705 		ldadjqparam(ld, mpu + (slop-- > 0));
706 	}
707 #endif
708 }
709 
710 /*
711  * Accept an open operation on the control device.
712  */
713 int
714 mlxopen(dev_t dev, int flag, int mode, struct lwp *l)
715 {
716 	struct mlx_softc *mlx;
717 
718 	if ((mlx = device_lookup(&mlx_cd, minor(dev))) == NULL)
719 		return (ENXIO);
720 	if ((mlx->mlx_flags & MLXF_INITOK) == 0)
721 		return (ENXIO);
722 	if ((mlx->mlx_flags & MLXF_OPEN) != 0)
723 		return (EBUSY);
724 
725 	mlx->mlx_flags |= MLXF_OPEN;
726 	return (0);
727 }
728 
729 /*
730  * Accept the last close on the control device.
731  */
732 int
733 mlxclose(dev_t dev, int flag, int mode, struct lwp *l)
734 {
735 	struct mlx_softc *mlx;
736 
737 	mlx = device_lookup(&mlx_cd, minor(dev));
738 	mlx->mlx_flags &= ~MLXF_OPEN;
739 	return (0);
740 }
741 
742 /*
743  * Handle control operations.
744  */
745 int
746 mlxioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l)
747 {
748 	struct mlx_softc *mlx;
749 	struct mlx_rebuild_request *rb;
750 	struct mlx_rebuild_status *rs;
751 	struct mlx_pause *mp;
752 	struct mlx_sysdrive *ms;
753 	int i, rv, *arg, result;
754 
755 	if (securelevel >= 2)
756 		return (EPERM);
757 
758 	mlx = device_lookup(&mlx_cd, minor(dev));
759 
760 	rb = (struct mlx_rebuild_request *)data;
761 	rs = (struct mlx_rebuild_status *)data;
762 	arg = (int *)data;
763 	rv = 0;
764 
765 	switch (cmd) {
766 	case MLX_RESCAN_DRIVES:
767 		/*
768 		 * Scan the controller to see whether new drives have
769 		 * appeared, or old ones disappeared.
770 		 */
771 		mlx_configure(mlx, 1);
772 		return (0);
773 
774 	case MLX_PAUSE_CHANNEL:
775 		/*
776 		 * Pause one or more SCSI channels for a period of time, to
777 		 * assist in the process of hot-swapping devices.
778 		 *
779 		 * Note that at least the 3.51 firmware on the DAC960PL
780 		 * doesn't seem to do this right.
781 		 */
782 		if ((mlx->mlx_flags & MLXF_PAUSEWORKS) == 0)
783 			return (EOPNOTSUPP);
784 
785 		mp = (struct mlx_pause *)data;
786 
787 		if ((mp->mp_which == MLX_PAUSE_CANCEL) &&
788 		    (mlx->mlx_pause.mp_when != 0)) {
789 			/* Cancel a pending pause operation. */
790 			mlx->mlx_pause.mp_which = 0;
791 			break;
792 		}
793 
794 		/* Fix for legal channels. */
795 		mp->mp_which &= ((1 << mlx->mlx_ci.ci_nchan) -1);
796 
797 		/* Check time values. */
798 		if (mp->mp_when < 0 || mp->mp_when > 3600 ||
799 		    mp->mp_howlong < 1 || mp->mp_howlong > (0xf * 30)) {
800 			rv = EINVAL;
801 			break;
802 		}
803 
804 		/* Check for a pause currently running. */
805 		if ((mlx->mlx_pause.mp_which != 0) &&
806 		    (mlx->mlx_pause.mp_when == 0)) {
807 			rv = EBUSY;
808 			break;
809 		}
810 
811 		/* Looks ok, go with it. */
812 		mlx->mlx_pause.mp_which = mp->mp_which;
813 		mlx->mlx_pause.mp_when = mlx_curtime() + mp->mp_when;
814 		mlx->mlx_pause.mp_howlong =
815 		    mlx->mlx_pause.mp_when + mp->mp_howlong;
816 
817 		return (0);
818 
819 	case MLX_COMMAND:
820 		/*
821 		 * Accept a command passthrough-style.
822 		 */
823 		return (mlx_user_command(mlx, (struct mlx_usercommand *)data));
824 
825 	case MLX_REBUILDASYNC:
826 		/*
827 		 * Start a rebuild on a given SCSI disk
828 		 */
829 		if (mlx->mlx_bg != 0) {
830 			rb->rr_status = 0x0106;
831 			rv = EBUSY;
832 			break;
833 		}
834 
835 		rb->rr_status = mlx_rebuild(mlx, rb->rr_channel, rb->rr_target);
836 		switch (rb->rr_status) {
837 		case 0:
838 			rv = 0;
839 			break;
840 		case 0x10000:
841 			rv = ENOMEM;	/* Couldn't set up the command. */
842 			break;
843 		case 0x0002:
844 			rv = EBUSY;
845 			break;
846 		case 0x0104:
847 			rv = EIO;
848 			break;
849 		case 0x0105:
850 			rv = ERANGE;
851 			break;
852 		case 0x0106:
853 			rv = EBUSY;
854 			break;
855 		default:
856 			rv = EINVAL;
857 			break;
858 		}
859 
860 		if (rv == 0)
861 			mlx->mlx_bg = MLX_BG_REBUILD;
862 
863 		return (0);
864 
865 	case MLX_REBUILDSTAT:
866 		/*
867 		 * Get the status of the current rebuild or consistency check.
868 		 */
869 		*rs = mlx->mlx_rebuildstat;
870 		return (0);
871 
872 	case MLX_GET_SYSDRIVE:
873 		/*
874 		 * Return the system drive number matching the `ld' device
875 		 * unit in (arg), if it happens to belong to us.
876 		 */
877 		for (i = 0; i < MLX_MAX_DRIVES; i++) {
878 			ms = &mlx->mlx_sysdrive[i];
879 			if (ms->ms_dv != NULL)
880 				if (ms->ms_dv->dv_xname[2] == '0' + *arg) {
881 					*arg = i;
882 					return (0);
883 				}
884 		}
885 		return (ENOENT);
886 
887 	case MLX_GET_CINFO:
888 		/*
889 		 * Return controller info.
890 		 */
891 		memcpy(arg, &mlx->mlx_ci, sizeof(mlx->mlx_ci));
892 		return (0);
893 	}
894 
895 	switch (cmd) {
896 	case MLXD_DETACH:
897 	case MLXD_STATUS:
898 	case MLXD_CHECKASYNC:
899 		if ((u_int)*arg >= MLX_MAX_DRIVES)
900 			return (EINVAL);
901 		ms = &mlx->mlx_sysdrive[*arg];
902 		if (*arg > MLX_MAX_DRIVES || ms->ms_dv == NULL)
903 			return (ENOENT);
904 		break;
905 
906 	default:
907 		return (ENOTTY);
908 	}
909 
910 	switch (cmd) {
911 	case MLXD_DETACH:
912 		/*
913 		 * Disconnect from the specified drive; it may be about to go
914 		 * away.
915 		 */
916 		return (config_detach(ms->ms_dv, 0));
917 
918 	case MLXD_STATUS:
919 		/*
920 		 * Return the current status of this drive.
921 		 */
922 		*arg = ms->ms_state;
923 		return (0);
924 
925 	case MLXD_CHECKASYNC:
926 		/*
927 		 * Start a background consistency check on this drive.
928 		 */
929 		if (mlx->mlx_bg != 0) {
930 			*arg = 0x0106;
931 			return (EBUSY);
932 		}
933 
934 		switch (result = mlx_check(mlx, *arg)) {
935 		case 0:
936 			rv = 0;
937 			break;
938 		case 0x10000:
939 			rv = ENOMEM;	/* Couldn't set up the command. */
940 			break;
941 		case 0x0002:
942 			rv = EIO;
943 			break;
944 		case 0x0105:
945 			rv = ERANGE;
946 			break;
947 		case 0x0106:
948 			rv = EBUSY;
949 			break;
950 		default:
951 			rv = EINVAL;
952 			break;
953 		}
954 
955 		if (rv == 0)
956 			mlx->mlx_bg = MLX_BG_CHECK;
957 		*arg = result;
958 		return (rv);
959 	}
960 
961 	return (ENOTTY);	/* XXX shut up gcc */
962 }
963 
964 /*
965  * Fire off commands to periodically check the status of connected drives.
966  * Check for commands that have timed out.
967  */
968 static void
969 mlx_periodic_create(void *cookie)
970 {
971 	int rv;
972 
973 	rv = kthread_create1(mlx_periodic_thread, NULL, &mlx_periodic_proc,
974 	    "mlxtask");
975 	if (rv == 0)
976 		return;
977 
978 	printf("mlx_periodic_create: unable to create thread (%d)\n", rv);
979 }
980 
981 static void
982 mlx_periodic_thread(void *cookie)
983 {
984 	struct mlx_softc *mlx;
985 	int i;
986 
987 	for (;;) {
988 		for (i = 0; i < mlx_cd.cd_ndevs; i++)
989 			if ((mlx = device_lookup(&mlx_cd, i)) != NULL)
990 				if (mlx->mlx_ci.ci_iftype > 1)
991 					mlx_periodic(mlx);
992 
993 		tsleep(mlx_periodic_thread, PWAIT, "mlxzzz", hz * 2);
994 	}
995 }
996 
997 static void
998 mlx_periodic(struct mlx_softc *mlx)
999 {
1000 	struct mlx_ccb *mc, *nmc;
1001 	int etype, s;
1002 	time_t ct;
1003 
1004 	ct = mlx_curtime();
1005 
1006 	if ((mlx->mlx_pause.mp_which != 0) &&
1007 	    (mlx->mlx_pause.mp_when > 0) &&
1008 	    (ct >= mlx->mlx_pause.mp_when)) {
1009 	    	/*
1010 	    	 * Start bus pause.
1011 	    	 */
1012 		mlx_pause_action(mlx);
1013 		mlx->mlx_pause.mp_when = 0;
1014 	} else if ((mlx->mlx_pause.mp_which != 0) &&
1015 		   (mlx->mlx_pause.mp_when == 0)) {
1016 		/*
1017 		 * Stop pause if required.
1018 		 */
1019 		if (ct >= mlx->mlx_pause.mp_howlong) {
1020 			mlx_pause_action(mlx);
1021 			mlx->mlx_pause.mp_which = 0;
1022 		}
1023 	} else if (ct > (mlx->mlx_lastpoll + 10)) {
1024 		/*
1025 		 * Run normal periodic activities...
1026 		 */
1027 		mlx->mlx_lastpoll = ct;
1028 
1029 		/*
1030 		 * Check controller status.
1031 		 */
1032 		if ((mlx->mlx_flags & MLXF_PERIODIC_CTLR) == 0) {
1033 			mlx->mlx_flags |= MLXF_PERIODIC_CTLR;
1034 
1035 			if (mlx->mlx_ci.ci_iftype <= 2)
1036 				etype = MLX_CMD_ENQUIRY_OLD;
1037 			else
1038 				etype =  MLX_CMD_ENQUIRY;
1039 
1040 			mlx_enquire(mlx, etype, max(sizeof(struct mlx_enquiry),
1041 			    sizeof(struct mlx_enquiry_old)),
1042 			    mlx_periodic_enquiry, 1);
1043 		}
1044 
1045 		/*
1046 		 * Check system drive status.
1047 		 */
1048 		if ((mlx->mlx_flags & MLXF_PERIODIC_DRIVE) == 0) {
1049 			mlx->mlx_flags |= MLXF_PERIODIC_DRIVE;
1050 			mlx_enquire(mlx, MLX_CMD_ENQSYSDRIVE,
1051 			    sizeof(struct mlx_enq_sys_drive) * MLX_MAX_DRIVES,
1052 			    mlx_periodic_enquiry, 1);
1053 		}
1054 	}
1055 
1056 	/*
1057 	 * Get drive rebuild/check status.
1058 	 */
1059 	if ((mlx->mlx_flags & MLXF_PERIODIC_REBUILD) == 0) {
1060 		mlx->mlx_flags |= MLXF_PERIODIC_REBUILD;
1061 		mlx_enquire(mlx, MLX_CMD_REBUILDSTAT,
1062 		    sizeof(struct mlx_rebuild_stat), mlx_periodic_rebuild, 1);
1063 	}
1064 
1065 	/*
1066 	 * Time-out busy CCBs.
1067 	 */
1068 	s = splbio();
1069 	for (mc = TAILQ_FIRST(&mlx->mlx_ccb_worklist); mc != NULL; mc = nmc) {
1070 		nmc = TAILQ_NEXT(mc, mc_chain.tailq);
1071 		if (mc->mc_expiry > ct) {
1072 			/*
1073 			 * The remaining CCBs will expire after this one, so
1074 			 * there's no point in going further.
1075 			 */
1076 			break;
1077 		}
1078 		TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
1079 		mc->mc_status = MLX_STATUS_LOST;
1080 		if (mc->mc_mx.mx_handler != NULL)
1081 			(*mc->mc_mx.mx_handler)(mc);
1082 		else if ((mc->mc_flags & MC_WAITING) != 0)
1083 			wakeup(mc);
1084 	}
1085 	splx(s);
1086 }
1087 
1088 /*
1089  * Handle the result of an ENQUIRY command instigated by periodic status
1090  * polling.
1091  */
1092 static void
1093 mlx_periodic_enquiry(struct mlx_ccb *mc)
1094 {
1095 	struct mlx_softc *mlx;
1096 	struct mlx_enquiry *me;
1097 	struct mlx_enquiry_old *meo;
1098 	struct mlx_enq_sys_drive *mes;
1099 	struct mlx_sysdrive *dr;
1100 	const char *statestr;
1101 	int i, j;
1102 	u_int lsn;
1103 
1104 	mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
1105 	mlx_ccb_unmap(mlx, mc);
1106 
1107 	/*
1108 	 * Command completed OK?
1109 	 */
1110 	if (mc->mc_status != 0) {
1111 		printf("%s: periodic enquiry failed - %s\n",
1112 		    mlx->mlx_dv.dv_xname, mlx_ccb_diagnose(mc));
1113 		goto out;
1114 	}
1115 
1116 	/*
1117 	 * Respond to command.
1118 	 */
1119 	switch (mc->mc_mbox[0]) {
1120 	case MLX_CMD_ENQUIRY_OLD:
1121 		/*
1122 		 * This is currently a bit fruitless, as we don't know how
1123 		 * to extract the eventlog pointer yet.
1124 		 */
1125 		me = (struct mlx_enquiry *)mc->mc_mx.mx_context;
1126 		meo = (struct mlx_enquiry_old *)mc->mc_mx.mx_context;
1127 
1128 		/* Convert data in-place to new format */
1129 		i = sizeof(me->me_dead) / sizeof(me->me_dead[0]);
1130 		while (--i >= 0) {
1131 			me->me_dead[i].dd_chan = meo->me_dead[i].dd_chan;
1132 			me->me_dead[i].dd_targ = meo->me_dead[i].dd_targ;
1133 		}
1134 
1135 		me->me_misc_flags = 0;
1136 		me->me_rebuild_count = meo->me_rebuild_count;
1137 		me->me_dead_count = meo->me_dead_count;
1138 		me->me_critical_sd_count = meo->me_critical_sd_count;
1139 		me->me_event_log_seq_num = 0;
1140 		me->me_offline_sd_count = meo->me_offline_sd_count;
1141 		me->me_max_commands = meo->me_max_commands;
1142 		me->me_rebuild_flag = meo->me_rebuild_flag;
1143 		me->me_fwmajor = meo->me_fwmajor;
1144 		me->me_fwminor = meo->me_fwminor;
1145 		me->me_status_flags = meo->me_status_flags;
1146 		me->me_flash_age = meo->me_flash_age;
1147 
1148 		i = sizeof(me->me_drvsize) / sizeof(me->me_drvsize[0]);
1149 		j = sizeof(meo->me_drvsize) / sizeof(meo->me_drvsize[0]);
1150 
1151 		while (--i >= 0) {
1152 			if (i >= j)
1153 				me->me_drvsize[i] = 0;
1154 			else
1155 				me->me_drvsize[i] = meo->me_drvsize[i];
1156 		}
1157 
1158 		me->me_num_sys_drvs = meo->me_num_sys_drvs;
1159 
1160 		/* FALLTHROUGH */
1161 
1162 	case MLX_CMD_ENQUIRY:
1163 		/*
1164 		 * Generic controller status update.  We could do more with
1165 		 * this than just checking the event log.
1166 		 */
1167 		me = (struct mlx_enquiry *)mc->mc_mx.mx_context;
1168 		lsn = le16toh(me->me_event_log_seq_num);
1169 
1170 		if (mlx->mlx_currevent == -1) {
1171 			/* Initialise our view of the event log. */
1172 			mlx->mlx_currevent = lsn;
1173 			mlx->mlx_lastevent = lsn;
1174 		} else if (lsn != mlx->mlx_lastevent &&
1175 			   (mlx->mlx_flags & MLXF_EVENTLOG_BUSY) == 0) {
1176 			/* Record where current events are up to */
1177 			mlx->mlx_currevent = lsn;
1178 
1179 			/* Mark the event log as busy. */
1180 			mlx->mlx_flags |= MLXF_EVENTLOG_BUSY;
1181 
1182 			/* Drain new eventlog entries. */
1183 			mlx_periodic_eventlog_poll(mlx);
1184 		}
1185 		break;
1186 
1187 	case MLX_CMD_ENQSYSDRIVE:
1188 		/*
1189 		 * Perform drive status comparison to see if something
1190 		 * has failed.  Don't perform the comparison if we're
1191 		 * reconfiguring, since the system drive table will be
1192 		 * changing.
1193 		 */
1194 		if ((mlx->mlx_flags & MLXF_RESCANNING) != 0)
1195 			break;
1196 
1197 		mes = (struct mlx_enq_sys_drive *)mc->mc_mx.mx_context;
1198 		dr = &mlx->mlx_sysdrive[0];
1199 
1200 		for (i = 0; i < mlx->mlx_numsysdrives; i++) {
1201 			/* Has state been changed by controller? */
1202 			if (dr->ms_state != mes[i].sd_state) {
1203 				switch (mes[i].sd_state) {
1204 				case MLX_SYSD_OFFLINE:
1205 					statestr = "offline";
1206 					break;
1207 
1208 				case MLX_SYSD_ONLINE:
1209 					statestr = "online";
1210 					break;
1211 
1212 				case MLX_SYSD_CRITICAL:
1213 					statestr = "critical";
1214 					break;
1215 
1216 				default:
1217 					statestr = "unknown";
1218 					break;
1219 				}
1220 
1221 				printf("%s: unit %d %s\n", mlx->mlx_dv.dv_xname,
1222 				    i, statestr);
1223 
1224 				/* Save new state. */
1225 				dr->ms_state = mes[i].sd_state;
1226 			}
1227 		}
1228 		break;
1229 
1230 #ifdef DIAGNOSTIC
1231 	default:
1232 		printf("%s: mlx_periodic_enquiry: eh?\n",
1233 		    mlx->mlx_dv.dv_xname);
1234 		break;
1235 #endif
1236 	}
1237 
1238  out:
1239 	if (mc->mc_mbox[0] == MLX_CMD_ENQSYSDRIVE)
1240 		mlx->mlx_flags &= ~MLXF_PERIODIC_DRIVE;
1241 	else
1242 		mlx->mlx_flags &= ~MLXF_PERIODIC_CTLR;
1243 
1244 	free(mc->mc_mx.mx_context, M_DEVBUF);
1245 	mlx_ccb_free(mlx, mc);
1246 }
1247 
1248 /*
1249  * Instigate a poll for one event log message on (mlx).  We only poll for
1250  * one message at a time, to keep our command usage down.
1251  */
1252 static void
1253 mlx_periodic_eventlog_poll(struct mlx_softc *mlx)
1254 {
1255 	struct mlx_ccb *mc;
1256 	void *result;
1257 	int rv;
1258 
1259 	result = NULL;
1260 
1261 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
1262 		goto out;
1263 
1264 	if ((result = malloc(1024, M_DEVBUF, M_WAITOK)) == NULL) {
1265 		rv = ENOMEM;
1266 		goto out;
1267 	}
1268 	if ((rv = mlx_ccb_map(mlx, mc, result, 1024, MC_XFER_IN)) != 0)
1269 		goto out;
1270 	if (mc->mc_nsgent != 1) {
1271 		mlx_ccb_unmap(mlx, mc);
1272 		printf("mlx_periodic_eventlog_poll: too many segs\n");
1273 		goto out;
1274 	}
1275 
1276 	/* Build the command to get one log entry. */
1277 	mlx_make_type3(mc, MLX_CMD_LOGOP, MLX_LOGOP_GET, 1,
1278 	    mlx->mlx_lastevent, 0, 0, mc->mc_xfer_phys, 0);
1279 
1280 	mc->mc_mx.mx_handler = mlx_periodic_eventlog_respond;
1281 	mc->mc_mx.mx_dv = &mlx->mlx_dv;
1282 	mc->mc_mx.mx_context = result;
1283 
1284 	/* Start the command. */
1285 	mlx_ccb_enqueue(mlx, mc);
1286 
1287  out:
1288 	if (rv != 0) {
1289 		if (mc != NULL)
1290 			mlx_ccb_free(mlx, mc);
1291 		if (result != NULL)
1292 			free(result, M_DEVBUF);
1293 	}
1294 }
1295 
1296 /*
1297  * Handle the result of polling for a log message, generate diagnostic
1298  * output.  If this wasn't the last message waiting for us, we'll go collect
1299  * another.
1300  */
1301 static void
1302 mlx_periodic_eventlog_respond(struct mlx_ccb *mc)
1303 {
1304 	struct mlx_softc *mlx;
1305 	struct mlx_eventlog_entry *el;
1306 	const char *reason;
1307 	u_int8_t sensekey, chan, targ;
1308 
1309 	mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
1310 	el = mc->mc_mx.mx_context;
1311 	mlx_ccb_unmap(mlx, mc);
1312 
1313 	mlx->mlx_lastevent++;
1314 
1315 	if (mc->mc_status == 0) {
1316 		switch (el->el_type) {
1317 		case MLX_LOGMSG_SENSE:		/* sense data */
1318 			sensekey = el->el_sense & 0x0f;
1319 			chan = (el->el_target >> 4) & 0x0f;
1320 			targ = el->el_target & 0x0f;
1321 
1322 			/*
1323 			 * This is the only sort of message we understand at
1324 			 * the moment.  The tests here are probably
1325 			 * incomplete.
1326 			 */
1327 
1328 			/*
1329 			 * Mylex vendor-specific message indicating a drive
1330 			 * was killed?
1331 			 */
1332 			if (sensekey == 9 && el->el_asc == 0x80) {
1333 				if (el->el_asq < sizeof(mlx_sense_msgs) /
1334 				    sizeof(mlx_sense_msgs[0]))
1335 					reason = mlx_sense_msgs[el->el_asq];
1336 				else
1337 					reason = "for unknown reason";
1338 
1339 				printf("%s: physical drive %d:%d killed %s\n",
1340 				    mlx->mlx_dv.dv_xname, chan, targ, reason);
1341 			}
1342 
1343 			/*
1344 			 * SCSI drive was reset?
1345 			 */
1346 			if (sensekey == 6 && el->el_asc == 0x29)
1347 				printf("%s: physical drive %d:%d reset\n",
1348 				    mlx->mlx_dv.dv_xname, chan, targ);
1349 
1350 			/*
1351 			 * SCSI drive error?
1352 			 */
1353 			if (!(sensekey == 0 ||
1354 			    (sensekey == 2 &&
1355 			    el->el_asc == 0x04 &&
1356 			    (el->el_asq == 0x01 || el->el_asq == 0x02)))) {
1357 				printf("%s: physical drive %d:%d error log: "
1358 				    "sense = %d asc = %x asq = %x\n",
1359 				    mlx->mlx_dv.dv_xname, chan, targ, sensekey,
1360 				    el->el_asc, el->el_asq);
1361 				printf("%s:   info = %d:%d:%d:%d "
1362 				    " csi = %d:%d:%d:%d\n",
1363 				    mlx->mlx_dv.dv_xname,
1364 				    el->el_information[0],
1365 				    el->el_information[1],
1366 				    el->el_information[2],
1367 				    el->el_information[3],
1368 				    el->el_csi[0], el->el_csi[1],
1369 				    el->el_csi[2], el->el_csi[3]);
1370 			}
1371 
1372 			break;
1373 
1374 		default:
1375 			printf("%s: unknown log message type 0x%x\n",
1376 			    mlx->mlx_dv.dv_xname, el->el_type);
1377 			break;
1378 		}
1379 	} else {
1380 		printf("%s: error reading message log - %s\n",
1381 		    mlx->mlx_dv.dv_xname, mlx_ccb_diagnose(mc));
1382 
1383 		/*
1384 		 * Give up on all the outstanding messages, as we may have
1385 		 * come unsynched.
1386 		 */
1387 		mlx->mlx_lastevent = mlx->mlx_currevent;
1388 	}
1389 
1390 	free(mc->mc_mx.mx_context, M_DEVBUF);
1391 	mlx_ccb_free(mlx, mc);
1392 
1393 	/*
1394 	 * Is there another message to obtain?
1395 	 */
1396 	if (mlx->mlx_lastevent != mlx->mlx_currevent)
1397 		mlx_periodic_eventlog_poll(mlx);
1398 	else
1399 		mlx->mlx_flags &= ~MLXF_EVENTLOG_BUSY;
1400 }
1401 
1402 /*
1403  * Handle check/rebuild operations in progress.
1404  */
1405 static void
1406 mlx_periodic_rebuild(struct mlx_ccb *mc)
1407 {
1408 	struct mlx_softc *mlx;
1409 	const char *opstr;
1410 	struct mlx_rebuild_status *mr;
1411 
1412 	mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
1413 	mr = mc->mc_mx.mx_context;
1414 	mlx_ccb_unmap(mlx, mc);
1415 
1416 	switch (mc->mc_status) {
1417 	case 0:
1418 		/*
1419 		 * Operation running, update stats.
1420 		 */
1421 		mlx->mlx_rebuildstat = *mr;
1422 
1423 		/* Spontaneous rebuild/check? */
1424 		if (mlx->mlx_bg == 0) {
1425 			mlx->mlx_bg = MLX_BG_SPONTANEOUS;
1426 			printf("%s: background check/rebuild started\n",
1427 			    mlx->mlx_dv.dv_xname);
1428 		}
1429 		break;
1430 
1431 	case 0x0105:
1432 		/*
1433 		 * Nothing running, finalise stats and report.
1434 		 */
1435 		switch (mlx->mlx_bg) {
1436 		case MLX_BG_CHECK:
1437 			/* XXX Print drive? */
1438 			opstr = "consistency check";
1439 			break;
1440 
1441 		case MLX_BG_REBUILD:
1442 			/* XXX Print channel:target? */
1443 			opstr = "drive rebuild";
1444 			break;
1445 
1446 		case MLX_BG_SPONTANEOUS:
1447 		default:
1448 			/*
1449 			 * If we have previously been non-idle, report the
1450 			 * transition
1451 			 */
1452 			if (mlx->mlx_rebuildstat.rs_code !=
1453 			    MLX_REBUILDSTAT_IDLE)
1454 				opstr = "background check/rebuild";
1455 			else
1456 				opstr = NULL;
1457 		}
1458 
1459 		if (opstr != NULL)
1460 			printf("%s: %s completed\n", mlx->mlx_dv.dv_xname,
1461 			    opstr);
1462 
1463 		mlx->mlx_bg = 0;
1464 		mlx->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE;
1465 		break;
1466 	}
1467 
1468 	free(mc->mc_mx.mx_context, M_DEVBUF);
1469 	mlx_ccb_free(mlx, mc);
1470 	mlx->mlx_flags &= ~MLXF_PERIODIC_REBUILD;
1471 }
1472 
1473 /*
1474  * It's time to perform a channel pause action for (mlx), either start or
1475  * stop the pause.
1476  */
1477 static void
1478 mlx_pause_action(struct mlx_softc *mlx)
1479 {
1480 	struct mlx_ccb *mc;
1481 	int failsafe, i, cmd;
1482 	time_t ct;
1483 
1484 	ct = mlx_curtime();
1485 
1486 	/* What are we doing here? */
1487 	if (mlx->mlx_pause.mp_when == 0) {
1488 		cmd = MLX_CMD_STARTCHANNEL;
1489 		failsafe = 0;
1490 	} else {
1491 		cmd = MLX_CMD_STOPCHANNEL;
1492 
1493 		/*
1494 		 * Channels will always start again after the failsafe
1495 		 * period, which is specified in multiples of 30 seconds.
1496 		 * This constrains us to a maximum pause of 450 seconds.
1497 		 */
1498 		failsafe = ((mlx->mlx_pause.mp_howlong - ct) + 5) / 30;
1499 
1500 		if (failsafe > 0xf) {
1501 			failsafe = 0xf;
1502 			mlx->mlx_pause.mp_howlong = ct + (0xf * 30) - 5;
1503 		}
1504 	}
1505 
1506 	/* Build commands for every channel requested. */
1507 	for (i = 0; i < mlx->mlx_ci.ci_nchan; i++) {
1508 		if ((1 << i) & mlx->mlx_pause.mp_which) {
1509 			if (mlx_ccb_alloc(mlx, &mc, 1) != 0) {
1510 				printf("%s: %s failed for channel %d\n",
1511 				    mlx->mlx_dv.dv_xname,
1512 				    cmd == MLX_CMD_STOPCHANNEL ?
1513 				    "pause" : "resume", i);
1514 				continue;
1515 			}
1516 
1517 			/* Build the command. */
1518 			mlx_make_type2(mc, cmd, (failsafe << 4) | i, 0, 0,
1519 			    0, 0, 0, 0, 0);
1520 			mc->mc_mx.mx_handler = mlx_pause_done;
1521 			mc->mc_mx.mx_dv = &mlx->mlx_dv;
1522 
1523 			mlx_ccb_enqueue(mlx, mc);
1524 		}
1525 	}
1526 }
1527 
1528 static void
1529 mlx_pause_done(struct mlx_ccb *mc)
1530 {
1531 	struct mlx_softc *mlx;
1532 	int command, channel;
1533 
1534 	mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
1535 	command = mc->mc_mbox[0];
1536 	channel = mc->mc_mbox[2] & 0xf;
1537 
1538 	if (mc->mc_status != 0)
1539 		printf("%s: %s command failed - %s\n", mlx->mlx_dv.dv_xname,
1540 		    command == MLX_CMD_STOPCHANNEL ? "pause" : "resume",
1541 		    mlx_ccb_diagnose(mc));
1542 	else if (command == MLX_CMD_STOPCHANNEL)
1543 		printf("%s: channel %d pausing for %ld seconds\n",
1544 		    mlx->mlx_dv.dv_xname, channel,
1545 		    (long)(mlx->mlx_pause.mp_howlong - mlx_curtime()));
1546 	else
1547 		printf("%s: channel %d resuming\n", mlx->mlx_dv.dv_xname,
1548 		    channel);
1549 
1550 	mlx_ccb_free(mlx, mc);
1551 }
1552 
1553 /*
1554  * Perform an Enquiry command using a type-3 command buffer and a return a
1555  * single linear result buffer.  If the completion function is specified, it
1556  * will be called with the completed command (and the result response will
1557  * not be valid until that point).  Otherwise, the command will either be
1558  * busy-waited for (interrupts must be blocked), or slept for.
1559  */
1560 static void *
1561 mlx_enquire(struct mlx_softc *mlx, int command, size_t bufsize,
1562 	    void (*handler)(struct mlx_ccb *mc), int waitok)
1563 {
1564 	struct mlx_ccb *mc;
1565 	void *result;
1566 	int rv, mapped;
1567 
1568 	result = NULL;
1569 	mapped = 0;
1570 
1571 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
1572 		goto out;
1573 
1574 	result = malloc(bufsize, M_DEVBUF, waitok ? M_WAITOK : M_NOWAIT);
1575 	if (result == NULL) {
1576 		printf("mlx_enquire: malloc() failed\n");
1577 		goto out;
1578 	}
1579 	if ((rv = mlx_ccb_map(mlx, mc, result, bufsize, MC_XFER_IN)) != 0)
1580 		goto out;
1581 	mapped = 1;
1582 	if (mc->mc_nsgent != 1) {
1583 		printf("mlx_enquire: too many segs\n");
1584 		goto out;
1585 	}
1586 
1587 	/* Build an enquiry command. */
1588 	mlx_make_type2(mc, command, 0, 0, 0, 0, 0, 0, mc->mc_xfer_phys, 0);
1589 
1590 	/* Do we want a completion callback? */
1591 	if (handler != NULL) {
1592 		mc->mc_mx.mx_context = result;
1593 		mc->mc_mx.mx_dv = &mlx->mlx_dv;
1594 		mc->mc_mx.mx_handler = handler;
1595 		mlx_ccb_enqueue(mlx, mc);
1596 	} else {
1597 		/* Run the command in either polled or wait mode. */
1598 		if (waitok)
1599 			rv = mlx_ccb_wait(mlx, mc);
1600 		else
1601 			rv = mlx_ccb_poll(mlx, mc, 5000);
1602 	}
1603 
1604  out:
1605 	/* We got a command, but nobody else will free it. */
1606 	if (handler == NULL && mc != NULL) {
1607 		if (mapped)
1608 			mlx_ccb_unmap(mlx, mc);
1609 		mlx_ccb_free(mlx, mc);
1610 	}
1611 
1612 	/* We got an error, and we allocated a result. */
1613 	if (rv != 0 && result != NULL) {
1614 		if (mc != NULL)
1615 			mlx_ccb_free(mlx, mc);
1616 		free(result, M_DEVBUF);
1617 		result = NULL;
1618 	}
1619 
1620 	return (result);
1621 }
1622 
1623 /*
1624  * Perform a Flush command on the nominated controller.
1625  *
1626  * May be called with interrupts enabled or disabled; will not return until
1627  * the flush operation completes or fails.
1628  */
1629 int
1630 mlx_flush(struct mlx_softc *mlx, int async)
1631 {
1632 	struct mlx_ccb *mc;
1633 	int rv;
1634 
1635 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
1636 		goto out;
1637 
1638 	/* Build a flush command and fire it off. */
1639 	mlx_make_type2(mc, MLX_CMD_FLUSH, 0, 0, 0, 0, 0, 0, 0, 0);
1640 
1641 	if (async)
1642 		rv = mlx_ccb_wait(mlx, mc);
1643 	else
1644 		rv = mlx_ccb_poll(mlx, mc, MLX_TIMEOUT * 1000);
1645 	if (rv != 0)
1646 		goto out;
1647 
1648 	/* Command completed OK? */
1649 	if (mc->mc_status != 0) {
1650 		printf("%s: FLUSH failed - %s\n", mlx->mlx_dv.dv_xname,
1651 		    mlx_ccb_diagnose(mc));
1652 		rv = EIO;
1653 	}
1654  out:
1655 	if (mc != NULL)
1656 		mlx_ccb_free(mlx, mc);
1657 
1658 	return (rv);
1659 }
1660 
1661 /*
1662  * Start a background consistency check on (drive).
1663  */
1664 static int
1665 mlx_check(struct mlx_softc *mlx, int drive)
1666 {
1667 	struct mlx_ccb *mc;
1668 	int rv;
1669 
1670 	/* Get ourselves a command buffer. */
1671 	rv = 0x10000;
1672 
1673 	if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
1674 		goto out;
1675 
1676 	/* Build a checkasync command, set the "fix it" flag. */
1677 	mlx_make_type2(mc, MLX_CMD_CHECKASYNC, 0, 0, 0, 0, 0, drive | 0x80,
1678 	    0, 0);
1679 
1680 	/* Start the command and wait for it to be returned. */
1681 	if (mlx_ccb_wait(mlx, mc) != 0)
1682 		goto out;
1683 
1684 	/* Command completed OK? */
1685 	if (mc->mc_status != 0)
1686 		printf("%s: CHECK ASYNC failed - %s\n", mlx->mlx_dv.dv_xname,
1687 		    mlx_ccb_diagnose(mc));
1688 	else
1689 		printf("%s: consistency check started",
1690 		    mlx->mlx_sysdrive[drive].ms_dv->dv_xname);
1691 
1692 	rv = mc->mc_status;
1693  out:
1694 	if (mc != NULL)
1695 		mlx_ccb_free(mlx, mc);
1696 
1697 	return (rv);
1698 }
1699 
1700 /*
1701  * Start a background rebuild of the physical drive at (channel),(target).
1702  *
1703  * May be called with interrupts enabled or disabled; will return as soon as
1704  * the operation has started or been refused.
1705  */
1706 static int
1707 mlx_rebuild(struct mlx_softc *mlx, int channel, int target)
1708 {
1709 	struct mlx_ccb *mc;
1710 	int error;
1711 
1712 	error = 0x10000;
1713 	if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
1714 		goto out;
1715 
1716 	/* Build a rebuildasync command, set the "fix it" flag. */
1717 	mlx_make_type2(mc, MLX_CMD_REBUILDASYNC, channel, target, 0, 0, 0, 0,
1718 	    0, 0);
1719 
1720 	/* Start the command and wait for it to be returned. */
1721 	if (mlx_ccb_wait(mlx, mc) != 0)
1722 		goto out;
1723 
1724 	/* Command completed OK? */
1725 	printf("%s: ", mlx->mlx_dv.dv_xname);
1726 	if (mc->mc_status != 0)
1727 		printf("REBUILD ASYNC failed - %s\n", mlx_ccb_diagnose(mc));
1728 	else
1729 		printf("rebuild started for %d:%d\n", channel, target);
1730 
1731 	error = mc->mc_status;
1732 
1733  out:
1734 	if (mc != NULL)
1735 		mlx_ccb_free(mlx, mc);
1736 
1737 	return (error);
1738 }
1739 
1740 /*
1741  * Take a command from user-space and try to run it.
1742  *
1743  * XXX Note that this can't perform very much in the way of error checking,
1744  * XXX and as such, applications _must_ be considered trustworthy.
1745  *
1746  * XXX Commands using S/G for data are not supported.
1747  */
1748 static int
1749 mlx_user_command(struct mlx_softc *mlx, struct mlx_usercommand *mu)
1750 {
1751 	struct mlx_ccb *mc;
1752 	struct mlx_dcdb *dcdb;
1753 	void *kbuf;
1754 	int rv, mapped;
1755 
1756 	if ((mu->mu_bufdir & ~MU_XFER_MASK) != 0)
1757 		return (EINVAL);
1758 
1759 	kbuf = NULL;
1760 	dcdb = NULL;
1761 	mapped = 0;
1762 
1763 	/* Get ourselves a command and copy in from user space. */
1764 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0) {
1765 		DPRINTF(("mlx_user_command: mlx_ccb_alloc = %d\n", rv));
1766 		goto out;
1767 	}
1768 
1769 	memcpy(mc->mc_mbox, mu->mu_command, sizeof(mc->mc_mbox));
1770 
1771 	/*
1772 	 * If we need a buffer for data transfer, allocate one and copy in
1773 	 * its initial contents.
1774 	 */
1775 	if (mu->mu_datasize > 0) {
1776 		if (mu->mu_datasize > MAXPHYS)
1777 			return (EINVAL);
1778 
1779 		kbuf = malloc(mu->mu_datasize, M_DEVBUF, M_WAITOK);
1780 		if (kbuf == NULL) {
1781 			DPRINTF(("mlx_user_command: malloc = NULL\n"));
1782 			rv = ENOMEM;
1783 			goto out;
1784 		}
1785 
1786 		if ((mu->mu_bufdir & MU_XFER_OUT) != 0) {
1787 			rv = copyin(mu->mu_buf, kbuf, mu->mu_datasize);
1788 			if (rv != 0) {
1789 				DPRINTF(("mlx_user_command: copyin = %d\n",
1790 				    rv));
1791 				goto out;
1792 			}
1793 		}
1794 
1795 		/* Map the buffer so the controller can see it. */
1796 		rv = mlx_ccb_map(mlx, mc, kbuf, mu->mu_datasize, mu->mu_bufdir);
1797 		if (rv != 0) {
1798 			DPRINTF(("mlx_user_command: mlx_ccb_map = %d\n", rv));
1799 			goto out;
1800 		}
1801 		if (mc->mc_nsgent > 1) {
1802 			DPRINTF(("mlx_user_command: too many s/g entries\n"));
1803 			rv = EFBIG;
1804 			goto out;
1805 		}
1806 		mapped = 1;
1807 		/*
1808 		 * If this is a passthrough SCSI command, the DCDB is packed at
1809 		 * the beginning of the data area.  Fix up the DCDB to point to
1810 		 * the correct physical address and override any bufptr
1811 		 * supplied by the caller since we know what it's meant to be.
1812 		 */
1813 		if (mc->mc_mbox[0] == MLX_CMD_DIRECT_CDB) {
1814 			dcdb = (struct mlx_dcdb *)kbuf;
1815 			dcdb->dcdb_physaddr = mc->mc_xfer_phys + sizeof(*dcdb);
1816 			mu->mu_bufptr = 8;
1817 		}
1818 	}
1819 
1820 
1821 	/*
1822 	 * If there's a data buffer, fix up the command's buffer pointer.
1823 	 */
1824 	if (mu->mu_datasize > 0) {
1825 		/* Range check the pointer to physical buffer address. */
1826 		if (mu->mu_bufptr < 0 ||
1827 		    mu->mu_bufptr > sizeof(mu->mu_command) - 4) {
1828 			DPRINTF(("mlx_user_command: bufptr botch\n"));
1829 			rv = EINVAL;
1830 			goto out;
1831 		}
1832 
1833 		mc->mc_mbox[mu->mu_bufptr] = mc->mc_xfer_phys;
1834 		mc->mc_mbox[mu->mu_bufptr+1] = mc->mc_xfer_phys >> 8;
1835 		mc->mc_mbox[mu->mu_bufptr+2] = mc->mc_xfer_phys >> 16;
1836 		mc->mc_mbox[mu->mu_bufptr+3] = mc->mc_xfer_phys >> 24;
1837 	}
1838 
1839 	/* Submit the command and wait. */
1840 	if ((rv = mlx_ccb_wait(mlx, mc)) != 0) {
1841 #ifdef DEBUG
1842 		printf("mlx_user_command: mlx_ccb_wait = %d\n", rv);
1843 #endif
1844 	}
1845 
1846  out:
1847 	if (mc != NULL) {
1848 		/* Copy out status and data */
1849 		mu->mu_status = mc->mc_status;
1850 		if (mapped)
1851 			mlx_ccb_unmap(mlx, mc);
1852 		mlx_ccb_free(mlx, mc);
1853 	}
1854 
1855 	if (kbuf != NULL) {
1856 		if (mu->mu_datasize > 0 && (mu->mu_bufdir & MU_XFER_IN) != 0) {
1857 			rv = copyout(kbuf, mu->mu_buf, mu->mu_datasize);
1858 #ifdef DIAGNOSTIC
1859 			if (rv != 0)
1860 				printf("mlx_user_command: copyout = %d\n", rv);
1861 #endif
1862 		}
1863 	}
1864 	if (kbuf != NULL)
1865 		free(kbuf, M_DEVBUF);
1866 
1867 	return (rv);
1868 }
1869 
1870 /*
1871  * Allocate and initialise a CCB.
1872  */
1873 int
1874 mlx_ccb_alloc(struct mlx_softc *mlx, struct mlx_ccb **mcp, int control)
1875 {
1876 	struct mlx_ccb *mc;
1877 	int s;
1878 
1879 	s = splbio();
1880 	mc = SLIST_FIRST(&mlx->mlx_ccb_freelist);
1881 	if (control) {
1882 		if (mlx->mlx_nccbs_ctrl >= MLX_NCCBS_CONTROL) {
1883 			splx(s);
1884 			*mcp = NULL;
1885 			return (EAGAIN);
1886 		}
1887 		mc->mc_flags |= MC_CONTROL;
1888 		mlx->mlx_nccbs_ctrl++;
1889 	}
1890 	SLIST_REMOVE_HEAD(&mlx->mlx_ccb_freelist, mc_chain.slist);
1891 	splx(s);
1892 
1893 	*mcp = mc;
1894 	return (0);
1895 }
1896 
1897 /*
1898  * Free a CCB.
1899  */
1900 void
1901 mlx_ccb_free(struct mlx_softc *mlx, struct mlx_ccb *mc)
1902 {
1903 	int s;
1904 
1905 	s = splbio();
1906 	if ((mc->mc_flags & MC_CONTROL) != 0)
1907 		mlx->mlx_nccbs_ctrl--;
1908 	mc->mc_flags = 0;
1909 	SLIST_INSERT_HEAD(&mlx->mlx_ccb_freelist, mc, mc_chain.slist);
1910 	splx(s);
1911 }
1912 
1913 /*
1914  * If a CCB is specified, enqueue it.  Pull CCBs off the software queue in
1915  * the order that they were enqueued and try to submit their mailboxes to
1916  * the controller for execution.
1917  */
1918 void
1919 mlx_ccb_enqueue(struct mlx_softc *mlx, struct mlx_ccb *mc)
1920 {
1921 	int s;
1922 
1923 	s = splbio();
1924 
1925 	if (mc != NULL)
1926 		SIMPLEQ_INSERT_TAIL(&mlx->mlx_ccb_queue, mc, mc_chain.simpleq);
1927 
1928 	while ((mc = SIMPLEQ_FIRST(&mlx->mlx_ccb_queue)) != NULL) {
1929 		if (mlx_ccb_submit(mlx, mc) != 0)
1930 			break;
1931 		SIMPLEQ_REMOVE_HEAD(&mlx->mlx_ccb_queue, mc_chain.simpleq);
1932 		TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
1933 	}
1934 
1935 	splx(s);
1936 }
1937 
1938 /*
1939  * Map the specified CCB's data buffer onto the bus, and fill the
1940  * scatter-gather list.
1941  */
1942 int
1943 mlx_ccb_map(struct mlx_softc *mlx, struct mlx_ccb *mc, void *data, int size,
1944 	    int dir)
1945 {
1946 	struct mlx_sgentry *sge;
1947 	int nsegs, i, rv, sgloff;
1948 	bus_dmamap_t xfer;
1949 
1950 	xfer = mc->mc_xfer_map;
1951 
1952 	rv = bus_dmamap_load(mlx->mlx_dmat, xfer, data, size, NULL,
1953 	    BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
1954 	    ((dir & MC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
1955 	if (rv != 0)
1956 		return (rv);
1957 
1958 	nsegs = xfer->dm_nsegs;
1959 	mc->mc_xfer_size = size;
1960 	mc->mc_flags |= dir;
1961 	mc->mc_nsgent = nsegs;
1962 	mc->mc_xfer_phys = xfer->dm_segs[0].ds_addr;
1963 
1964 	sgloff = MLX_SGL_SIZE * mc->mc_ident;
1965 	sge = (struct mlx_sgentry *)((caddr_t)mlx->mlx_sgls + sgloff);
1966 
1967 	for (i = 0; i < nsegs; i++, sge++) {
1968 		sge->sge_addr = htole32(xfer->dm_segs[i].ds_addr);
1969 		sge->sge_count = htole32(xfer->dm_segs[i].ds_len);
1970 	}
1971 
1972 	if ((dir & MC_XFER_OUT) != 0)
1973 		i = BUS_DMASYNC_PREWRITE;
1974 	else
1975 		i = 0;
1976 	if ((dir & MC_XFER_IN) != 0)
1977 		i |= BUS_DMASYNC_PREREAD;
1978 
1979 	bus_dmamap_sync(mlx->mlx_dmat, xfer, 0, mc->mc_xfer_size, i);
1980 	bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap, sgloff,
1981 	    MLX_SGL_SIZE, BUS_DMASYNC_PREWRITE);
1982 
1983 	return (0);
1984 }
1985 
1986 /*
1987  * Unmap the specified CCB's data buffer.
1988  */
1989 void
1990 mlx_ccb_unmap(struct mlx_softc *mlx, struct mlx_ccb *mc)
1991 {
1992 	int i;
1993 
1994 	bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap,
1995 	    MLX_SGL_SIZE * mc->mc_ident, MLX_SGL_SIZE,
1996 	    BUS_DMASYNC_POSTWRITE);
1997 
1998 	if ((mc->mc_flags & MC_XFER_OUT) != 0)
1999 		i = BUS_DMASYNC_POSTWRITE;
2000 	else
2001 		i = 0;
2002 	if ((mc->mc_flags & MC_XFER_IN) != 0)
2003 		i |= BUS_DMASYNC_POSTREAD;
2004 
2005 	bus_dmamap_sync(mlx->mlx_dmat, mc->mc_xfer_map, 0, mc->mc_xfer_size, i);
2006 	bus_dmamap_unload(mlx->mlx_dmat, mc->mc_xfer_map);
2007 }
2008 
2009 /*
2010  * Submit the CCB, and busy-wait for it to complete.  Return non-zero on
2011  * timeout or submission error.  Must be called with interrupts blocked.
2012  */
2013 int
2014 mlx_ccb_poll(struct mlx_softc *mlx, struct mlx_ccb *mc, int timo)
2015 {
2016 	int rv;
2017 
2018 	mc->mc_mx.mx_handler = NULL;
2019 
2020 	if ((rv = mlx_ccb_submit(mlx, mc)) != 0)
2021 		return (rv);
2022 	TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
2023 
2024 	for (timo *= 10; timo != 0; timo--) {
2025 		mlx_intr(mlx);
2026 		if (mc->mc_status != MLX_STATUS_BUSY)
2027 			break;
2028 		DELAY(100);
2029 	}
2030 
2031 	if (timo != 0) {
2032 		if (mc->mc_status != 0) {
2033 			printf("%s: command failed - %s\n",
2034 			    mlx->mlx_dv.dv_xname, mlx_ccb_diagnose(mc));
2035 			rv = EIO;
2036 		} else
2037 			rv = 0;
2038 	} else {
2039 		printf("%s: command timed out\n", mlx->mlx_dv.dv_xname);
2040 		rv = EIO;
2041 	}
2042 
2043 	return (rv);
2044 }
2045 
2046 /*
2047  * Enqueue the CCB, and sleep until it completes.  Return non-zero on
2048  * timeout or error.
2049  */
2050 int
2051 mlx_ccb_wait(struct mlx_softc *mlx, struct mlx_ccb *mc)
2052 {
2053 	int s;
2054 
2055 	mc->mc_flags |= MC_WAITING;
2056 	mc->mc_mx.mx_handler = NULL;
2057 
2058 	s = splbio();
2059 	mlx_ccb_enqueue(mlx, mc);
2060 	tsleep(mc, PRIBIO, "mlxwccb", 0);
2061 	splx(s);
2062 
2063 	if (mc->mc_status != 0) {
2064 		printf("%s: command failed - %s\n", mlx->mlx_dv.dv_xname,
2065 		    mlx_ccb_diagnose(mc));
2066 		return (EIO);
2067 	}
2068 
2069 	return (0);
2070 }
2071 
2072 /*
2073  * Try to submit a CCB's mailbox to the controller for execution.  Return
2074  * non-zero on timeout or error.  Must be called with interrupts blocked.
2075  */
2076 static int
2077 mlx_ccb_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
2078 {
2079 	int i, s, r;
2080 
2081 	/* Save the ident so we can handle this command when complete. */
2082 	mc->mc_mbox[1] = (u_int8_t)(mc->mc_ident + 1);
2083 
2084 	/* Mark the command as currently being processed. */
2085 	mc->mc_status = MLX_STATUS_BUSY;
2086 	mc->mc_expiry = mlx_curtime() + MLX_TIMEOUT;
2087 
2088 	/* Spin waiting for the mailbox. */
2089 	for (i = 100; i != 0; i--) {
2090 		s = splbio();
2091 		r = (*mlx->mlx_submit)(mlx, mc);
2092 		splx(s);
2093 		if (r != 0)
2094 			break;
2095 		DELAY(100);
2096 	}
2097 	if (i != 0)
2098 		return (0);
2099 
2100 	DPRINTF(("mlx_ccb_submit: rejected; queueing\n"));
2101 	mc->mc_status = MLX_STATUS_WEDGED;
2102 	return (EIO);
2103 }
2104 
2105 /*
2106  * Return a string that describes why a command has failed.
2107  */
2108 const char *
2109 mlx_ccb_diagnose(struct mlx_ccb *mc)
2110 {
2111 	static char tbuf[80];
2112 	int i;
2113 
2114 	for (i = 0; i < sizeof(mlx_msgs) / sizeof(mlx_msgs[0]); i++)
2115 		if ((mc->mc_mbox[0] == mlx_msgs[i].command ||
2116 		    mlx_msgs[i].command == 0) &&
2117 		    mc->mc_status == mlx_msgs[i].status) {
2118 			snprintf(tbuf, sizeof(tbuf), "%s (0x%x)",
2119 			    mlx_status_msgs[mlx_msgs[i].msg], mc->mc_status);
2120 			return (tbuf);
2121 		}
2122 
2123 	snprintf(tbuf, sizeof(tbuf), "unknown response 0x%x for command 0x%x",
2124 	    (int)mc->mc_status, (int)mc->mc_mbox[0]);
2125 
2126 	return (tbuf);
2127 }
2128 
2129 /*
2130  * Poll the controller for completed commands.  Returns non-zero if one or
2131  * more commands were completed.  Must be called with interrupts blocked.
2132  */
2133 int
2134 mlx_intr(void *cookie)
2135 {
2136 	struct mlx_softc *mlx;
2137 	struct mlx_ccb *mc;
2138 	int result;
2139 	u_int ident, status;
2140 
2141 	mlx = cookie;
2142 	result = 0;
2143 
2144 	while ((*mlx->mlx_findcomplete)(mlx, &ident, &status) != 0) {
2145 		result = 1;
2146 		ident--;
2147 
2148 		if (ident >= MLX_MAX_QUEUECNT) {
2149 			printf("%s: bad completion returned\n",
2150 			    mlx->mlx_dv.dv_xname);
2151 			continue;
2152 		}
2153 
2154 		mc = mlx->mlx_ccbs + ident;
2155 
2156 		if (mc->mc_status != MLX_STATUS_BUSY) {
2157 			printf("%s: bad completion returned\n",
2158 			    mlx->mlx_dv.dv_xname);
2159 			continue;
2160 		}
2161 
2162 		TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
2163 
2164 		/* Record status and notify the initiator, if requested. */
2165 		mc->mc_status = status;
2166 		if (mc->mc_mx.mx_handler != NULL)
2167 			(*mc->mc_mx.mx_handler)(mc);
2168 		else if ((mc->mc_flags & MC_WAITING) != 0)
2169 			wakeup(mc);
2170 	}
2171 
2172 	/* If we've completed any commands, try posting some more. */
2173 	if (result)
2174 		mlx_ccb_enqueue(mlx, NULL);
2175 
2176 	return (result);
2177 }
2178 
2179 /*
2180  * Emit a string describing the firmware handshake status code, and return a
2181  * flag indicating whether the code represents a fatal error.
2182  *
2183  * Error code interpretations are from the Linux driver, and don't directly
2184  * match the messages printed by Mylex's BIOS.  This may change if
2185  * documentation on the codes is forthcoming.
2186  */
2187 static int
2188 mlx_fw_message(struct mlx_softc *mlx, int error, int param1, int param2)
2189 {
2190 	const char *fmt;
2191 
2192 	switch (error) {
2193 	case 0x00:
2194 		fmt = "physical drive %d:%d not responding";
2195 		break;
2196 
2197 	case 0x08:
2198 		/*
2199 		 * We could be neater about this and give some indication
2200 		 * when we receive more of them.
2201 		 */
2202 		if ((mlx->mlx_flags & MLXF_SPINUP_REPORTED) == 0) {
2203 			printf("%s: spinning up drives...\n",
2204 			    mlx->mlx_dv.dv_xname);
2205 			mlx->mlx_flags |= MLXF_SPINUP_REPORTED;
2206 		}
2207 		return (0);
2208 
2209 	case 0x30:
2210 		fmt = "configuration checksum error";
2211 		break;
2212 
2213 	case 0x60:
2214 		fmt = "mirror race recovery failed";
2215 		break;
2216 
2217 	case 0x70:
2218 		fmt = "mirror race recovery in progress";
2219 		break;
2220 
2221 	case 0x90:
2222 		fmt = "physical drive %d:%d COD mismatch";
2223 		break;
2224 
2225 	case 0xa0:
2226 		fmt = "logical drive installation aborted";
2227 		break;
2228 
2229 	case 0xb0:
2230 		fmt = "mirror race on a critical system drive";
2231 		break;
2232 
2233 	case 0xd0:
2234 		fmt = "new controller configuration found";
2235 		break;
2236 
2237 	case 0xf0:
2238 		printf("%s: FATAL MEMORY PARITY ERROR\n",
2239 		    mlx->mlx_dv.dv_xname);
2240 		return (1);
2241 
2242 	default:
2243 		printf("%s: unknown firmware init error %02x:%02x:%02x\n",
2244 		    mlx->mlx_dv.dv_xname, error, param1, param2);
2245 		return (0);
2246 	}
2247 
2248 	printf("%s: ", mlx->mlx_dv.dv_xname);
2249 	printf(fmt, param2, param1);
2250 	printf("\n");
2251 
2252 	return (0);
2253 }
2254