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