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