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