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