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