xref: /netbsd-src/sys/dev/ic/mlx.c (revision e5548b402ae4c44fb816de42c7bba9581ce23ef5)
1 /*	$NetBSD: mlx.c,v 1.37 2005/12/11 12:21:27 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.37 2005/12/11 12:21:27 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 (ld->sc_dv.dv_parent != &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 (handler != NULL && mc != NULL) {
1615 			if (mapped)
1616 				mlx_ccb_unmap(mlx, mc);
1617 			mlx_ccb_free(mlx, mc);
1618 		}
1619 		free(result, M_DEVBUF);
1620 		result = NULL;
1621 	}
1622 
1623 	return (result);
1624 }
1625 
1626 /*
1627  * Perform a Flush command on the nominated controller.
1628  *
1629  * May be called with interrupts enabled or disabled; will not return until
1630  * the flush operation completes or fails.
1631  */
1632 int
1633 mlx_flush(struct mlx_softc *mlx, int async)
1634 {
1635 	struct mlx_ccb *mc;
1636 	int rv;
1637 
1638 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
1639 		goto out;
1640 
1641 	/* Build a flush command and fire it off. */
1642 	mlx_make_type2(mc, MLX_CMD_FLUSH, 0, 0, 0, 0, 0, 0, 0, 0);
1643 
1644 	if (async)
1645 		rv = mlx_ccb_wait(mlx, mc);
1646 	else
1647 		rv = mlx_ccb_poll(mlx, mc, MLX_TIMEOUT * 1000);
1648 	if (rv != 0)
1649 		goto out;
1650 
1651 	/* Command completed OK? */
1652 	if (mc->mc_status != 0) {
1653 		printf("%s: FLUSH failed - %s\n", mlx->mlx_dv.dv_xname,
1654 		    mlx_ccb_diagnose(mc));
1655 		rv = EIO;
1656 	}
1657  out:
1658 	if (mc != NULL)
1659 		mlx_ccb_free(mlx, mc);
1660 
1661 	return (rv);
1662 }
1663 
1664 /*
1665  * Start a background consistency check on (drive).
1666  */
1667 static int
1668 mlx_check(struct mlx_softc *mlx, int drive)
1669 {
1670 	struct mlx_ccb *mc;
1671 	int rv;
1672 
1673 	/* Get ourselves a command buffer. */
1674 	rv = 0x10000;
1675 
1676 	if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
1677 		goto out;
1678 
1679 	/* Build a checkasync command, set the "fix it" flag. */
1680 	mlx_make_type2(mc, MLX_CMD_CHECKASYNC, 0, 0, 0, 0, 0, drive | 0x80,
1681 	    0, 0);
1682 
1683 	/* Start the command and wait for it to be returned. */
1684 	if (mlx_ccb_wait(mlx, mc) != 0)
1685 		goto out;
1686 
1687 	/* Command completed OK? */
1688 	if (mc->mc_status != 0)
1689 		printf("%s: CHECK ASYNC failed - %s\n", mlx->mlx_dv.dv_xname,
1690 		    mlx_ccb_diagnose(mc));
1691 	else
1692 		printf("%s: consistency check started",
1693 		    mlx->mlx_sysdrive[drive].ms_dv->dv_xname);
1694 
1695 	rv = mc->mc_status;
1696  out:
1697 	if (mc != NULL)
1698 		mlx_ccb_free(mlx, mc);
1699 
1700 	return (rv);
1701 }
1702 
1703 /*
1704  * Start a background rebuild of the physical drive at (channel),(target).
1705  *
1706  * May be called with interrupts enabled or disabled; will return as soon as
1707  * the operation has started or been refused.
1708  */
1709 static int
1710 mlx_rebuild(struct mlx_softc *mlx, int channel, int target)
1711 {
1712 	struct mlx_ccb *mc;
1713 	int error;
1714 
1715 	error = 0x10000;
1716 	if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
1717 		goto out;
1718 
1719 	/* Build a rebuildasync command, set the "fix it" flag. */
1720 	mlx_make_type2(mc, MLX_CMD_REBUILDASYNC, channel, target, 0, 0, 0, 0,
1721 	    0, 0);
1722 
1723 	/* Start the command and wait for it to be returned. */
1724 	if (mlx_ccb_wait(mlx, mc) != 0)
1725 		goto out;
1726 
1727 	/* Command completed OK? */
1728 	printf("%s: ", mlx->mlx_dv.dv_xname);
1729 	if (mc->mc_status != 0)
1730 		printf("REBUILD ASYNC failed - %s\n", mlx_ccb_diagnose(mc));
1731 	else
1732 		printf("rebuild started for %d:%d\n", channel, target);
1733 
1734 	error = mc->mc_status;
1735 
1736  out:
1737 	if (mc != NULL)
1738 		mlx_ccb_free(mlx, mc);
1739 
1740 	return (error);
1741 }
1742 
1743 /*
1744  * Take a command from user-space and try to run it.
1745  *
1746  * XXX Note that this can't perform very much in the way of error checking,
1747  * XXX and as such, applications _must_ be considered trustworthy.
1748  *
1749  * XXX Commands using S/G for data are not supported.
1750  */
1751 static int
1752 mlx_user_command(struct mlx_softc *mlx, struct mlx_usercommand *mu)
1753 {
1754 	struct mlx_ccb *mc;
1755 	struct mlx_dcdb *dcdb;
1756 	void *kbuf;
1757 	int rv, mapped;
1758 
1759 	if ((mu->mu_bufdir & ~MU_XFER_MASK) != 0)
1760 		return (EINVAL);
1761 
1762 	kbuf = NULL;
1763 	dcdb = NULL;
1764 	mapped = 0;
1765 
1766 	/* Get ourselves a command and copy in from user space. */
1767 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0) {
1768 		DPRINTF(("mlx_user_command: mlx_ccb_alloc = %d\n", rv));
1769 		goto out;
1770 	}
1771 
1772 	memcpy(mc->mc_mbox, mu->mu_command, sizeof(mc->mc_mbox));
1773 
1774 	/*
1775 	 * If we need a buffer for data transfer, allocate one and copy in
1776 	 * its initial contents.
1777 	 */
1778 	if (mu->mu_datasize > 0) {
1779 		if (mu->mu_datasize > MAXPHYS)
1780 			return (EINVAL);
1781 
1782 		kbuf = malloc(mu->mu_datasize, M_DEVBUF, M_WAITOK);
1783 		if (kbuf == NULL) {
1784 			DPRINTF(("mlx_user_command: malloc = NULL\n"));
1785 			rv = ENOMEM;
1786 			goto out;
1787 		}
1788 
1789 		if ((mu->mu_bufdir & MU_XFER_OUT) != 0) {
1790 			rv = copyin(mu->mu_buf, kbuf, mu->mu_datasize);
1791 			if (rv != 0) {
1792 				DPRINTF(("mlx_user_command: copyin = %d\n",
1793 				    rv));
1794 				goto out;
1795 			}
1796 		}
1797 
1798 		/* Map the buffer so the controller can see it. */
1799 		rv = mlx_ccb_map(mlx, mc, kbuf, mu->mu_datasize, mu->mu_bufdir);
1800 		if (rv != 0) {
1801 			DPRINTF(("mlx_user_command: mlx_ccb_map = %d\n", rv));
1802 			goto out;
1803 		}
1804 		if (mc->mc_nsgent > 1) {
1805 			DPRINTF(("mlx_user_command: too many s/g entries\n"));
1806 			rv = EFBIG;
1807 			goto out;
1808 		}
1809 		mapped = 1;
1810 	}
1811 
1812 	/*
1813 	 * If this is a passthrough SCSI command, the DCDB is packed at the
1814 	 * beginning of the data area.  Fix up the DCDB to point to the correct physical
1815 	 * address and override any bufptr supplied by the caller since we know
1816 	 * what it's meant to be.
1817 	 */
1818 	if (mc->mc_mbox[0] == MLX_CMD_DIRECT_CDB) {
1819 		dcdb = (struct mlx_dcdb *)kbuf;
1820 		dcdb->dcdb_physaddr = mc->mc_xfer_phys + sizeof(*dcdb);
1821 		mu->mu_bufptr = 8;
1822 	}
1823 
1824 	/*
1825 	 * If there's a data buffer, fix up the command's buffer pointer.
1826 	 */
1827 	if (mu->mu_datasize > 0) {
1828 		/* Range check the pointer to physical buffer address. */
1829 		if (mu->mu_bufptr < 0 ||
1830 		    mu->mu_bufptr > sizeof(mu->mu_command) - 4) {
1831 			DPRINTF(("mlx_user_command: bufptr botch\n"));
1832 			rv = EINVAL;
1833 			goto out;
1834 		}
1835 
1836 		mc->mc_mbox[mu->mu_bufptr] = mc->mc_xfer_phys;
1837 		mc->mc_mbox[mu->mu_bufptr+1] = mc->mc_xfer_phys >> 8;
1838 		mc->mc_mbox[mu->mu_bufptr+2] = mc->mc_xfer_phys >> 16;
1839 		mc->mc_mbox[mu->mu_bufptr+3] = mc->mc_xfer_phys >> 24;
1840 	}
1841 
1842 	/* Submit the command and wait. */
1843 	if ((rv = mlx_ccb_wait(mlx, mc)) != 0) {
1844 #ifdef DEBUG
1845 		printf("mlx_user_command: mlx_ccb_wait = %d\n", rv);
1846 #endif
1847 	}
1848 
1849  out:
1850 	if (mc != NULL) {
1851 		if (mapped)
1852 			mlx_ccb_unmap(mlx, mc);
1853 		mlx_ccb_free(mlx, mc);
1854 	}
1855 
1856 	/* Copy out status and data */
1857 	mu->mu_status = mc->mc_status;
1858 
1859 	if (kbuf != NULL) {
1860 		if (mu->mu_datasize > 0 && (mu->mu_bufdir & MU_XFER_IN) != 0) {
1861 			rv = copyout(kbuf, mu->mu_buf, mu->mu_datasize);
1862 #ifdef DIAGNOSTIC
1863 			if (rv != 0)
1864 				printf("mlx_user_command: copyout = %d\n", rv);
1865 #endif
1866 		}
1867 	}
1868 	if (kbuf != NULL)
1869 		free(kbuf, M_DEVBUF);
1870 
1871 	return (rv);
1872 }
1873 
1874 /*
1875  * Allocate and initialise a CCB.
1876  */
1877 int
1878 mlx_ccb_alloc(struct mlx_softc *mlx, struct mlx_ccb **mcp, int control)
1879 {
1880 	struct mlx_ccb *mc;
1881 	int s;
1882 
1883 	s = splbio();
1884 	mc = SLIST_FIRST(&mlx->mlx_ccb_freelist);
1885 	if (control) {
1886 		if (mlx->mlx_nccbs_ctrl >= MLX_NCCBS_CONTROL) {
1887 			splx(s);
1888 			*mcp = NULL;
1889 			return (EAGAIN);
1890 		}
1891 		mc->mc_flags |= MC_CONTROL;
1892 		mlx->mlx_nccbs_ctrl++;
1893 	}
1894 	SLIST_REMOVE_HEAD(&mlx->mlx_ccb_freelist, mc_chain.slist);
1895 	splx(s);
1896 
1897 	*mcp = mc;
1898 	return (0);
1899 }
1900 
1901 /*
1902  * Free a CCB.
1903  */
1904 void
1905 mlx_ccb_free(struct mlx_softc *mlx, struct mlx_ccb *mc)
1906 {
1907 	int s;
1908 
1909 	s = splbio();
1910 	if ((mc->mc_flags & MC_CONTROL) != 0)
1911 		mlx->mlx_nccbs_ctrl--;
1912 	mc->mc_flags = 0;
1913 	SLIST_INSERT_HEAD(&mlx->mlx_ccb_freelist, mc, mc_chain.slist);
1914 	splx(s);
1915 }
1916 
1917 /*
1918  * If a CCB is specified, enqueue it.  Pull CCBs off the software queue in
1919  * the order that they were enqueued and try to submit their mailboxes to
1920  * the controller for execution.
1921  */
1922 void
1923 mlx_ccb_enqueue(struct mlx_softc *mlx, struct mlx_ccb *mc)
1924 {
1925 	int s;
1926 
1927 	s = splbio();
1928 
1929 	if (mc != NULL)
1930 		SIMPLEQ_INSERT_TAIL(&mlx->mlx_ccb_queue, mc, mc_chain.simpleq);
1931 
1932 	while ((mc = SIMPLEQ_FIRST(&mlx->mlx_ccb_queue)) != NULL) {
1933 		if (mlx_ccb_submit(mlx, mc) != 0)
1934 			break;
1935 		SIMPLEQ_REMOVE_HEAD(&mlx->mlx_ccb_queue, mc_chain.simpleq);
1936 		TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
1937 	}
1938 
1939 	splx(s);
1940 }
1941 
1942 /*
1943  * Map the specified CCB's data buffer onto the bus, and fill the
1944  * scatter-gather list.
1945  */
1946 int
1947 mlx_ccb_map(struct mlx_softc *mlx, struct mlx_ccb *mc, void *data, int size,
1948 	    int dir)
1949 {
1950 	struct mlx_sgentry *sge;
1951 	int nsegs, i, rv, sgloff;
1952 	bus_dmamap_t xfer;
1953 
1954 	xfer = mc->mc_xfer_map;
1955 
1956 	rv = bus_dmamap_load(mlx->mlx_dmat, xfer, data, size, NULL,
1957 	    BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
1958 	    ((dir & MC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
1959 	if (rv != 0)
1960 		return (rv);
1961 
1962 	nsegs = xfer->dm_nsegs;
1963 	mc->mc_xfer_size = size;
1964 	mc->mc_flags |= dir;
1965 	mc->mc_nsgent = nsegs;
1966 	mc->mc_xfer_phys = xfer->dm_segs[0].ds_addr;
1967 
1968 	sgloff = MLX_SGL_SIZE * mc->mc_ident;
1969 	sge = (struct mlx_sgentry *)((caddr_t)mlx->mlx_sgls + sgloff);
1970 
1971 	for (i = 0; i < nsegs; i++, sge++) {
1972 		sge->sge_addr = htole32(xfer->dm_segs[i].ds_addr);
1973 		sge->sge_count = htole32(xfer->dm_segs[i].ds_len);
1974 	}
1975 
1976 	if ((dir & MC_XFER_OUT) != 0)
1977 		i = BUS_DMASYNC_PREWRITE;
1978 	else
1979 		i = 0;
1980 	if ((dir & MC_XFER_IN) != 0)
1981 		i |= BUS_DMASYNC_PREREAD;
1982 
1983 	bus_dmamap_sync(mlx->mlx_dmat, xfer, 0, mc->mc_xfer_size, i);
1984 	bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap, sgloff,
1985 	    MLX_SGL_SIZE, BUS_DMASYNC_PREWRITE);
1986 
1987 	return (0);
1988 }
1989 
1990 /*
1991  * Unmap the specified CCB's data buffer.
1992  */
1993 void
1994 mlx_ccb_unmap(struct mlx_softc *mlx, struct mlx_ccb *mc)
1995 {
1996 	int i;
1997 
1998 	bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap,
1999 	    MLX_SGL_SIZE * mc->mc_ident, MLX_SGL_SIZE,
2000 	    BUS_DMASYNC_POSTWRITE);
2001 
2002 	if ((mc->mc_flags & MC_XFER_OUT) != 0)
2003 		i = BUS_DMASYNC_POSTWRITE;
2004 	else
2005 		i = 0;
2006 	if ((mc->mc_flags & MC_XFER_IN) != 0)
2007 		i |= BUS_DMASYNC_POSTREAD;
2008 
2009 	bus_dmamap_sync(mlx->mlx_dmat, mc->mc_xfer_map, 0, mc->mc_xfer_size, i);
2010 	bus_dmamap_unload(mlx->mlx_dmat, mc->mc_xfer_map);
2011 }
2012 
2013 /*
2014  * Submit the CCB, and busy-wait for it to complete.  Return non-zero on
2015  * timeout or submission error.  Must be called with interrupts blocked.
2016  */
2017 int
2018 mlx_ccb_poll(struct mlx_softc *mlx, struct mlx_ccb *mc, int timo)
2019 {
2020 	int rv;
2021 
2022 	mc->mc_mx.mx_handler = NULL;
2023 
2024 	if ((rv = mlx_ccb_submit(mlx, mc)) != 0)
2025 		return (rv);
2026 	TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
2027 
2028 	for (timo *= 10; timo != 0; timo--) {
2029 		mlx_intr(mlx);
2030 		if (mc->mc_status != MLX_STATUS_BUSY)
2031 			break;
2032 		DELAY(100);
2033 	}
2034 
2035 	if (timo != 0) {
2036 		if (mc->mc_status != 0) {
2037 			printf("%s: command failed - %s\n",
2038 			    mlx->mlx_dv.dv_xname, mlx_ccb_diagnose(mc));
2039 			rv = EIO;
2040 		} else
2041 			rv = 0;
2042 	} else {
2043 		printf("%s: command timed out\n", mlx->mlx_dv.dv_xname);
2044 		rv = EIO;
2045 	}
2046 
2047 	return (rv);
2048 }
2049 
2050 /*
2051  * Enqueue the CCB, and sleep until it completes.  Return non-zero on
2052  * timeout or error.
2053  */
2054 int
2055 mlx_ccb_wait(struct mlx_softc *mlx, struct mlx_ccb *mc)
2056 {
2057 	int s;
2058 
2059 	mc->mc_flags |= MC_WAITING;
2060 	mc->mc_mx.mx_handler = NULL;
2061 
2062 	s = splbio();
2063 	mlx_ccb_enqueue(mlx, mc);
2064 	tsleep(mc, PRIBIO, "mlxwccb", 0);
2065 	splx(s);
2066 
2067 	if (mc->mc_status != 0) {
2068 		printf("%s: command failed - %s\n", mlx->mlx_dv.dv_xname,
2069 		    mlx_ccb_diagnose(mc));
2070 		return (EIO);
2071 	}
2072 
2073 	return (0);
2074 }
2075 
2076 /*
2077  * Try to submit a CCB's mailbox to the controller for execution.  Return
2078  * non-zero on timeout or error.  Must be called with interrupts blocked.
2079  */
2080 static int
2081 mlx_ccb_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
2082 {
2083 	int i, s, r;
2084 
2085 	/* Save the ident so we can handle this command when complete. */
2086 	mc->mc_mbox[1] = (u_int8_t)(mc->mc_ident + 1);
2087 
2088 	/* Mark the command as currently being processed. */
2089 	mc->mc_status = MLX_STATUS_BUSY;
2090 	mc->mc_expiry = mlx_curtime() + MLX_TIMEOUT;
2091 
2092 	/* Spin waiting for the mailbox. */
2093 	for (i = 100; i != 0; i--) {
2094 		s = splbio();
2095 		r = (*mlx->mlx_submit)(mlx, mc);
2096 		splx(s);
2097 		if (r != 0)
2098 			break;
2099 		DELAY(100);
2100 	}
2101 	if (i != 0)
2102 		return (0);
2103 
2104 	DPRINTF(("mlx_ccb_submit: rejected; queueing\n"));
2105 	mc->mc_status = MLX_STATUS_WEDGED;
2106 	return (EIO);
2107 }
2108 
2109 /*
2110  * Return a string that describes why a command has failed.
2111  */
2112 const char *
2113 mlx_ccb_diagnose(struct mlx_ccb *mc)
2114 {
2115 	static char tbuf[80];
2116 	int i;
2117 
2118 	for (i = 0; i < sizeof(mlx_msgs) / sizeof(mlx_msgs[0]); i++)
2119 		if ((mc->mc_mbox[0] == mlx_msgs[i].command ||
2120 		    mlx_msgs[i].command == 0) &&
2121 		    mc->mc_status == mlx_msgs[i].status) {
2122 			snprintf(tbuf, sizeof(tbuf), "%s (0x%x)",
2123 			    mlx_status_msgs[mlx_msgs[i].msg], mc->mc_status);
2124 			return (tbuf);
2125 		}
2126 
2127 	snprintf(tbuf, sizeof(tbuf), "unknown response 0x%x for command 0x%x",
2128 	    (int)mc->mc_status, (int)mc->mc_mbox[0]);
2129 
2130 	return (tbuf);
2131 }
2132 
2133 /*
2134  * Poll the controller for completed commands.  Returns non-zero if one or
2135  * more commands were completed.  Must be called with interrupts blocked.
2136  */
2137 int
2138 mlx_intr(void *cookie)
2139 {
2140 	struct mlx_softc *mlx;
2141 	struct mlx_ccb *mc;
2142 	int result;
2143 	u_int ident, status;
2144 
2145 	mlx = cookie;
2146 	result = 0;
2147 
2148 	while ((*mlx->mlx_findcomplete)(mlx, &ident, &status) != 0) {
2149 		result = 1;
2150 		ident--;
2151 
2152 		if (ident >= MLX_MAX_QUEUECNT) {
2153 			printf("%s: bad completion returned\n",
2154 			    mlx->mlx_dv.dv_xname);
2155 			continue;
2156 		}
2157 
2158 		mc = mlx->mlx_ccbs + ident;
2159 
2160 		if (mc->mc_status != MLX_STATUS_BUSY) {
2161 			printf("%s: bad completion returned\n",
2162 			    mlx->mlx_dv.dv_xname);
2163 			continue;
2164 		}
2165 
2166 		TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
2167 
2168 		/* Record status and notify the initiator, if requested. */
2169 		mc->mc_status = status;
2170 		if (mc->mc_mx.mx_handler != NULL)
2171 			(*mc->mc_mx.mx_handler)(mc);
2172 		else if ((mc->mc_flags & MC_WAITING) != 0)
2173 			wakeup(mc);
2174 	}
2175 
2176 	/* If we've completed any commands, try posting some more. */
2177 	if (result)
2178 		mlx_ccb_enqueue(mlx, NULL);
2179 
2180 	return (result);
2181 }
2182 
2183 /*
2184  * Emit a string describing the firmware handshake status code, and return a
2185  * flag indicating whether the code represents a fatal error.
2186  *
2187  * Error code interpretations are from the Linux driver, and don't directly
2188  * match the messages printed by Mylex's BIOS.  This may change if
2189  * documentation on the codes is forthcoming.
2190  */
2191 static int
2192 mlx_fw_message(struct mlx_softc *mlx, int error, int param1, int param2)
2193 {
2194 	const char *fmt;
2195 
2196 	switch (error) {
2197 	case 0x00:
2198 		fmt = "physical drive %d:%d not responding";
2199 		break;
2200 
2201 	case 0x08:
2202 		/*
2203 		 * We could be neater about this and give some indication
2204 		 * when we receive more of them.
2205 		 */
2206 		if ((mlx->mlx_flags & MLXF_SPINUP_REPORTED) == 0) {
2207 			printf("%s: spinning up drives...\n",
2208 			    mlx->mlx_dv.dv_xname);
2209 			mlx->mlx_flags |= MLXF_SPINUP_REPORTED;
2210 		}
2211 		return (0);
2212 
2213 	case 0x30:
2214 		fmt = "configuration checksum error";
2215 		break;
2216 
2217 	case 0x60:
2218 		fmt = "mirror race recovery failed";
2219 		break;
2220 
2221 	case 0x70:
2222 		fmt = "mirror race recovery in progress";
2223 		break;
2224 
2225 	case 0x90:
2226 		fmt = "physical drive %d:%d COD mismatch";
2227 		break;
2228 
2229 	case 0xa0:
2230 		fmt = "logical drive installation aborted";
2231 		break;
2232 
2233 	case 0xb0:
2234 		fmt = "mirror race on a critical system drive";
2235 		break;
2236 
2237 	case 0xd0:
2238 		fmt = "new controller configuration found";
2239 		break;
2240 
2241 	case 0xf0:
2242 		printf("%s: FATAL MEMORY PARITY ERROR\n",
2243 		    mlx->mlx_dv.dv_xname);
2244 		return (1);
2245 
2246 	default:
2247 		printf("%s: unknown firmware init error %02x:%02x:%02x\n",
2248 		    mlx->mlx_dv.dv_xname, error, param1, param2);
2249 		return (0);
2250 	}
2251 
2252 	printf("%s: ", mlx->mlx_dv.dv_xname);
2253 	printf(fmt, param2, param1);
2254 	printf("\n");
2255 
2256 	return (0);
2257 }
2258