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