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