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