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