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