xref: /netbsd/sys/dev/ic/mlx.c (revision bf9ec67e)
1 /*	$NetBSD: mlx.c,v 1.16 2002/04/23 11:57:45 ad 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.16 2002/04/23 11:57:45 ad 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 					*arg = i;
860 					return (0);
861 				}
862 		}
863 		return (ENOENT);
864 	}
865 
866 	switch (cmd) {
867 	case MLXD_DETACH:
868 	case MLXD_STATUS:
869 	case MLXD_CHECKASYNC:
870 		if ((u_int)*arg >= MLX_MAX_DRIVES)
871 			return (EINVAL);
872 		ms = &mlx->mlx_sysdrive[*arg];
873 		if (*arg > MLX_MAX_DRIVES || ms->ms_dv == NULL)
874 			return (ENOENT);
875 		break;
876 
877 	default:
878 		return (ENOTTY);
879 	}
880 
881 	switch (cmd) {
882 	case MLXD_DETACH:
883 		/*
884 		 * Disconnect from the specified drive; it may be about to go
885 		 * away.
886 		 */
887 		return (config_detach(ms->ms_dv, 0));
888 
889 	case MLXD_STATUS:
890 		/*
891 		 * Return the current status of this drive.
892 		 */
893 		*arg = ms->ms_state;
894 		return (0);
895 
896 	case MLXD_CHECKASYNC:
897 		/*
898 		 * Start a background consistency check on this drive.
899 		 */
900 		if (mlx->mlx_bg != 0) {
901 			*arg = 0x0106;
902 			return (EBUSY);
903 		}
904 
905 		switch (result = mlx_check(mlx, *arg)) {
906 		case 0:
907 			rv = 0;
908 			break;
909 		case 0x10000:
910 			rv = ENOMEM;	/* Couldn't set up the command. */
911 			break;
912 		case 0x0002:
913 			rv = EIO;
914 			break;
915 		case 0x0105:
916 			rv = ERANGE;
917 			break;
918 		case 0x0106:
919 			rv = EBUSY;
920 			break;
921 		default:
922 			rv = EINVAL;
923 			break;
924 		}
925 
926 		if (rv == 0)
927 			mlx->mlx_bg = MLX_BG_CHECK;
928 		*arg = result;
929 		return (rv);
930 	}
931 
932 	return (ENOTTY);	/* XXX shut up gcc */
933 }
934 
935 /*
936  * Fire off commands to periodically check the status of connected drives.
937  * Check for commands that have timed out.
938  */
939 static void
940 mlx_periodic_create(void *cookie)
941 {
942 	int rv;
943 
944 	rv = kthread_create1(mlx_periodic_thread, NULL, &mlx_periodic_proc,
945 	    "mlxmonitor");
946 	if (rv == 0)
947 		return;
948 
949 	printf("mlx_periodic_create: unable to create thread (%d)\n", rv);
950 }
951 
952 static void
953 mlx_periodic_thread(void *cookie)
954 {
955 	struct mlx_softc *mlx;
956 	int i;
957 
958 	for (;;) {
959 		for (i = 0; i < mlx_cd.cd_ndevs; i++)
960 			if ((mlx = device_lookup(&mlx_cd, i)) != NULL)
961 				mlx_periodic(mlx);
962 
963 		tsleep(mlx_periodic_thread, PWAIT, "mlxzzz", hz);
964 	}
965 }
966 
967 static void
968 mlx_periodic(struct mlx_softc *mlx)
969 {
970 	struct mlx_ccb *mc, *nmc;
971 	int etype, s;
972 	time_t ct;
973 
974 	ct = mlx_curtime();
975 
976 	if ((mlx->mlx_pause.mp_which != 0) &&
977 	    (mlx->mlx_pause.mp_when > 0) &&
978 	    (ct >= mlx->mlx_pause.mp_when)) {
979 	    	/*
980 	    	 * Start bus pause.
981 	    	 */
982 		mlx_pause_action(mlx);
983 		mlx->mlx_pause.mp_when = 0;
984 	} else if ((mlx->mlx_pause.mp_which != 0) &&
985 		   (mlx->mlx_pause.mp_when == 0)) {
986 		/*
987 		 * Stop pause if required.
988 		 */
989 		if (ct >= mlx->mlx_pause.mp_howlong) {
990 			mlx_pause_action(mlx);
991 			mlx->mlx_pause.mp_which = 0;
992 		}
993 	} else if (ct > (mlx->mlx_lastpoll + 10)) {
994 		/*
995 		 * Run normal periodic activities...
996 		 */
997 		mlx->mlx_lastpoll = ct;
998 
999 		/*
1000 		 * Check controller status.
1001 		 */
1002 		if ((mlx->mlx_flags & MLXF_PERIODIC_CTLR) == 0) {
1003 			mlx->mlx_flags |= MLXF_PERIODIC_CTLR;
1004 
1005 			if (mlx->mlx_iftype == 2)
1006 				etype = MLX_CMD_ENQUIRY_OLD;
1007 			else
1008 				etype =  MLX_CMD_ENQUIRY;
1009 
1010 			mlx_enquire(mlx, etype, max(sizeof(struct mlx_enquiry),
1011 			    sizeof(struct mlx_enquiry_old)),
1012 			    mlx_periodic_enquiry, 1);
1013 		}
1014 
1015 		/*
1016 		 * Check system drive status.
1017 		 */
1018 		if ((mlx->mlx_flags & MLXF_PERIODIC_DRIVE) == 0) {
1019 			mlx->mlx_flags |= MLXF_PERIODIC_DRIVE;
1020 			mlx_enquire(mlx, MLX_CMD_ENQSYSDRIVE,
1021 			    sizeof(struct mlx_enq_sys_drive) * MLX_MAX_DRIVES,
1022 			    mlx_periodic_enquiry, 1);
1023 		}
1024 	}
1025 
1026 	/*
1027 	 * Get drive rebuild/check status.
1028 	 */
1029 	if ((mlx->mlx_flags & MLXF_PERIODIC_REBUILD) == 0) {
1030 		mlx->mlx_flags |= MLXF_PERIODIC_REBUILD;
1031 		mlx_enquire(mlx, MLX_CMD_REBUILDSTAT,
1032 		    sizeof(struct mlx_rebuild_stat), mlx_periodic_rebuild, 1);
1033 	}
1034 
1035 	/*
1036 	 * Time-out busy CCBs.
1037 	 */
1038 	s = splbio();
1039 	for (mc = TAILQ_FIRST(&mlx->mlx_ccb_worklist); mc != NULL; mc = nmc) {
1040 		nmc = TAILQ_NEXT(mc, mc_chain.tailq);
1041 		if (mc->mc_expiry > ct) {
1042 			/*
1043 			 * The remaining CCBs will expire after this one, so
1044 			 * there's no point in going further.
1045 			 */
1046 			break;
1047 		}
1048 		TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
1049 		mc->mc_status = MLX_STATUS_LOST;
1050 		if (mc->mc_mx.mx_handler != NULL)
1051 			(*mc->mc_mx.mx_handler)(mc);
1052 		else if ((mc->mc_flags & MC_WAITING) != 0)
1053 			wakeup(mc);
1054 	}
1055 	splx(s);
1056 }
1057 
1058 /*
1059  * Handle the result of an ENQUIRY command instigated by periodic status
1060  * polling.
1061  */
1062 static void
1063 mlx_periodic_enquiry(struct mlx_ccb *mc)
1064 {
1065 	struct mlx_softc *mlx;
1066 	struct mlx_enquiry *me;
1067 	struct mlx_enquiry_old *meo;
1068 	struct mlx_enq_sys_drive *mes;
1069 	struct mlx_sysdrive *dr;
1070 	const char *statestr;
1071 	int i, j;
1072 	u_int lsn;
1073 
1074 	mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
1075 
1076 	/*
1077 	 * Command completed OK?
1078 	 */
1079 	if (mc->mc_status != 0) {
1080 		printf("%s: periodic enquiry failed - %s\n",
1081 		    mlx->mlx_dv.dv_xname, mlx_ccb_diagnose(mc));
1082 		goto out;
1083 	}
1084 
1085 	/*
1086 	 * Respond to command.
1087 	 */
1088 	switch (mc->mc_mbox[0]) {
1089 	case MLX_CMD_ENQUIRY_OLD:
1090 		/*
1091 		 * This is currently a bit fruitless, as we don't know how
1092 		 * to extract the eventlog pointer yet.
1093 		 */
1094 		me = (struct mlx_enquiry *)mc->mc_mx.mx_context;
1095 		meo = (struct mlx_enquiry_old *)mc->mc_mx.mx_context;
1096 
1097 		/* Convert data in-place to new format */
1098 		i = sizeof(me->me_dead) / sizeof(me->me_dead[0]);
1099 		while (--i >= 0) {
1100 			me->me_dead[i].dd_chan = meo->me_dead[i].dd_chan;
1101 			me->me_dead[i].dd_targ = meo->me_dead[i].dd_targ;
1102 		}
1103 
1104 		me->me_misc_flags = 0;
1105 		me->me_rebuild_count = meo->me_rebuild_count;
1106 		me->me_dead_count = meo->me_dead_count;
1107 		me->me_critical_sd_count = meo->me_critical_sd_count;
1108 		me->me_event_log_seq_num = 0;
1109 		me->me_offline_sd_count = meo->me_offline_sd_count;
1110 		me->me_max_commands = meo->me_max_commands;
1111 		me->me_rebuild_flag = meo->me_rebuild_flag;
1112 		me->me_fwmajor = meo->me_fwmajor;
1113 		me->me_fwminor = meo->me_fwminor;
1114 		me->me_status_flags = meo->me_status_flags;
1115 		me->me_flash_age = meo->me_flash_age;
1116 
1117 		i = sizeof(me->me_drvsize) / sizeof(me->me_drvsize[0]);
1118 		j = sizeof(meo->me_drvsize) / sizeof(meo->me_drvsize[0]);
1119 
1120 		while (--i >= 0) {
1121 			if (i >= j)
1122 				me->me_drvsize[i] = 0;
1123 			else
1124 				me->me_drvsize[i] = meo->me_drvsize[i];
1125 		}
1126 
1127 		me->me_num_sys_drvs = meo->me_num_sys_drvs;
1128 
1129 		/* FALLTHROUGH */
1130 
1131 	case MLX_CMD_ENQUIRY:
1132 		/*
1133 		 * Generic controller status update.  We could do more with
1134 		 * this than just checking the event log.
1135 		 */
1136 		me = (struct mlx_enquiry *)mc->mc_mx.mx_context;
1137 		lsn = le16toh(me->me_event_log_seq_num);
1138 
1139 		if (mlx->mlx_currevent == -1) {
1140 			/* Initialise our view of the event log. */
1141 			mlx->mlx_currevent = lsn;
1142 			mlx->mlx_lastevent = lsn;
1143 		} else if (lsn != mlx->mlx_lastevent &&
1144 			   (mlx->mlx_flags & MLXF_EVENTLOG_BUSY) == 0) {
1145 			/* Record where current events are up to */
1146 			mlx->mlx_currevent = lsn;
1147 
1148 			/* Mark the event log as busy. */
1149 			mlx->mlx_flags |= MLXF_EVENTLOG_BUSY;
1150 
1151 			/* Drain new eventlog entries. */
1152 			mlx_periodic_eventlog_poll(mlx);
1153 		}
1154 		break;
1155 
1156 	case MLX_CMD_ENQSYSDRIVE:
1157 		/*
1158 		 * Perform drive status comparison to see if something
1159 		 * has failed.  Don't perform the comparison if we're
1160 		 * reconfiguring, since the system drive table will be
1161 		 * changing.
1162 		 */
1163 		if ((mlx->mlx_flags & MLXF_RESCANNING) != 0)
1164 			break;
1165 
1166 		mes = (struct mlx_enq_sys_drive *)mc->mc_mx.mx_context;
1167 		dr = &mlx->mlx_sysdrive[0];
1168 
1169 		for (i = 0; i < mlx->mlx_numsysdrives; i++) {
1170 			/* Has state been changed by controller? */
1171 			if (dr->ms_state != mes[i].sd_state) {
1172 				switch (mes[i].sd_state) {
1173 				case MLX_SYSD_OFFLINE:
1174 					statestr = "offline";
1175 					break;
1176 
1177 				case MLX_SYSD_ONLINE:
1178 					statestr = "online";
1179 					break;
1180 
1181 				case MLX_SYSD_CRITICAL:
1182 					statestr = "critical";
1183 					break;
1184 
1185 				default:
1186 					statestr = "unknown";
1187 					break;
1188 				}
1189 
1190 				printf("%s: unit %d %s\n", mlx->mlx_dv.dv_xname,
1191 				    i, statestr);
1192 
1193 				/* Save new state. */
1194 				dr->ms_state = mes[i].sd_state;
1195 			}
1196 		}
1197 		break;
1198 
1199 #ifdef DIAGNOSTIC
1200 	default:
1201 		printf("%s: mlx_periodic_enquiry: eh?\n",
1202 		    mlx->mlx_dv.dv_xname);
1203 		break;
1204 #endif
1205 	}
1206 
1207  out:
1208 	if (mc->mc_mbox[0] == MLX_CMD_ENQSYSDRIVE)
1209 		mlx->mlx_flags &= ~MLXF_PERIODIC_DRIVE;
1210 	else
1211 		mlx->mlx_flags &= ~MLXF_PERIODIC_CTLR;
1212 
1213 	free(mc->mc_mx.mx_context, M_DEVBUF);
1214 	mlx_ccb_free(mlx, mc);
1215 }
1216 
1217 /*
1218  * Instigate a poll for one event log message on (mlx).  We only poll for
1219  * one message at a time, to keep our command usage down.
1220  */
1221 static void
1222 mlx_periodic_eventlog_poll(struct mlx_softc *mlx)
1223 {
1224 	struct mlx_ccb *mc;
1225 	void *result;
1226 	int rv;
1227 
1228 	result = NULL;
1229 
1230 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
1231 		goto out;
1232 
1233 	if ((result = malloc(1024, M_DEVBUF, M_WAITOK)) == NULL) {
1234 		rv = ENOMEM;
1235 		goto out;
1236 	}
1237 	if ((rv = mlx_ccb_map(mlx, mc, result, 1024, MC_XFER_IN)) != 0)
1238 		goto out;
1239 	if (mc->mc_nsgent != 1) {
1240 		mlx_ccb_unmap(mlx, mc);
1241 		printf("mlx_periodic_eventlog_poll: too many segs\n");
1242 		goto out;
1243 	}
1244 
1245 	/* Build the command to get one log entry. */
1246 	mlx_make_type3(mc, MLX_CMD_LOGOP, MLX_LOGOP_GET, 1,
1247 	    mlx->mlx_lastevent, 0, 0, mc->mc_xfer_phys, 0);
1248 
1249 	mc->mc_mx.mx_handler = mlx_periodic_eventlog_respond;
1250 	mc->mc_mx.mx_dv = &mlx->mlx_dv;
1251 	mc->mc_mx.mx_context = result;
1252 
1253 	/* Start the command. */
1254 	mlx_ccb_enqueue(mlx, mc);
1255 
1256  out:
1257 	if (rv != 0) {
1258 		if (mc != NULL)
1259 			mlx_ccb_free(mlx, mc);
1260 		if (result != NULL)
1261 			free(result, M_DEVBUF);
1262 	}
1263 }
1264 
1265 /*
1266  * Handle the result of polling for a log message, generate diagnostic
1267  * output.  If this wasn't the last message waiting for us, we'll go collect
1268  * another.
1269  */
1270 static void
1271 mlx_periodic_eventlog_respond(struct mlx_ccb *mc)
1272 {
1273 	struct mlx_softc *mlx;
1274 	struct mlx_eventlog_entry *el;
1275 	const char *reason;
1276 	u_int8_t sensekey, chan, targ;
1277 
1278 	mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
1279 	el = mc->mc_mx.mx_context;
1280 	mlx_ccb_unmap(mlx, mc);
1281 
1282 	mlx->mlx_lastevent++;
1283 
1284 	if (mc->mc_status == 0) {
1285 		switch (el->el_type) {
1286 		case MLX_LOGMSG_SENSE:		/* sense data */
1287 			sensekey = el->el_sense & 0x0f;
1288 			chan = (el->el_target >> 4) & 0x0f;
1289 			targ = el->el_target & 0x0f;
1290 
1291 			/*
1292 			 * This is the only sort of message we understand at
1293 			 * the moment.  The tests here are probably
1294 			 * incomplete.
1295 			 */
1296 
1297 			/*
1298 			 * Mylex vendor-specific message indicating a drive
1299 			 * was killed?
1300 			 */
1301 			if (sensekey == 9 && el->el_asc == 0x80) {
1302 				if (el->el_asq < sizeof(mlx_sense_msgs) /
1303 				    sizeof(mlx_sense_msgs[0]))
1304 					reason = mlx_sense_msgs[el->el_asq];
1305 				else
1306 					reason = "for unknown reason";
1307 
1308 				printf("%s: physical drive %d:%d killed %s\n",
1309 				    mlx->mlx_dv.dv_xname, chan, targ, reason);
1310 			}
1311 
1312 			/*
1313 			 * SCSI drive was reset?
1314 			 */
1315 			if (sensekey == 6 && el->el_asc == 0x29)
1316 				printf("%s: physical drive %d:%d reset\n",
1317 				    mlx->mlx_dv.dv_xname, chan, targ);
1318 
1319 			/*
1320 			 * SCSI drive error?
1321 			 */
1322 			if (!(sensekey == 0 ||
1323 			    (sensekey == 2 &&
1324 			    el->el_asc == 0x04 &&
1325 			    (el->el_asq == 0x01 || el->el_asq == 0x02)))) {
1326 				printf("%s: physical drive %d:%d error log: "
1327 				    "sense = %d asc = %x asq = %x\n",
1328 				    mlx->mlx_dv.dv_xname, chan, targ, sensekey,
1329 				    el->el_asc, el->el_asq);
1330 				printf("%s:   info = %d:%d:%d:%d "
1331 				    " csi = %d:%d:%d:%d\n",
1332 				    mlx->mlx_dv.dv_xname,
1333 				    el->el_information[0],
1334 				    el->el_information[1],
1335 				    el->el_information[2],
1336 				    el->el_information[3],
1337 				    el->el_csi[0], el->el_csi[1],
1338 				    el->el_csi[2], el->el_csi[3]);
1339 			}
1340 
1341 			break;
1342 
1343 		default:
1344 			printf("%s: unknown log message type 0x%x\n",
1345 			    mlx->mlx_dv.dv_xname, el->el_type);
1346 			break;
1347 		}
1348 	} else {
1349 		printf("%s: error reading message log - %s\n",
1350 		    mlx->mlx_dv.dv_xname, mlx_ccb_diagnose(mc));
1351 
1352 		/*
1353 		 * Give up on all the outstanding messages, as we may have
1354 		 * come unsynched.
1355 		 */
1356 		mlx->mlx_lastevent = mlx->mlx_currevent;
1357 	}
1358 
1359 	free(mc->mc_mx.mx_context, M_DEVBUF);
1360 	mlx_ccb_free(mlx, mc);
1361 
1362 	/*
1363 	 * Is there another message to obtain?
1364 	 */
1365 	if (mlx->mlx_lastevent != mlx->mlx_currevent)
1366 		mlx_periodic_eventlog_poll(mlx);
1367 	else
1368 		mlx->mlx_flags &= ~MLXF_EVENTLOG_BUSY;
1369 }
1370 
1371 /*
1372  * Handle check/rebuild operations in progress.
1373  */
1374 static void
1375 mlx_periodic_rebuild(struct mlx_ccb *mc)
1376 {
1377 	struct mlx_softc *mlx;
1378 	const char *opstr;
1379 	struct mlx_rebuild_status *mr;
1380 
1381 	mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
1382 	mr = mc->mc_mx.mx_context;
1383 	mlx_ccb_unmap(mlx, mc);
1384 
1385 	switch (mc->mc_status) {
1386 	case 0:
1387 		/*
1388 		 * Operation running, update stats.
1389 		 */
1390 		mlx->mlx_rebuildstat = *mr;
1391 
1392 		/* Spontaneous rebuild/check? */
1393 		if (mlx->mlx_bg == 0) {
1394 			mlx->mlx_bg = MLX_BG_SPONTANEOUS;
1395 			printf("%s: background check/rebuild started\n",
1396 			    mlx->mlx_dv.dv_xname);
1397 		}
1398 		break;
1399 
1400 	case 0x0105:
1401 		/*
1402 		 * Nothing running, finalise stats and report.
1403 		 */
1404 		switch (mlx->mlx_bg) {
1405 		case MLX_BG_CHECK:
1406 			/* XXX Print drive? */
1407 			opstr = "consistency check";
1408 			break;
1409 
1410 		case MLX_BG_REBUILD:
1411 			/* XXX Print channel:target? */
1412 			opstr = "drive rebuild";
1413 			break;
1414 
1415 		case MLX_BG_SPONTANEOUS:
1416 		default:
1417 			/*
1418 			 * If we have previously been non-idle, report the
1419 			 * transition
1420 			 */
1421 			if (mlx->mlx_rebuildstat.rs_code !=
1422 			    MLX_REBUILDSTAT_IDLE)
1423 				opstr = "background check/rebuild";
1424 			else
1425 				opstr = NULL;
1426 		}
1427 
1428 		if (opstr != NULL)
1429 			printf("%s: %s completed\n", mlx->mlx_dv.dv_xname,
1430 			    opstr);
1431 
1432 		mlx->mlx_bg = 0;
1433 		mlx->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE;
1434 		break;
1435 	}
1436 
1437 	free(mc->mc_mx.mx_context, M_DEVBUF);
1438 	mlx_ccb_free(mlx, mc);
1439 	mlx->mlx_flags &= ~MLXF_PERIODIC_REBUILD;
1440 }
1441 
1442 /*
1443  * It's time to perform a channel pause action for (mlx), either start or
1444  * stop the pause.
1445  */
1446 static void
1447 mlx_pause_action(struct mlx_softc *mlx)
1448 {
1449 	struct mlx_ccb *mc;
1450 	int failsafe, i, cmd;
1451 	time_t ct;
1452 
1453 	ct = mlx_curtime();
1454 
1455 	/* What are we doing here? */
1456 	if (mlx->mlx_pause.mp_when == 0) {
1457 		cmd = MLX_CMD_STARTCHANNEL;
1458 		failsafe = 0;
1459 	} else {
1460 		cmd = MLX_CMD_STOPCHANNEL;
1461 
1462 		/*
1463 		 * Channels will always start again after the failsafe
1464 		 * period, which is specified in multiples of 30 seconds.
1465 		 * This constrains us to a maximum pause of 450 seconds.
1466 		 */
1467 		failsafe = ((mlx->mlx_pause.mp_howlong - ct) + 5) / 30;
1468 
1469 		if (failsafe > 0xf) {
1470 			failsafe = 0xf;
1471 			mlx->mlx_pause.mp_howlong = ct + (0xf * 30) - 5;
1472 		}
1473 	}
1474 
1475 	/* Build commands for every channel requested. */
1476 	for (i = 0; i < mlx->mlx_enq2->me_actual_channels; i++) {
1477 		if ((1 << i) & mlx->mlx_pause.mp_which) {
1478 			if (mlx_ccb_alloc(mlx, &mc, 1) != 0) {
1479 				printf("%s: %s failed for channel %d\n",
1480 				    mlx->mlx_dv.dv_xname,
1481 				    cmd == MLX_CMD_STOPCHANNEL ?
1482 				    "pause" : "resume", i);
1483 				continue;
1484 			}
1485 
1486 			/* Build the command. */
1487 			mlx_make_type2(mc, cmd, (failsafe << 4) | i, 0, 0,
1488 			    0, 0, 0, 0, 0);
1489 			mc->mc_mx.mx_handler = mlx_pause_done;
1490 			mc->mc_mx.mx_dv = &mlx->mlx_dv;
1491 
1492 			mlx_ccb_enqueue(mlx, mc);
1493 		}
1494 	}
1495 }
1496 
1497 static void
1498 mlx_pause_done(struct mlx_ccb *mc)
1499 {
1500 	struct mlx_softc *mlx;
1501 	int command, channel;
1502 
1503 	mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
1504 	command = mc->mc_mbox[0];
1505 	channel = mc->mc_mbox[2] & 0xf;
1506 
1507 	if (mc->mc_status != 0)
1508 		printf("%s: %s command failed - %s\n", mlx->mlx_dv.dv_xname,
1509 		    command == MLX_CMD_STOPCHANNEL ? "pause" : "resume",
1510 		    mlx_ccb_diagnose(mc));
1511 	else if (command == MLX_CMD_STOPCHANNEL)
1512 		printf("%s: channel %d pausing for %ld seconds\n",
1513 		    mlx->mlx_dv.dv_xname, channel,
1514 		    (long)(mlx->mlx_pause.mp_howlong - mlx_curtime()));
1515 	else
1516 		printf("%s: channel %d resuming\n", mlx->mlx_dv.dv_xname,
1517 		    channel);
1518 
1519 	mlx_ccb_free(mlx, mc);
1520 }
1521 
1522 /*
1523  * Perform an Enquiry command using a type-3 command buffer and a return a
1524  * single linear result buffer.  If the completion function is specified, it
1525  * will be called with the completed command (and the result response will
1526  * not be valid until that point).  Otherwise, the command will either be
1527  * busy-waited for (interrupts must be blocked), or slept for.
1528  */
1529 static void *
1530 mlx_enquire(struct mlx_softc *mlx, int command, size_t bufsize,
1531 	    void (*handler)(struct mlx_ccb *mc), int waitok)
1532 {
1533 	struct mlx_ccb *mc;
1534 	void *result;
1535 	int rv, mapped;
1536 
1537 	result = NULL;
1538 	mapped = 0;
1539 
1540 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
1541 		goto out;
1542 
1543 	result = malloc(bufsize, M_DEVBUF, waitok ? M_WAITOK : M_NOWAIT);
1544 	if (result == NULL) {
1545 		printf("mlx_enquire: malloc() failed\n");
1546 		goto out;
1547 	}
1548 	if ((rv = mlx_ccb_map(mlx, mc, result, bufsize, MC_XFER_IN)) != 0)
1549 		goto out;
1550 	mapped = 1;
1551 	if (mc->mc_nsgent != 1) {
1552 		printf("mlx_enquire: too many segs\n");
1553 		goto out;
1554 	}
1555 
1556 	/* Build an enquiry command. */
1557 	mlx_make_type2(mc, command, 0, 0, 0, 0, 0, 0, mc->mc_xfer_phys, 0);
1558 
1559 	/* Do we want a completion callback? */
1560 	if (handler != NULL) {
1561 		mc->mc_mx.mx_context = result;
1562 		mc->mc_mx.mx_dv = &mlx->mlx_dv;
1563 		mc->mc_mx.mx_handler = handler;
1564 		mlx_ccb_enqueue(mlx, mc);
1565 	} else {
1566 		/* Run the command in either polled or wait mode. */
1567 		if (waitok)
1568 			rv = mlx_ccb_wait(mlx, mc);
1569 		else
1570 			rv = mlx_ccb_poll(mlx, mc, 5000);
1571 	}
1572 
1573  out:
1574 	/* We got a command, but nobody else will free it. */
1575 	if (handler == NULL && mc != NULL) {
1576 		if (mapped)
1577 			mlx_ccb_unmap(mlx, mc);
1578 		mlx_ccb_free(mlx, mc);
1579 	}
1580 
1581 	/* We got an error, and we allocated a result. */
1582 	if (rv != 0 && result != NULL) {
1583 		if (handler != NULL && mc != NULL) {
1584 			if (mapped)
1585 				mlx_ccb_unmap(mlx, mc);
1586 			mlx_ccb_free(mlx, mc);
1587 		}
1588 		free(result, M_DEVBUF);
1589 		result = NULL;
1590 	}
1591 
1592 	return (result);
1593 }
1594 
1595 /*
1596  * Perform a Flush command on the nominated controller.
1597  *
1598  * May be called with interrupts enabled or disabled; will not return until
1599  * the flush operation completes or fails.
1600  */
1601 int
1602 mlx_flush(struct mlx_softc *mlx, int async)
1603 {
1604 	struct mlx_ccb *mc;
1605 	int rv;
1606 
1607 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
1608 		goto out;
1609 
1610 	/* Build a flush command and fire it off. */
1611 	mlx_make_type2(mc, MLX_CMD_FLUSH, 0, 0, 0, 0, 0, 0, 0, 0);
1612 
1613 	if (async)
1614 		rv = mlx_ccb_wait(mlx, mc);
1615 	else
1616 		rv = mlx_ccb_poll(mlx, mc, MLX_TIMEOUT * 1000);
1617 	if (rv != 0)
1618 		goto out;
1619 
1620 	/* Command completed OK? */
1621 	if (mc->mc_status != 0) {
1622 		printf("%s: FLUSH failed - %s\n", mlx->mlx_dv.dv_xname,
1623 		    mlx_ccb_diagnose(mc));
1624 		rv = EIO;
1625 	}
1626  out:
1627 	if (mc != NULL)
1628 		mlx_ccb_free(mlx, mc);
1629 
1630 	return (rv);
1631 }
1632 
1633 /*
1634  * Start a background consistency check on (drive).
1635  */
1636 static int
1637 mlx_check(struct mlx_softc *mlx, int drive)
1638 {
1639 	struct mlx_ccb *mc;
1640 	int rv;
1641 
1642 	/* Get ourselves a command buffer. */
1643 	rv = 0x10000;
1644 
1645 	if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
1646 		goto out;
1647 
1648 	/* Build a checkasync command, set the "fix it" flag. */
1649 	mlx_make_type2(mc, MLX_CMD_CHECKASYNC, 0, 0, 0, 0, 0, drive | 0x80,
1650 	    0, 0);
1651 
1652 	/* Start the command and wait for it to be returned. */
1653 	if (mlx_ccb_wait(mlx, mc) != 0)
1654 		goto out;
1655 
1656 	/* Command completed OK? */
1657 	if (mc->mc_status != 0)
1658 		printf("%s: CHECK ASYNC failed - %s\n", mlx->mlx_dv.dv_xname,
1659 		    mlx_ccb_diagnose(mc));
1660 	else
1661 		printf("%s: consistency check started",
1662 		    mlx->mlx_sysdrive[drive].ms_dv->dv_xname);
1663 
1664 	rv = mc->mc_status;
1665  out:
1666 	if (mc != NULL)
1667 		mlx_ccb_free(mlx, mc);
1668 
1669 	return (rv);
1670 }
1671 
1672 /*
1673  * Start a background rebuild of the physical drive at (channel),(target).
1674  *
1675  * May be called with interrupts enabled or disabled; will return as soon as
1676  * the operation has started or been refused.
1677  */
1678 static int
1679 mlx_rebuild(struct mlx_softc *mlx, int channel, int target)
1680 {
1681 	struct mlx_ccb *mc;
1682 	int error;
1683 
1684 	error = 0x10000;
1685 	if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
1686 		goto out;
1687 
1688 	/* Build a rebuildasync command, set the "fix it" flag. */
1689 	mlx_make_type2(mc, MLX_CMD_REBUILDASYNC, channel, target, 0, 0, 0, 0,
1690 	    0, 0);
1691 
1692 	/* Start the command and wait for it to be returned. */
1693 	if (mlx_ccb_wait(mlx, mc) != 0)
1694 		goto out;
1695 
1696 	/* Command completed OK? */
1697 	printf("%s: ", mlx->mlx_dv.dv_xname);
1698 	if (mc->mc_status != 0)
1699 		printf("REBUILD ASYNC failed - %s\n", mlx_ccb_diagnose(mc));
1700 	else
1701 		printf("rebuild started for %d:%d\n", channel, target);
1702 
1703 	error = mc->mc_status;
1704 
1705  out:
1706 	if (mc != NULL)
1707 		mlx_ccb_free(mlx, mc);
1708 
1709 	return (error);
1710 }
1711 
1712 /*
1713  * Take a command from user-space and try to run it.
1714  *
1715  * XXX Note that this can't perform very much in the way of error checking,
1716  * XXX and as such, applications _must_ be considered trustworthy.
1717  *
1718  * XXX Commands using S/G for data are not supported.
1719  */
1720 static int
1721 mlx_user_command(struct mlx_softc *mlx, struct mlx_usercommand *mu)
1722 {
1723 	struct mlx_ccb *mc;
1724 	struct mlx_dcdb *dcdb;
1725 	void *kbuf;
1726 	int rv, mapped;
1727 
1728 	if ((mu->mu_bufdir & ~MU_XFER_MASK) != 0)
1729 		return (EINVAL);
1730 
1731 	kbuf = NULL;
1732 	dcdb = NULL;
1733 	mapped = 0;
1734 
1735 	/* Get ourselves a command and copy in from user space. */
1736 	if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0) {
1737 		DPRINTF(("mlx_user_command: mlx_ccb_alloc = %d\n", rv));
1738 		goto out;
1739 	}
1740 
1741 	memcpy(mc->mc_mbox, mu->mu_command, sizeof(mc->mc_mbox));
1742 
1743 	/*
1744 	 * If we need a buffer for data transfer, allocate one and copy in
1745 	 * its initial contents.
1746 	 */
1747 	if (mu->mu_datasize > 0) {
1748 		if (mu->mu_datasize > MAXPHYS)
1749 			return (EINVAL);
1750 
1751 		kbuf = malloc(mu->mu_datasize, M_DEVBUF, M_WAITOK);
1752 		if (kbuf == NULL) {
1753 			DPRINTF(("mlx_user_command: malloc = NULL\n"));
1754 			rv = ENOMEM;
1755 			goto out;
1756 		}
1757 
1758 		if ((mu->mu_bufdir & MU_XFER_OUT) != 0) {
1759 			rv = copyin(mu->mu_buf, kbuf, mu->mu_datasize);
1760 			if (rv != 0) {
1761 				DPRINTF(("mlx_user_command: copyin = %d\n",
1762 				    rv));
1763 				goto out;
1764 			}
1765 		}
1766 
1767 		/* Map the buffer so the controller can see it. */
1768 		rv = mlx_ccb_map(mlx, mc, kbuf, mu->mu_datasize, mu->mu_bufdir);
1769 		if (rv != 0) {
1770 			DPRINTF(("mlx_user_command: mlx_ccb_map = %d\n", rv));
1771 			goto out;
1772 		}
1773 		if (mc->mc_nsgent > 1) {
1774 			DPRINTF(("mlx_user_command: too many s/g entries\n"));
1775 			rv = EFBIG;
1776 			goto out;
1777 		}
1778 		mapped = 1;
1779 	}
1780 
1781 	/*
1782 	 * If this is a passthrough SCSI command, the DCDB is packed at the
1783 	 * beginning of the data area.  Fix up the DCDB to point to the correct physical
1784 	 * address and override any bufptr supplied by the caller since we know
1785 	 * what it's meant to be.
1786 	 */
1787 	if (mc->mc_mbox[0] == MLX_CMD_DIRECT_CDB) {
1788 		dcdb = (struct mlx_dcdb *)kbuf;
1789 		dcdb->dcdb_physaddr = mc->mc_xfer_phys + sizeof(*dcdb);
1790 		mu->mu_bufptr = 8;
1791 	}
1792 
1793 	/*
1794 	 * If there's a data buffer, fix up the command's buffer pointer.
1795 	 */
1796 	if (mu->mu_datasize > 0) {
1797 		/* Range check the pointer to physical buffer address. */
1798 		if (mu->mu_bufptr < 0 ||
1799 		    mu->mu_bufptr > sizeof(mu->mu_command) - 4) {
1800 			DPRINTF(("mlx_user_command: bufptr botch\n"));
1801 			rv = EINVAL;
1802 			goto out;
1803 		}
1804 
1805 		mc->mc_mbox[mu->mu_bufptr] = mc->mc_xfer_phys;
1806 		mc->mc_mbox[mu->mu_bufptr+1] = mc->mc_xfer_phys >> 8;
1807 		mc->mc_mbox[mu->mu_bufptr+2] = mc->mc_xfer_phys >> 16;
1808 		mc->mc_mbox[mu->mu_bufptr+3] = mc->mc_xfer_phys >> 24;
1809 	}
1810 
1811 	/* Submit the command and wait. */
1812 	if ((rv = mlx_ccb_wait(mlx, mc)) != 0) {
1813 #ifdef DEBUG
1814 		printf("mlx_user_command: mlx_ccb_wait = %d\n", rv);
1815 #endif
1816 	}
1817 
1818  out:
1819 	if (mc != NULL) {
1820 		if (mapped)
1821 			mlx_ccb_unmap(mlx, mc);
1822 		mlx_ccb_free(mlx, mc);
1823 	}
1824 
1825 	/* Copy out status and data */
1826 	mu->mu_status = mc->mc_status;
1827 
1828 	if (kbuf != NULL) {
1829 		if (mu->mu_datasize > 0 && (mu->mu_bufdir & MU_XFER_IN) != 0) {
1830 			rv = copyout(kbuf, mu->mu_buf, mu->mu_datasize);
1831 #ifdef DIAGNOSTIC
1832 			if (rv != 0)
1833 				printf("mlx_user_command: copyout = %d\n", rv);
1834 #endif
1835 		}
1836 	}
1837 	if (kbuf != NULL)
1838 		free(kbuf, M_DEVBUF);
1839 
1840 	return (rv);
1841 }
1842 
1843 /*
1844  * Allocate and initialise a CCB.
1845  */
1846 int
1847 mlx_ccb_alloc(struct mlx_softc *mlx, struct mlx_ccb **mcp, int special)
1848 {
1849 	struct mlx_ccb *mc;
1850 	int s;
1851 
1852 	s = splbio();
1853 	if ((!special && mlx->mlx_nccbs_free < MLX_NCCBS_RESERVE) ||
1854 	    SLIST_FIRST(&mlx->mlx_ccb_freelist) == NULL) {
1855 		splx(s);
1856 		*mcp = NULL;
1857 		return (EAGAIN);
1858 	}
1859 	mc = SLIST_FIRST(&mlx->mlx_ccb_freelist);
1860 	SLIST_REMOVE_HEAD(&mlx->mlx_ccb_freelist, mc_chain.slist);
1861 	mlx->mlx_nccbs_free--;
1862 	splx(s);
1863 
1864 	*mcp = mc;
1865 	return (0);
1866 }
1867 
1868 /*
1869  * Free a CCB.
1870  */
1871 void
1872 mlx_ccb_free(struct mlx_softc *mlx, struct mlx_ccb *mc)
1873 {
1874 	int s;
1875 
1876 	s = splbio();
1877 	mc->mc_flags = 0;
1878 	SLIST_INSERT_HEAD(&mlx->mlx_ccb_freelist, mc, mc_chain.slist);
1879 	mlx->mlx_nccbs_free++;
1880 	splx(s);
1881 }
1882 
1883 /*
1884  * If a CCB is specified, enqueue it.  Pull CCBs off the software queue in
1885  * the order that they were enqueued and try to submit their mailboxes to
1886  * the controller for execution.
1887  */
1888 void
1889 mlx_ccb_enqueue(struct mlx_softc *mlx, struct mlx_ccb *mc)
1890 {
1891 	int s;
1892 
1893 	s = splbio();
1894 
1895 	if (mc != NULL)
1896 		SIMPLEQ_INSERT_TAIL(&mlx->mlx_ccb_queue, mc, mc_chain.simpleq);
1897 
1898 	while ((mc = SIMPLEQ_FIRST(&mlx->mlx_ccb_queue)) != NULL) {
1899 		if (mlx_ccb_submit(mlx, mc) != 0)
1900 			break;
1901 		SIMPLEQ_REMOVE_HEAD(&mlx->mlx_ccb_queue, mc, mc_chain.simpleq);
1902 		TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
1903 	}
1904 
1905 	splx(s);
1906 }
1907 
1908 /*
1909  * Map the specified CCB's data buffer onto the bus, and fill the
1910  * scatter-gather list.
1911  */
1912 int
1913 mlx_ccb_map(struct mlx_softc *mlx, struct mlx_ccb *mc, void *data, int size,
1914 	    int dir)
1915 {
1916 	struct mlx_sgentry *sge;
1917 	int nsegs, i, rv, sgloff;
1918 	bus_dmamap_t xfer;
1919 
1920 	xfer = mc->mc_xfer_map;
1921 
1922 	rv = bus_dmamap_load(mlx->mlx_dmat, xfer, data, size, NULL,
1923 	    BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
1924 	    ((dir & MC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
1925 	if (rv != 0)
1926 		return (rv);
1927 
1928 	nsegs = xfer->dm_nsegs;
1929 	mc->mc_xfer_size = size;
1930 	mc->mc_flags |= dir;
1931 	mc->mc_nsgent = nsegs;
1932 	mc->mc_xfer_phys = xfer->dm_segs[0].ds_addr;
1933 
1934 	sgloff = MLX_SGL_SIZE * mc->mc_ident;
1935 	sge = (struct mlx_sgentry *)((caddr_t)mlx->mlx_sgls + sgloff);
1936 
1937 	for (i = 0; i < nsegs; i++, sge++) {
1938 		sge->sge_addr = htole32(xfer->dm_segs[i].ds_addr);
1939 		sge->sge_count = htole32(xfer->dm_segs[i].ds_len);
1940 	}
1941 
1942 	if ((dir & MC_XFER_OUT) != 0)
1943 		i = BUS_DMASYNC_PREWRITE;
1944 	else
1945 		i = 0;
1946 	if ((dir & MC_XFER_IN) != 0)
1947 		i |= BUS_DMASYNC_PREREAD;
1948 
1949 	bus_dmamap_sync(mlx->mlx_dmat, xfer, 0, mc->mc_xfer_size, i);
1950 	bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap, sgloff,
1951 	    MLX_SGL_SIZE, BUS_DMASYNC_PREWRITE);
1952 
1953 	return (0);
1954 }
1955 
1956 /*
1957  * Unmap the specified CCB's data buffer.
1958  */
1959 void
1960 mlx_ccb_unmap(struct mlx_softc *mlx, struct mlx_ccb *mc)
1961 {
1962 	int i;
1963 
1964 	bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap,
1965 	    MLX_SGL_SIZE * mc->mc_ident, MLX_SGL_SIZE,
1966 	    BUS_DMASYNC_POSTWRITE);
1967 
1968 	if ((mc->mc_flags & MC_XFER_OUT) != 0)
1969 		i = BUS_DMASYNC_POSTWRITE;
1970 	else
1971 		i = 0;
1972 	if ((mc->mc_flags & MC_XFER_IN) != 0)
1973 		i |= BUS_DMASYNC_POSTREAD;
1974 
1975 	bus_dmamap_sync(mlx->mlx_dmat, mc->mc_xfer_map, 0, mc->mc_xfer_size, i);
1976 	bus_dmamap_unload(mlx->mlx_dmat, mc->mc_xfer_map);
1977 }
1978 
1979 /*
1980  * Submit the CCB, and busy-wait for it to complete.  Return non-zero on
1981  * timeout or submission error.  Must be called with interrupts blocked.
1982  */
1983 int
1984 mlx_ccb_poll(struct mlx_softc *mlx, struct mlx_ccb *mc, int timo)
1985 {
1986 	int rv;
1987 
1988 	mc->mc_mx.mx_handler = NULL;
1989 
1990 	if ((rv = mlx_ccb_submit(mlx, mc)) != 0)
1991 		return (rv);
1992 	TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
1993 
1994 	for (timo *= 10; timo != 0; timo--) {
1995 		mlx_intr(mlx);
1996 		if (mc->mc_status != MLX_STATUS_BUSY)
1997 			break;
1998 		DELAY(100);
1999 	}
2000 
2001 	if (timo != 0) {
2002 		if (mc->mc_status != 0) {
2003 			printf("%s: command failed - %s\n",
2004 			    mlx->mlx_dv.dv_xname, mlx_ccb_diagnose(mc));
2005 			rv = EIO;
2006 		} else
2007 			rv = 0;
2008 	} else {
2009 		printf("%s: command timed out\n", mlx->mlx_dv.dv_xname);
2010 		rv = EIO;
2011 	}
2012 
2013 	return (rv);
2014 }
2015 
2016 /*
2017  * Enqueue the CCB, and sleep until it completes.  Return non-zero on
2018  * timeout or error.
2019  */
2020 int
2021 mlx_ccb_wait(struct mlx_softc *mlx, struct mlx_ccb *mc)
2022 {
2023 	int s;
2024 
2025 	mc->mc_flags |= MC_WAITING;
2026 	mc->mc_mx.mx_handler = NULL;
2027 
2028 	s = splbio();
2029 	mlx_ccb_enqueue(mlx, mc);
2030 	tsleep(mc, PRIBIO, "mlxwccb", 0);
2031 	splx(s);
2032 
2033 	if (mc->mc_status != 0) {
2034 		printf("%s: command failed - %s\n", mlx->mlx_dv.dv_xname,
2035 		    mlx_ccb_diagnose(mc));
2036 		return (EIO);
2037 	}
2038 
2039 	return (0);
2040 }
2041 
2042 /*
2043  * Try to submit a CCB's mailbox to the controller for execution.  Return
2044  * non-zero on timeout or error.  Must be called with interrupts blocked.
2045  */
2046 static int
2047 mlx_ccb_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
2048 {
2049 	int i, s, r;
2050 
2051 	/* Save the ident so we can handle this command when complete. */
2052 	mc->mc_mbox[1] = (u_int8_t)mc->mc_ident;
2053 
2054 	/* Mark the command as currently being processed. */
2055 	mc->mc_status = MLX_STATUS_BUSY;
2056 	mc->mc_expiry = mlx_curtime() + MLX_TIMEOUT;
2057 
2058 	/* Spin waiting for the mailbox. */
2059 	for (i = 100; i != 0; i--) {
2060 		s = splbio();
2061 		r = (*mlx->mlx_submit)(mlx, mc);
2062 		splx(s);
2063 		if (r != 0)
2064 			break;
2065 		DELAY(100);
2066 	}
2067 	if (i != 0)
2068 		return (0);
2069 
2070 	DPRINTF(("mlx_ccb_submit: rejected; queueing\n"));
2071 	mc->mc_status = MLX_STATUS_WEDGED;
2072 	return (EIO);
2073 }
2074 
2075 /*
2076  * Return a string that describes why a command has failed.
2077  */
2078 const char *
2079 mlx_ccb_diagnose(struct mlx_ccb *mc)
2080 {
2081 	static char buf[80];
2082 	int i;
2083 
2084 	for (i = 0; i < sizeof(mlx_msgs) / sizeof(mlx_msgs[0]); i++)
2085 		if ((mc->mc_mbox[0] == mlx_msgs[i].command ||
2086 		    mlx_msgs[i].command == 0) &&
2087 		    mc->mc_status == mlx_msgs[i].status) {
2088 			sprintf(buf, "%s (0x%x)",
2089 			    mlx_status_msgs[mlx_msgs[i].msg], mc->mc_status);
2090 			return (buf);
2091 		}
2092 
2093 	sprintf(buf, "unknown response 0x%x for command 0x%x",
2094 	    (int)mc->mc_status, (int)mc->mc_mbox[0]);
2095 
2096 	return (buf);
2097 }
2098 
2099 /*
2100  * Poll the controller for completed commands.  Returns non-zero if one or
2101  * more commands were completed.  Must be called with interrupts blocked.
2102  */
2103 int
2104 mlx_intr(void *cookie)
2105 {
2106 	struct mlx_softc *mlx;
2107 	struct mlx_ccb *mc;
2108 	int result;
2109 	u_int ident, status;
2110 
2111 	mlx = cookie;
2112 	result = 0;
2113 
2114 	while ((*mlx->mlx_findcomplete)(mlx, &ident, &status) != 0) {
2115 		result = 1;
2116 
2117 		if (ident >= MLX_MAX_QUEUECNT) {
2118 			printf("%s: bad completion returned\n",
2119 			    mlx->mlx_dv.dv_xname);
2120 			continue;
2121 		}
2122 
2123 		mc = mlx->mlx_ccbs + ident;
2124 
2125 		if (mc->mc_status != MLX_STATUS_BUSY) {
2126 			printf("%s: bad completion returned\n",
2127 			    mlx->mlx_dv.dv_xname);
2128 			continue;
2129 		}
2130 
2131 		TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
2132 
2133 		/* Record status and notify the initiator, if requested. */
2134 		mc->mc_status = status;
2135 		if (mc->mc_mx.mx_handler != NULL)
2136 			(*mc->mc_mx.mx_handler)(mc);
2137 		else if ((mc->mc_flags & MC_WAITING) != 0)
2138 			wakeup(mc);
2139 	}
2140 
2141 	/* If we've completed any commands, try posting some more. */
2142 	if (result)
2143 		mlx_ccb_enqueue(mlx, NULL);
2144 
2145 	return (result);
2146 }
2147 
2148 /*
2149  * Emit a string describing the firmware handshake status code, and return a
2150  * flag indicating whether the code represents a fatal error.
2151  *
2152  * Error code interpretations are from the Linux driver, and don't directly
2153  * match the messages printed by Mylex's BIOS.  This may change if
2154  * documentation on the codes is forthcoming.
2155  */
2156 static int
2157 mlx_fw_message(struct mlx_softc *mlx, int error, int param1, int param2)
2158 {
2159 	const char *fmt;
2160 
2161 	switch (error) {
2162 	case 0x00:
2163 		fmt = "physical drive %d:%d not responding";
2164 		break;
2165 
2166 	case 0x08:
2167 		/*
2168 		 * We could be neater about this and give some indication
2169 		 * when we receive more of them.
2170 		 */
2171 		if ((mlx->mlx_flags & MLXF_SPINUP_REPORTED) == 0) {
2172 			printf("%s: spinning up drives...\n",
2173 			    mlx->mlx_dv.dv_xname);
2174 			mlx->mlx_flags |= MLXF_SPINUP_REPORTED;
2175 		}
2176 		break;
2177 
2178 	case 0x30:
2179 		fmt = "configuration checksum error";
2180 		break;
2181 
2182 	case 0x60:
2183 		fmt = "mirror race recovery failed";
2184 		break;
2185 
2186 	case 0x70:
2187 		fmt = "mirror race recovery in progress";
2188 		break;
2189 
2190 	case 0x90:
2191 		fmt = "physical drive %d:%d COD mismatch";
2192 		break;
2193 
2194 	case 0xa0:
2195 		fmt = "logical drive installation aborted";
2196 		break;
2197 
2198 	case 0xb0:
2199 		fmt = "mirror race on a critical system drive";
2200 		break;
2201 
2202 	case 0xd0:
2203 		fmt = "new controller configuration found";
2204 		break;
2205 
2206 	case 0xf0:
2207 		fmt = "FATAL MEMORY PARITY ERROR";
2208 		return (1);
2209 
2210 	default:
2211 		printf("%s: unknown firmware init error %02x:%02x:%02x\n",
2212 		    mlx->mlx_dv.dv_xname, error, param1, param2);
2213 		return (0);
2214 	}
2215 
2216 	printf("%s: ", mlx->mlx_dv.dv_xname);
2217 	printf(fmt, param2, param1);
2218 	printf("\n");
2219 
2220 	return (0);
2221 }
2222