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