1 /* $NetBSD: mlx_pci.c,v 1.26 2016/09/27 03:33:32 pgoyette Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /*- 33 * Copyright (c) 1999 Michael Smith 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 * 57 * from FreeBSD: mlx_pci.c,v 1.4.2.4 2000/10/28 10:48:09 msmith Exp 58 */ 59 60 /* 61 * PCI front-end for the mlx(4) driver. 62 */ 63 64 #include <sys/cdefs.h> 65 __KERNEL_RCSID(0, "$NetBSD: mlx_pci.c,v 1.26 2016/09/27 03:33:32 pgoyette Exp $"); 66 67 #include <sys/param.h> 68 #include <sys/systm.h> 69 #include <sys/kernel.h> 70 #include <sys/device.h> 71 #include <sys/queue.h> 72 #include <sys/callout.h> 73 #include <sys/module.h> 74 75 #include <machine/endian.h> 76 #include <sys/bus.h> 77 78 #include <dev/ic/mlxreg.h> 79 #include <dev/ic/mlxio.h> 80 #include <dev/ic/mlxvar.h> 81 82 #include <dev/pci/pcireg.h> 83 #include <dev/pci/pcivar.h> 84 #include <dev/pci/pcidevs.h> 85 86 #include "ioconf.h" 87 88 static void mlx_pci_attach(device_t, device_t, void *); 89 static int mlx_pci_match(device_t, cfdata_t, void *); 90 static const struct mlx_pci_ident *mlx_pci_findmpi(struct pci_attach_args *); 91 92 static int mlx_v3_submit(struct mlx_softc *, struct mlx_ccb *); 93 static int mlx_v3_findcomplete(struct mlx_softc *, u_int *, u_int *); 94 static void mlx_v3_intaction(struct mlx_softc *, int); 95 static int mlx_v3_fw_handshake(struct mlx_softc *, int *, int *, int *); 96 #ifdef MLX_RESET 97 static int mlx_v3_reset(struct mlx_softc *); 98 #endif 99 100 static int mlx_v4_submit(struct mlx_softc *, struct mlx_ccb *); 101 static int mlx_v4_findcomplete(struct mlx_softc *, u_int *, u_int *); 102 static void mlx_v4_intaction(struct mlx_softc *, int); 103 static int mlx_v4_fw_handshake(struct mlx_softc *, int *, int *, int *); 104 105 static int mlx_v5_submit(struct mlx_softc *, struct mlx_ccb *); 106 static int mlx_v5_findcomplete(struct mlx_softc *, u_int *, u_int *); 107 static void mlx_v5_intaction(struct mlx_softc *, int); 108 static int mlx_v5_fw_handshake(struct mlx_softc *, int *, int *, int *); 109 110 static struct mlx_pci_ident { 111 u_short mpi_vendor; 112 u_short mpi_product; 113 u_short mpi_subvendor; 114 u_short mpi_subproduct; 115 int mpi_iftype; 116 } const mlx_pci_ident[] = { 117 { 118 PCI_VENDOR_MYLEX, 119 PCI_PRODUCT_MYLEX_RAID_V2, 120 0x0000, 121 0x0000, 122 2, 123 }, 124 { 125 PCI_VENDOR_MYLEX, 126 PCI_PRODUCT_MYLEX_RAID_V3, 127 0x0000, 128 0x0000, 129 3, 130 }, 131 { 132 PCI_VENDOR_MYLEX, 133 PCI_PRODUCT_MYLEX_RAID_V4, 134 0x0000, 135 0x0000, 136 4, 137 }, 138 { 139 PCI_VENDOR_DEC, 140 PCI_PRODUCT_DEC_SWXCR, 141 PCI_VENDOR_MYLEX, 142 PCI_PRODUCT_MYLEX_RAID_V5, 143 5, 144 }, 145 }; 146 147 static int 148 mlx_pci_rescan(device_t self, const char *attr, const int *flag) 149 { 150 151 return mlx_configure(device_private(self), 1); 152 } 153 154 CFATTACH_DECL3_NEW(mlx_pci, sizeof(struct mlx_softc), 155 mlx_pci_match, mlx_pci_attach, NULL, NULL, mlx_pci_rescan, NULL, 0); 156 157 /* 158 * Try to find a `mlx_pci_ident' entry corresponding to this board. 159 */ 160 static const struct mlx_pci_ident * 161 mlx_pci_findmpi(struct pci_attach_args *pa) 162 { 163 const struct mlx_pci_ident *mpi, *maxmpi; 164 pcireg_t reg; 165 166 mpi = mlx_pci_ident; 167 maxmpi = mpi + sizeof(mlx_pci_ident) / sizeof(mlx_pci_ident[0]); 168 169 for (; mpi < maxmpi; mpi++) { 170 if (PCI_VENDOR(pa->pa_id) != mpi->mpi_vendor || 171 PCI_PRODUCT(pa->pa_id) != mpi->mpi_product) 172 continue; 173 174 if (mpi->mpi_subvendor == 0x0000) 175 return (mpi); 176 177 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 178 179 if (PCI_VENDOR(reg) == mpi->mpi_subvendor && 180 PCI_PRODUCT(reg) == mpi->mpi_subproduct) 181 return (mpi); 182 } 183 184 return (NULL); 185 } 186 187 /* 188 * Match a supported board. 189 */ 190 static int 191 mlx_pci_match(device_t parent, cfdata_t cfdata, void *aux) 192 { 193 194 return (mlx_pci_findmpi(aux) != NULL); 195 } 196 197 /* 198 * Attach a supported board. 199 */ 200 static void 201 mlx_pci_attach(device_t parent, device_t self, void *aux) 202 { 203 struct pci_attach_args *pa; 204 struct mlx_softc *mlx; 205 pci_chipset_tag_t pc; 206 pci_intr_handle_t ih; 207 bus_space_handle_t memh, ioh; 208 bus_space_tag_t memt, iot; 209 pcireg_t reg; 210 const char *intrstr; 211 int ior, memr, i; 212 const struct mlx_pci_ident *mpi; 213 char intrbuf[PCI_INTRSTR_LEN]; 214 215 mlx = device_private(self); 216 pa = aux; 217 pc = pa->pa_pc; 218 mpi = mlx_pci_findmpi(aux); 219 220 mlx->mlx_dv = self; 221 mlx->mlx_dmat = pa->pa_dmat; 222 mlx->mlx_ci.ci_iftype = mpi->mpi_iftype; 223 224 printf(": Mylex RAID (v%d interface)\n", mpi->mpi_iftype); 225 226 /* 227 * Map the PCI register window. 228 */ 229 memr = -1; 230 ior = -1; 231 232 for (i = 0x10; i <= 0x14; i += 4) { 233 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, i); 234 235 if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) { 236 if (ior == -1 && PCI_MAPREG_IO_SIZE(reg) != 0) 237 ior = i; 238 } else { 239 if (memr == -1 && PCI_MAPREG_MEM_SIZE(reg) != 0) 240 memr = i; 241 } 242 } 243 244 if (memr != -1) 245 if (pci_mapreg_map(pa, memr, PCI_MAPREG_TYPE_MEM, 0, 246 &memt, &memh, NULL, NULL)) 247 memr = -1; 248 if (ior != -1) 249 if (pci_mapreg_map(pa, ior, PCI_MAPREG_TYPE_IO, 0, 250 &iot, &ioh, NULL, NULL)) 251 ior = -1; 252 253 if (memr != -1) { 254 mlx->mlx_iot = memt; 255 mlx->mlx_ioh = memh; 256 } else if (ior != -1) { 257 mlx->mlx_iot = iot; 258 mlx->mlx_ioh = ioh; 259 } else { 260 aprint_error_dev(self, "can't map i/o or memory space\n"); 261 return; 262 } 263 264 /* Enable the device. */ 265 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 266 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 267 reg | PCI_COMMAND_MASTER_ENABLE); 268 269 /* Map and establish the interrupt. */ 270 if (pci_intr_map(pa, &ih)) { 271 aprint_error_dev(self, "can't map interrupt\n"); 272 return; 273 } 274 intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); 275 mlx->mlx_ih = pci_intr_establish(pc, ih, IPL_BIO, mlx_intr, mlx); 276 if (mlx->mlx_ih == NULL) { 277 aprint_error_dev(self, "can't establish interrupt"); 278 if (intrstr != NULL) 279 aprint_error(" at %s", intrstr); 280 aprint_error("\n"); 281 return; 282 } 283 284 /* Select linkage based on controller interface type. */ 285 switch (mlx->mlx_ci.ci_iftype) { 286 case 2: 287 case 3: 288 mlx->mlx_submit = mlx_v3_submit; 289 mlx->mlx_findcomplete = mlx_v3_findcomplete; 290 mlx->mlx_intaction = mlx_v3_intaction; 291 mlx->mlx_fw_handshake = mlx_v3_fw_handshake; 292 #ifdef MLX_RESET 293 mlx->mlx_reset = mlx_v3_reset; 294 #endif 295 break; 296 297 case 4: 298 mlx->mlx_submit = mlx_v4_submit; 299 mlx->mlx_findcomplete = mlx_v4_findcomplete; 300 mlx->mlx_intaction = mlx_v4_intaction; 301 mlx->mlx_fw_handshake = mlx_v4_fw_handshake; 302 break; 303 304 case 5: 305 mlx->mlx_submit = mlx_v5_submit; 306 mlx->mlx_findcomplete = mlx_v5_findcomplete; 307 mlx->mlx_intaction = mlx_v5_intaction; 308 mlx->mlx_fw_handshake = mlx_v5_fw_handshake; 309 break; 310 } 311 312 mlx_init(mlx, intrstr); 313 } 314 315 /* 316 * ================= V3 interface linkage ================= 317 */ 318 319 /* 320 * Try to give (mc) to the controller. Returns 1 if successful, 0 on 321 * failure (the controller is not ready to take a command). 322 * 323 * Must be called at splbio or in a fashion that prevents reentry. 324 */ 325 static int 326 mlx_v3_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 327 { 328 329 /* Ready for our command? */ 330 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_FULL) == 0) { 331 /* Copy mailbox data to window. */ 332 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh, 333 MLX_V3REG_MAILBOX, mc->mc_mbox, 13); 334 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 335 MLX_V3REG_MAILBOX, 13, 336 BUS_SPACE_BARRIER_WRITE); 337 338 /* Post command. */ 339 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_FULL); 340 return (1); 341 } 342 343 return (0); 344 } 345 346 /* 347 * See if a command has been completed, if so acknowledge its completion and 348 * recover the slot number and status code. 349 * 350 * Must be called at splbio or in a fashion that prevents reentry. 351 */ 352 static int 353 mlx_v3_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 354 { 355 356 /* Status available? */ 357 if ((mlx_inb(mlx, MLX_V3REG_ODB) & MLX_V3_ODB_SAVAIL) != 0) { 358 *slot = mlx_inb(mlx, MLX_V3REG_STATUS_IDENT); 359 *status = mlx_inw(mlx, MLX_V3REG_STATUS); 360 361 /* Acknowledge completion. */ 362 mlx_outb(mlx, MLX_V3REG_ODB, MLX_V3_ODB_SAVAIL); 363 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 364 return (1); 365 } 366 367 return (0); 368 } 369 370 /* 371 * Enable/disable interrupts as requested. (No acknowledge required) 372 * 373 * Must be called at splbio or in a fashion that prevents reentry. 374 */ 375 static void 376 mlx_v3_intaction(struct mlx_softc *mlx, int action) 377 { 378 379 mlx_outb(mlx, MLX_V3REG_IE, action != 0); 380 } 381 382 /* 383 * Poll for firmware error codes during controller initialisation. 384 * 385 * Returns 0 if initialisation is complete, 1 if still in progress but no 386 * error has been fetched, 2 if an error has been retrieved. 387 */ 388 static int 389 mlx_v3_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 390 { 391 u_int8_t fwerror; 392 393 /* First time around, clear any hardware completion status. */ 394 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 395 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 396 DELAY(1000); 397 mlx->mlx_flags |= MLXF_FW_INITTED; 398 } 399 400 /* Init in progress? */ 401 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_INIT_BUSY) == 0) 402 return (0); 403 404 /* Test error value. */ 405 fwerror = mlx_inb(mlx, MLX_V3REG_FWERROR); 406 407 if ((fwerror & MLX_V3_FWERROR_PEND) == 0) 408 return (1); 409 410 /* Mask status pending bit, fetch status. */ 411 *error = fwerror & ~MLX_V3_FWERROR_PEND; 412 *param1 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM1); 413 *param2 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM2); 414 415 /* Acknowledge. */ 416 mlx_outb(mlx, MLX_V3REG_FWERROR, 0); 417 418 return (2); 419 } 420 421 #ifdef MLX_RESET 422 /* 423 * Reset the controller. Return non-zero on failure. 424 */ 425 static int 426 mlx_v3_reset(struct mlx_softc *mlx) 427 { 428 int i; 429 430 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 431 delay(1000000); 432 433 /* Wait up to 2 minutes for the bit to clear. */ 434 for (i = 120; i != 0; i--) { 435 delay(1000000); 436 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_SACK) == 0) 437 break; 438 } 439 if (i == 0) { 440 /* ZZZ */ 441 printf("mlx0: SACK didn't clear\n"); 442 return (-1); 443 } 444 445 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_RESET); 446 447 /* Wait up to 5 seconds for the bit to clear. */ 448 for (i = 5; i != 0; i--) { 449 delay(1000000); 450 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_RESET) == 0) 451 break; 452 } 453 if (i == 0) { 454 /* ZZZ */ 455 printf("mlx0: RESET didn't clear\n"); 456 return (-1); 457 } 458 459 return (0); 460 } 461 #endif /* MLX_RESET */ 462 463 /* 464 * ================= V4 interface linkage ================= 465 */ 466 467 /* 468 * Try to give (mc) to the controller. Returns 1 if successful, 0 on 469 * failure (the controller is not ready to take a command). 470 * 471 * Must be called at splbio or in a fashion that prevents reentry. 472 */ 473 static int 474 mlx_v4_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 475 { 476 477 /* Ready for our command? */ 478 if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_FULL) == 0) { 479 /* Copy mailbox data to window. */ 480 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh, 481 MLX_V4REG_MAILBOX, mc->mc_mbox, 13); 482 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 483 MLX_V4REG_MAILBOX, 13, 484 BUS_SPACE_BARRIER_WRITE); 485 486 /* Post command. */ 487 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_HWMBOX_CMD); 488 return (1); 489 } 490 491 return (0); 492 } 493 494 /* 495 * See if a command has been completed, if so acknowledge its completion and 496 * recover the slot number and status code. 497 * 498 * Must be called at splbio or in a fashion that prevents reentry. 499 */ 500 static int 501 mlx_v4_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 502 { 503 504 /* Status available? */ 505 if ((mlx_inl(mlx, MLX_V4REG_ODB) & MLX_V4_ODB_HWSAVAIL) != 0) { 506 *slot = mlx_inb(mlx, MLX_V4REG_STATUS_IDENT); 507 *status = mlx_inw(mlx, MLX_V4REG_STATUS); 508 509 /* Acknowledge completion. */ 510 mlx_outl(mlx, MLX_V4REG_ODB, MLX_V4_ODB_HWMBOX_ACK); 511 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK); 512 return (1); 513 } 514 515 return (0); 516 } 517 518 /* 519 * Enable/disable interrupts as requested. 520 * 521 * Must be called at splbio or in a fashion that prevents reentry. 522 */ 523 static void 524 mlx_v4_intaction(struct mlx_softc *mlx, int action) 525 { 526 u_int32_t ier; 527 528 if (!action) 529 ier = MLX_V4_IE_MASK | MLX_V4_IE_DISINT; 530 else 531 ier = MLX_V4_IE_MASK & ~MLX_V4_IE_DISINT; 532 533 mlx_outl(mlx, MLX_V4REG_IE, ier); 534 } 535 536 /* 537 * Poll for firmware error codes during controller initialisation. 538 * 539 * Returns 0 if initialisation is complete, 1 if still in progress but no 540 * error has been fetched, 2 if an error has been retrieved. 541 */ 542 static int 543 mlx_v4_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 544 { 545 u_int8_t fwerror; 546 547 /* First time around, clear any hardware completion status. */ 548 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 549 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK); 550 DELAY(1000); 551 mlx->mlx_flags |= MLXF_FW_INITTED; 552 } 553 554 /* Init in progress? */ 555 if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_INIT_BUSY) == 0) 556 return (0); 557 558 /* Test error value */ 559 fwerror = mlx_inb(mlx, MLX_V4REG_FWERROR); 560 if ((fwerror & MLX_V4_FWERROR_PEND) == 0) 561 return (1); 562 563 /* Mask status pending bit, fetch status. */ 564 *error = fwerror & ~MLX_V4_FWERROR_PEND; 565 *param1 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM1); 566 *param2 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM2); 567 568 /* Acknowledge. */ 569 mlx_outb(mlx, MLX_V4REG_FWERROR, 0); 570 571 return (2); 572 } 573 574 /* 575 * ================= V5 interface linkage ================= 576 */ 577 578 /* 579 * Try to give (mc) to the controller. Returns 1 if successful, 0 on failure 580 * (the controller is not ready to take a command). 581 * 582 * Must be called at splbio or in a fashion that prevents reentry. 583 */ 584 static int 585 mlx_v5_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 586 { 587 588 /* Ready for our command? */ 589 if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_EMPTY) != 0) { 590 /* Copy mailbox data to window. */ 591 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh, 592 MLX_V5REG_MAILBOX, mc->mc_mbox, 13); 593 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 594 MLX_V5REG_MAILBOX, 13, 595 BUS_SPACE_BARRIER_WRITE); 596 597 /* Post command */ 598 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_HWMBOX_CMD); 599 return (1); 600 } 601 602 return (0); 603 } 604 605 /* 606 * See if a command has been completed, if so acknowledge its completion and 607 * recover the slot number and status code. 608 * 609 * Must be called at splbio or in a fashion that prevents reentry. 610 */ 611 static int 612 mlx_v5_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 613 { 614 615 /* Status available? */ 616 if ((mlx_inb(mlx, MLX_V5REG_ODB) & MLX_V5_ODB_HWSAVAIL) != 0) { 617 *slot = mlx_inb(mlx, MLX_V5REG_STATUS_IDENT); 618 *status = mlx_inw(mlx, MLX_V5REG_STATUS); 619 620 /* Acknowledge completion. */ 621 mlx_outb(mlx, MLX_V5REG_ODB, MLX_V5_ODB_HWMBOX_ACK); 622 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK); 623 return (1); 624 } 625 626 return (0); 627 } 628 629 /* 630 * Enable/disable interrupts as requested. 631 * 632 * Must be called at splbio or in a fashion that prevents reentry. 633 */ 634 static void 635 mlx_v5_intaction(struct mlx_softc *mlx, int action) 636 { 637 u_int8_t ier; 638 639 if (!action) 640 ier = 0xff & MLX_V5_IE_DISINT; 641 else 642 ier = 0xff & ~MLX_V5_IE_DISINT; 643 644 mlx_outb(mlx, MLX_V5REG_IE, ier); 645 } 646 647 /* 648 * Poll for firmware error codes during controller initialisation. 649 * 650 * Returns 0 if initialisation is complete, 1 if still in progress but no 651 * error has been fetched, 2 if an error has been retrieved. 652 */ 653 static int 654 mlx_v5_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 655 { 656 u_int8_t fwerror; 657 658 /* First time around, clear any hardware completion status. */ 659 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 660 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK); 661 DELAY(1000); 662 mlx->mlx_flags |= MLXF_FW_INITTED; 663 } 664 665 /* Init in progress? */ 666 if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_INIT_DONE) != 0) 667 return (0); 668 669 /* Test for error value. */ 670 fwerror = mlx_inb(mlx, MLX_V5REG_FWERROR); 671 if ((fwerror & MLX_V5_FWERROR_PEND) == 0) 672 return (1); 673 674 /* Mask status pending bit, fetch status. */ 675 *error = fwerror & ~MLX_V5_FWERROR_PEND; 676 *param1 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM1); 677 *param2 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM2); 678 679 /* Acknowledge. */ 680 mlx_outb(mlx, MLX_V5REG_FWERROR, 0xff); 681 682 return (2); 683 } 684 685 MODULE(MODULE_CLASS_DRIVER, mlx_pci, "mlx,pci"); 686 687 #ifdef _MODULE 688 /* 689 * XXX Don't allow ioconf.c to redefine the "struct cfdriver ld_cd" 690 * XXX it will be defined in the common-code module 691 */ 692 #undef CFDRIVER_DECL 693 #define CFDRIVER_DECL(name, class, attr) 694 #include "ioconf.c" 695 #endif 696 697 static int 698 mlx_pci_modcmd(modcmd_t cmd, void *opaque) 699 { 700 int error = 0; 701 702 #ifdef _MODULE 703 switch (cmd) { 704 case MODULE_CMD_INIT: 705 /* 706 * We skip over the first entry in cfdriver[] array 707 * since the cfdriver is attached by the common 708 * (non-attachment-specific) code. 709 */ 710 error = config_init_component(&cfdriver_ioconf_mlx_pci[1], 711 cfattach_ioconf_mlx_pci, cfdata_ioconf_mlx_pci); 712 break; 713 case MODULE_CMD_FINI: 714 error = config_fini_component(&cfdriver_ioconf_mlx_pci[1], 715 cfattach_ioconf_mlx_pci, cfdata_ioconf_mlx_pci); 716 break; 717 default: 718 error = ENOTTY; 719 break; 720 } 721 #endif 722 723 return error; 724 } 725