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