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