.. | .. |
---|
| 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) |
---|