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