| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Driver for Adaptec AHA-1542 SCSI host adapters |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 58 | 59 | int aha1542_last_mbi_used; |
|---|
| 59 | 60 | int aha1542_last_mbo_used; |
|---|
| 60 | 61 | struct scsi_cmnd *int_cmds[AHA1542_MAILBOXES]; |
|---|
| 61 | | - struct mailbox mb[2 * AHA1542_MAILBOXES]; |
|---|
| 62 | | - struct ccb ccb[AHA1542_MAILBOXES]; |
|---|
| 62 | + struct mailbox *mb; |
|---|
| 63 | + dma_addr_t mb_handle; |
|---|
| 64 | + struct ccb *ccb; |
|---|
| 65 | + dma_addr_t ccb_handle; |
|---|
| 66 | +}; |
|---|
| 67 | + |
|---|
| 68 | +struct aha1542_cmd { |
|---|
| 69 | + struct chain *chain; |
|---|
| 70 | + dma_addr_t chain_handle; |
|---|
| 63 | 71 | }; |
|---|
| 64 | 72 | |
|---|
| 65 | 73 | static inline void aha1542_intr_reset(u16 base) |
|---|
| .. | .. |
|---|
| 233 | 241 | return 1; |
|---|
| 234 | 242 | } |
|---|
| 235 | 243 | |
|---|
| 244 | +static void aha1542_free_cmd(struct scsi_cmnd *cmd) |
|---|
| 245 | +{ |
|---|
| 246 | + struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); |
|---|
| 247 | + struct device *dev = cmd->device->host->dma_dev; |
|---|
| 248 | + size_t len = scsi_sg_count(cmd) * sizeof(struct chain); |
|---|
| 249 | + |
|---|
| 250 | + if (acmd->chain) { |
|---|
| 251 | + dma_unmap_single(dev, acmd->chain_handle, len, DMA_TO_DEVICE); |
|---|
| 252 | + kfree(acmd->chain); |
|---|
| 253 | + } |
|---|
| 254 | + |
|---|
| 255 | + acmd->chain = NULL; |
|---|
| 256 | + scsi_dma_unmap(cmd); |
|---|
| 257 | +} |
|---|
| 258 | + |
|---|
| 236 | 259 | static irqreturn_t aha1542_interrupt(int irq, void *dev_id) |
|---|
| 237 | 260 | { |
|---|
| 238 | 261 | struct Scsi_Host *sh = dev_id; |
|---|
| .. | .. |
|---|
| 303 | 326 | return IRQ_HANDLED; |
|---|
| 304 | 327 | }; |
|---|
| 305 | 328 | |
|---|
| 306 | | - mbo = (scsi2int(mb[mbi].ccbptr) - (isa_virt_to_bus(&ccb[0]))) / sizeof(struct ccb); |
|---|
| 329 | + mbo = (scsi2int(mb[mbi].ccbptr) - (unsigned long)aha1542->ccb_handle) / sizeof(struct ccb); |
|---|
| 307 | 330 | mbistatus = mb[mbi].status; |
|---|
| 308 | 331 | mb[mbi].status = 0; |
|---|
| 309 | 332 | aha1542->aha1542_last_mbi_used = mbi; |
|---|
| .. | .. |
|---|
| 331 | 354 | return IRQ_HANDLED; |
|---|
| 332 | 355 | } |
|---|
| 333 | 356 | my_done = tmp_cmd->scsi_done; |
|---|
| 334 | | - kfree(tmp_cmd->host_scribble); |
|---|
| 335 | | - tmp_cmd->host_scribble = NULL; |
|---|
| 357 | + aha1542_free_cmd(tmp_cmd); |
|---|
| 336 | 358 | /* Fetch the sense data, and tuck it away, in the required slot. The |
|---|
| 337 | 359 | Adaptec automatically fetches it, and there is no guarantee that |
|---|
| 338 | 360 | we will still have it in the cdb when we come back */ |
|---|
| .. | .. |
|---|
| 369 | 391 | |
|---|
| 370 | 392 | static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) |
|---|
| 371 | 393 | { |
|---|
| 394 | + struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); |
|---|
| 372 | 395 | struct aha1542_hostdata *aha1542 = shost_priv(sh); |
|---|
| 373 | 396 | u8 direction; |
|---|
| 374 | 397 | u8 target = cmd->device->id; |
|---|
| .. | .. |
|---|
| 378 | 401 | int mbo, sg_count; |
|---|
| 379 | 402 | struct mailbox *mb = aha1542->mb; |
|---|
| 380 | 403 | struct ccb *ccb = aha1542->ccb; |
|---|
| 381 | | - struct chain *cptr; |
|---|
| 382 | 404 | |
|---|
| 383 | 405 | if (*cmd->cmnd == REQUEST_SENSE) { |
|---|
| 384 | 406 | /* Don't do the command - we have the sense data already */ |
|---|
| .. | .. |
|---|
| 398 | 420 | print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len); |
|---|
| 399 | 421 | } |
|---|
| 400 | 422 | #endif |
|---|
| 401 | | - if (bufflen) { /* allocate memory before taking host_lock */ |
|---|
| 402 | | - sg_count = scsi_sg_count(cmd); |
|---|
| 403 | | - cptr = kmalloc_array(sg_count, sizeof(*cptr), |
|---|
| 404 | | - GFP_KERNEL | GFP_DMA); |
|---|
| 405 | | - if (!cptr) |
|---|
| 406 | | - return SCSI_MLQUEUE_HOST_BUSY; |
|---|
| 407 | | - } else { |
|---|
| 408 | | - sg_count = 0; |
|---|
| 409 | | - cptr = NULL; |
|---|
| 423 | + sg_count = scsi_dma_map(cmd); |
|---|
| 424 | + if (sg_count) { |
|---|
| 425 | + size_t len = sg_count * sizeof(struct chain); |
|---|
| 426 | + |
|---|
| 427 | + acmd->chain = kmalloc(len, GFP_DMA); |
|---|
| 428 | + if (!acmd->chain) |
|---|
| 429 | + goto out_unmap; |
|---|
| 430 | + acmd->chain_handle = dma_map_single(sh->dma_dev, acmd->chain, |
|---|
| 431 | + len, DMA_TO_DEVICE); |
|---|
| 432 | + if (dma_mapping_error(sh->dma_dev, acmd->chain_handle)) |
|---|
| 433 | + goto out_free_chain; |
|---|
| 410 | 434 | } |
|---|
| 411 | 435 | |
|---|
| 412 | 436 | /* Use the outgoing mailboxes in a round-robin fashion, because this |
|---|
| .. | .. |
|---|
| 437 | 461 | shost_printk(KERN_DEBUG, sh, "Sending command (%d %p)...", mbo, cmd->scsi_done); |
|---|
| 438 | 462 | #endif |
|---|
| 439 | 463 | |
|---|
| 440 | | - any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */ |
|---|
| 464 | + /* This gets trashed for some reason */ |
|---|
| 465 | + any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb)); |
|---|
| 441 | 466 | |
|---|
| 442 | 467 | memset(&ccb[mbo], 0, sizeof(struct ccb)); |
|---|
| 443 | 468 | |
|---|
| .. | .. |
|---|
| 456 | 481 | int i; |
|---|
| 457 | 482 | |
|---|
| 458 | 483 | ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */ |
|---|
| 459 | | - cmd->host_scribble = (void *)cptr; |
|---|
| 460 | 484 | scsi_for_each_sg(cmd, sg, sg_count, i) { |
|---|
| 461 | | - any2scsi(cptr[i].dataptr, isa_page_to_bus(sg_page(sg)) |
|---|
| 462 | | - + sg->offset); |
|---|
| 463 | | - any2scsi(cptr[i].datalen, sg->length); |
|---|
| 485 | + any2scsi(acmd->chain[i].dataptr, sg_dma_address(sg)); |
|---|
| 486 | + any2scsi(acmd->chain[i].datalen, sg_dma_len(sg)); |
|---|
| 464 | 487 | }; |
|---|
| 465 | 488 | any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain)); |
|---|
| 466 | | - any2scsi(ccb[mbo].dataptr, isa_virt_to_bus(cptr)); |
|---|
| 489 | + any2scsi(ccb[mbo].dataptr, acmd->chain_handle); |
|---|
| 467 | 490 | #ifdef DEBUG |
|---|
| 468 | | - shost_printk(KERN_DEBUG, sh, "cptr %p: ", cptr); |
|---|
| 469 | | - print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, cptr, 18); |
|---|
| 491 | + shost_printk(KERN_DEBUG, sh, "cptr %p: ", acmd->chain); |
|---|
| 492 | + print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, acmd->chain, 18); |
|---|
| 470 | 493 | #endif |
|---|
| 471 | 494 | } else { |
|---|
| 472 | 495 | ccb[mbo].op = 0; /* SCSI Initiator Command */ |
|---|
| 473 | | - cmd->host_scribble = NULL; |
|---|
| 474 | 496 | any2scsi(ccb[mbo].datalen, 0); |
|---|
| 475 | 497 | any2scsi(ccb[mbo].dataptr, 0); |
|---|
| 476 | 498 | }; |
|---|
| .. | .. |
|---|
| 488 | 510 | spin_unlock_irqrestore(sh->host_lock, flags); |
|---|
| 489 | 511 | |
|---|
| 490 | 512 | return 0; |
|---|
| 513 | +out_free_chain: |
|---|
| 514 | + kfree(acmd->chain); |
|---|
| 515 | + acmd->chain = NULL; |
|---|
| 516 | +out_unmap: |
|---|
| 517 | + scsi_dma_unmap(cmd); |
|---|
| 518 | + return SCSI_MLQUEUE_HOST_BUSY; |
|---|
| 491 | 519 | } |
|---|
| 492 | 520 | |
|---|
| 493 | 521 | /* Initialize mailboxes */ |
|---|
| 494 | 522 | static void setup_mailboxes(struct Scsi_Host *sh) |
|---|
| 495 | 523 | { |
|---|
| 496 | 524 | struct aha1542_hostdata *aha1542 = shost_priv(sh); |
|---|
| 497 | | - int i; |
|---|
| 498 | | - struct mailbox *mb = aha1542->mb; |
|---|
| 499 | | - struct ccb *ccb = aha1542->ccb; |
|---|
| 500 | | - |
|---|
| 501 | 525 | u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0}; |
|---|
| 526 | + int i; |
|---|
| 502 | 527 | |
|---|
| 503 | 528 | for (i = 0; i < AHA1542_MAILBOXES; i++) { |
|---|
| 504 | | - mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0; |
|---|
| 505 | | - any2scsi(mb[i].ccbptr, isa_virt_to_bus(&ccb[i])); |
|---|
| 529 | + aha1542->mb[i].status = 0; |
|---|
| 530 | + any2scsi(aha1542->mb[i].ccbptr, |
|---|
| 531 | + aha1542->ccb_handle + i * sizeof(struct ccb)); |
|---|
| 532 | + aha1542->mb[AHA1542_MAILBOXES + i].status = 0; |
|---|
| 506 | 533 | }; |
|---|
| 507 | 534 | aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */ |
|---|
| 508 | | - any2scsi((mb_cmd + 2), isa_virt_to_bus(mb)); |
|---|
| 535 | + any2scsi(mb_cmd + 2, aha1542->mb_handle); |
|---|
| 509 | 536 | if (aha1542_out(sh->io_port, mb_cmd, 5)) |
|---|
| 510 | 537 | shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n"); |
|---|
| 511 | 538 | aha1542_intr_reset(sh->io_port); |
|---|
| .. | .. |
|---|
| 739 | 766 | if (aha1542->bios_translation == BIOS_TRANSLATION_25563) |
|---|
| 740 | 767 | shost_printk(KERN_INFO, sh, "Using extended bios translation\n"); |
|---|
| 741 | 768 | |
|---|
| 769 | + if (dma_set_mask_and_coherent(pdev, DMA_BIT_MASK(24)) < 0) |
|---|
| 770 | + goto unregister; |
|---|
| 771 | + |
|---|
| 772 | + aha1542->mb = dma_alloc_coherent(pdev, |
|---|
| 773 | + AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), |
|---|
| 774 | + &aha1542->mb_handle, GFP_KERNEL); |
|---|
| 775 | + if (!aha1542->mb) |
|---|
| 776 | + goto unregister; |
|---|
| 777 | + |
|---|
| 778 | + aha1542->ccb = dma_alloc_coherent(pdev, |
|---|
| 779 | + AHA1542_MAILBOXES * sizeof(struct ccb), |
|---|
| 780 | + &aha1542->ccb_handle, GFP_KERNEL); |
|---|
| 781 | + if (!aha1542->ccb) |
|---|
| 782 | + goto free_mb; |
|---|
| 783 | + |
|---|
| 742 | 784 | setup_mailboxes(sh); |
|---|
| 743 | 785 | |
|---|
| 744 | 786 | if (request_irq(sh->irq, aha1542_interrupt, 0, "aha1542", sh)) { |
|---|
| 745 | 787 | shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n"); |
|---|
| 746 | | - goto unregister; |
|---|
| 788 | + goto free_ccb; |
|---|
| 747 | 789 | } |
|---|
| 748 | 790 | if (sh->dma_channel != 0xFF) { |
|---|
| 749 | 791 | if (request_dma(sh->dma_channel, "aha1542")) { |
|---|
| .. | .. |
|---|
| 762 | 804 | scsi_scan_host(sh); |
|---|
| 763 | 805 | |
|---|
| 764 | 806 | return sh; |
|---|
| 807 | + |
|---|
| 765 | 808 | free_dma: |
|---|
| 766 | 809 | if (sh->dma_channel != 0xff) |
|---|
| 767 | 810 | free_dma(sh->dma_channel); |
|---|
| 768 | 811 | free_irq: |
|---|
| 769 | 812 | free_irq(sh->irq, sh); |
|---|
| 813 | +free_ccb: |
|---|
| 814 | + dma_free_coherent(pdev, AHA1542_MAILBOXES * sizeof(struct ccb), |
|---|
| 815 | + aha1542->ccb, aha1542->ccb_handle); |
|---|
| 816 | +free_mb: |
|---|
| 817 | + dma_free_coherent(pdev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), |
|---|
| 818 | + aha1542->mb, aha1542->mb_handle); |
|---|
| 770 | 819 | unregister: |
|---|
| 771 | 820 | scsi_host_put(sh); |
|---|
| 772 | 821 | release: |
|---|
| .. | .. |
|---|
| 777 | 826 | |
|---|
| 778 | 827 | static int aha1542_release(struct Scsi_Host *sh) |
|---|
| 779 | 828 | { |
|---|
| 829 | + struct aha1542_hostdata *aha1542 = shost_priv(sh); |
|---|
| 830 | + struct device *dev = sh->dma_dev; |
|---|
| 831 | + |
|---|
| 780 | 832 | scsi_remove_host(sh); |
|---|
| 781 | 833 | if (sh->dma_channel != 0xff) |
|---|
| 782 | 834 | free_dma(sh->dma_channel); |
|---|
| 835 | + dma_free_coherent(dev, AHA1542_MAILBOXES * sizeof(struct ccb), |
|---|
| 836 | + aha1542->ccb, aha1542->ccb_handle); |
|---|
| 837 | + dma_free_coherent(dev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), |
|---|
| 838 | + aha1542->mb, aha1542->mb_handle); |
|---|
| 783 | 839 | if (sh->irq) |
|---|
| 784 | 840 | free_irq(sh->irq, sh); |
|---|
| 785 | 841 | if (sh->io_port && sh->n_io_port) |
|---|
| .. | .. |
|---|
| 826 | 882 | |
|---|
| 827 | 883 | aha1542->aha1542_last_mbo_used = mbo; |
|---|
| 828 | 884 | |
|---|
| 829 | | - any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */ |
|---|
| 885 | + /* This gets trashed for some reason */ |
|---|
| 886 | + any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb)); |
|---|
| 830 | 887 | |
|---|
| 831 | 888 | memset(&ccb[mbo], 0, sizeof(struct ccb)); |
|---|
| 832 | 889 | |
|---|
| .. | .. |
|---|
| 901 | 958 | */ |
|---|
| 902 | 959 | continue; |
|---|
| 903 | 960 | } |
|---|
| 904 | | - kfree(tmp_cmd->host_scribble); |
|---|
| 905 | | - tmp_cmd->host_scribble = NULL; |
|---|
| 961 | + aha1542_free_cmd(tmp_cmd); |
|---|
| 906 | 962 | aha1542->int_cmds[i] = NULL; |
|---|
| 907 | 963 | aha1542->mb[i].status = 0; |
|---|
| 908 | 964 | } |
|---|
| .. | .. |
|---|
| 946 | 1002 | .module = THIS_MODULE, |
|---|
| 947 | 1003 | .proc_name = "aha1542", |
|---|
| 948 | 1004 | .name = "Adaptec 1542", |
|---|
| 1005 | + .cmd_size = sizeof(struct aha1542_cmd), |
|---|
| 949 | 1006 | .queuecommand = aha1542_queuecommand, |
|---|
| 950 | 1007 | .eh_device_reset_handler= aha1542_dev_reset, |
|---|
| 951 | 1008 | .eh_bus_reset_handler = aha1542_bus_reset, |
|---|
| .. | .. |
|---|
| 955 | 1012 | .this_id = 7, |
|---|
| 956 | 1013 | .sg_tablesize = 16, |
|---|
| 957 | 1014 | .unchecked_isa_dma = 1, |
|---|
| 958 | | - .use_clustering = ENABLE_CLUSTERING, |
|---|
| 959 | 1015 | }; |
|---|
| 960 | 1016 | |
|---|
| 961 | 1017 | static int aha1542_isa_match(struct device *pdev, unsigned int ndev) |
|---|