316 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2#include <linux/types.h>3#include <linux/mm.h>4#include <linux/ioport.h>5#include <linux/init.h>6#include <linux/slab.h>7#include <linux/spinlock.h>8#include <linux/interrupt.h>9#include <linux/platform_device.h>10#include <linux/dma-mapping.h>11#include <linux/module.h>12 13#include <asm/page.h>14#include <asm/amigaints.h>15#include <asm/amigahw.h>16 17#include <scsi/scsi.h>18#include <scsi/scsi_cmnd.h>19#include <scsi/scsi_device.h>20#include <scsi/scsi_eh.h>21#include <scsi/scsi_tcq.h>22#include "wd33c93.h"23#include "a3000.h"24 25 26struct a3000_hostdata {27 struct WD33C93_hostdata wh;28 struct a3000_scsiregs *regs;29 struct device *dev;30};31 32#define DMA_DIR(d) ((d == DATA_OUT_DIR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE)33 34static irqreturn_t a3000_intr(int irq, void *data)35{36 struct Scsi_Host *instance = data;37 struct a3000_hostdata *hdata = shost_priv(instance);38 unsigned int status = hdata->regs->ISTR;39 unsigned long flags;40 41 if (!(status & ISTR_INT_P))42 return IRQ_NONE;43 if (status & ISTR_INTS) {44 spin_lock_irqsave(instance->host_lock, flags);45 wd33c93_intr(instance);46 spin_unlock_irqrestore(instance->host_lock, flags);47 return IRQ_HANDLED;48 }49 pr_warn("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status);50 return IRQ_NONE;51}52 53static int dma_setup(struct scsi_cmnd *cmd, int dir_in)54{55 struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(cmd);56 unsigned long len = scsi_pointer->this_residual;57 struct Scsi_Host *instance = cmd->device->host;58 struct a3000_hostdata *hdata = shost_priv(instance);59 struct WD33C93_hostdata *wh = &hdata->wh;60 struct a3000_scsiregs *regs = hdata->regs;61 unsigned short cntr = CNTR_PDMD | CNTR_INTEN;62 dma_addr_t addr;63 64 addr = dma_map_single(hdata->dev, scsi_pointer->ptr,65 len, DMA_DIR(dir_in));66 if (dma_mapping_error(hdata->dev, addr)) {67 dev_warn(hdata->dev, "cannot map SCSI data block %p\n",68 scsi_pointer->ptr);69 return 1;70 }71 scsi_pointer->dma_handle = addr;72 73 /*74 * if the physical address has the wrong alignment, or if75 * physical address is bad, or if it is a write and at the76 * end of a physical memory chunk, then allocate a bounce77 * buffer78 * MSch 20220629 - only wrong alignment tested - bounce79 * buffer returned by kmalloc is guaranteed to be aligned80 */81 if (addr & A3000_XFER_MASK) {82 WARN_ONCE(1, "Invalid alignment for DMA!");83 /* drop useless mapping */84 dma_unmap_single(hdata->dev, scsi_pointer->dma_handle,85 scsi_pointer->this_residual,86 DMA_DIR(dir_in));87 88 wh->dma_bounce_len = (scsi_pointer->this_residual + 511) & ~0x1ff;89 wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len,90 GFP_KERNEL);91 92 /* can't allocate memory; use PIO */93 if (!wh->dma_bounce_buffer) {94 wh->dma_bounce_len = 0;95 scsi_pointer->dma_handle = (dma_addr_t) NULL;96 return 1;97 }98 99 if (!dir_in) {100 /* copy to bounce buffer for a write */101 memcpy(wh->dma_bounce_buffer, scsi_pointer->ptr,102 scsi_pointer->this_residual);103 }104 105 addr = dma_map_single(hdata->dev, scsi_pointer->ptr,106 len, DMA_DIR(dir_in));107 if (dma_mapping_error(hdata->dev, addr)) {108 dev_warn(hdata->dev,109 "cannot map SCSI data block %p\n",110 scsi_pointer->ptr);111 return 1;112 }113 scsi_pointer->dma_handle = addr;114 }115 116 /* setup dma direction */117 if (!dir_in)118 cntr |= CNTR_DDIR;119 120 /* remember direction */121 wh->dma_dir = dir_in;122 123 regs->CNTR = cntr;124 125 /* setup DMA *physical* address */126 regs->ACR = addr;127 128 /* no more cache flush here - dma_map_single() takes care */129 130 /* start DMA */131 mb(); /* make sure setup is completed */132 regs->ST_DMA = 1;133 mb(); /* make sure DMA has started before next IO */134 135 /* return success */136 return 0;137}138 139static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,140 int status)141{142 struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(SCpnt);143 struct a3000_hostdata *hdata = shost_priv(instance);144 struct WD33C93_hostdata *wh = &hdata->wh;145 struct a3000_scsiregs *regs = hdata->regs;146 147 /* disable SCSI interrupts */148 unsigned short cntr = CNTR_PDMD;149 150 if (!wh->dma_dir)151 cntr |= CNTR_DDIR;152 153 regs->CNTR = cntr;154 mb(); /* make sure CNTR is updated before next IO */155 156 /* flush if we were reading */157 if (wh->dma_dir) {158 regs->FLUSH = 1;159 mb(); /* don't allow prefetch */160 while (!(regs->ISTR & ISTR_FE_FLG))161 barrier();162 mb(); /* no IO until FLUSH is done */163 }164 165 /* clear a possible interrupt */166 /* I think that this CINT is only necessary if you are167 * using the terminal count features. HM 7 Mar 1994168 */169 regs->CINT = 1;170 171 /* stop DMA */172 regs->SP_DMA = 1;173 mb(); /* make sure DMA is stopped before next IO */174 175 /* restore the CONTROL bits (minus the direction flag) */176 regs->CNTR = CNTR_PDMD | CNTR_INTEN;177 mb(); /* make sure CNTR is updated before next IO */178 179 dma_unmap_single(hdata->dev, scsi_pointer->dma_handle,180 scsi_pointer->this_residual,181 DMA_DIR(wh->dma_dir));182 183 /* copy from a bounce buffer, if necessary */184 if (status && wh->dma_bounce_buffer) {185 if (SCpnt) {186 if (wh->dma_dir && SCpnt)187 memcpy(scsi_pointer->ptr, wh->dma_bounce_buffer,188 scsi_pointer->this_residual);189 kfree(wh->dma_bounce_buffer);190 wh->dma_bounce_buffer = NULL;191 wh->dma_bounce_len = 0;192 } else {193 kfree(wh->dma_bounce_buffer);194 wh->dma_bounce_buffer = NULL;195 wh->dma_bounce_len = 0;196 }197 }198}199 200static const struct scsi_host_template amiga_a3000_scsi_template = {201 .module = THIS_MODULE,202 .name = "Amiga 3000 built-in SCSI",203 .show_info = wd33c93_show_info,204 .write_info = wd33c93_write_info,205 .proc_name = "A3000",206 .queuecommand = wd33c93_queuecommand,207 .eh_abort_handler = wd33c93_abort,208 .eh_host_reset_handler = wd33c93_host_reset,209 .can_queue = CAN_QUEUE,210 .this_id = 7,211 .sg_tablesize = SG_ALL,212 .cmd_per_lun = CMD_PER_LUN,213 .cmd_size = sizeof(struct scsi_pointer),214};215 216static int __init amiga_a3000_scsi_probe(struct platform_device *pdev)217{218 struct resource *res;219 struct Scsi_Host *instance;220 int error;221 struct a3000_scsiregs *regs;222 wd33c93_regs wdregs;223 struct a3000_hostdata *hdata;224 225 if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) {226 dev_warn(&pdev->dev, "cannot use 32 bit DMA\n");227 return -ENODEV;228 }229 230 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);231 if (!res)232 return -ENODEV;233 234 if (!request_mem_region(res->start, resource_size(res), "wd33c93"))235 return -EBUSY;236 237 instance = scsi_host_alloc(&amiga_a3000_scsi_template,238 sizeof(struct a3000_hostdata));239 if (!instance) {240 error = -ENOMEM;241 goto fail_alloc;242 }243 244 instance->irq = IRQ_AMIGA_PORTS;245 246 regs = ZTWO_VADDR(res->start);247 regs->DAWR = DAWR_A3000;248 249 wdregs.SASR = ®s->SASR;250 wdregs.SCMD = ®s->SCMD;251 252 hdata = shost_priv(instance);253 hdata->dev = &pdev->dev;254 hdata->wh.no_sync = 0xff;255 hdata->wh.fast = 0;256 hdata->wh.dma_mode = CTRL_DMA;257 hdata->regs = regs;258 259 wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15);260 error = request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED,261 "A3000 SCSI", instance);262 if (error)263 goto fail_irq;264 265 regs->CNTR = CNTR_PDMD | CNTR_INTEN;266 267 error = scsi_add_host(instance, NULL);268 if (error)269 goto fail_host;270 271 platform_set_drvdata(pdev, instance);272 273 scsi_scan_host(instance);274 return 0;275 276fail_host:277 free_irq(IRQ_AMIGA_PORTS, instance);278fail_irq:279 scsi_host_put(instance);280fail_alloc:281 release_mem_region(res->start, resource_size(res));282 return error;283}284 285static void __exit amiga_a3000_scsi_remove(struct platform_device *pdev)286{287 struct Scsi_Host *instance = platform_get_drvdata(pdev);288 struct a3000_hostdata *hdata = shost_priv(instance);289 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);290 291 hdata->regs->CNTR = 0;292 scsi_remove_host(instance);293 free_irq(IRQ_AMIGA_PORTS, instance);294 scsi_host_put(instance);295 release_mem_region(res->start, resource_size(res));296}297 298/*299 * amiga_a3000_scsi_remove() lives in .exit.text. For drivers registered via300 * module_platform_driver_probe() this is ok because they cannot get unbound at301 * runtime. So mark the driver struct with __refdata to prevent modpost302 * triggering a section mismatch warning.303 */304static struct platform_driver amiga_a3000_scsi_driver __refdata = {305 .remove_new = __exit_p(amiga_a3000_scsi_remove),306 .driver = {307 .name = "amiga-a3000-scsi",308 },309};310 311module_platform_driver_probe(amiga_a3000_scsi_driver, amiga_a3000_scsi_probe);312 313MODULE_DESCRIPTION("Amiga 3000 built-in SCSI");314MODULE_LICENSE("GPL");315MODULE_ALIAS("platform:amiga-a3000-scsi");316