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