Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 #include <linux/types.h>
0003 #include <linux/mm.h>
0004 #include <linux/ioport.h>
0005 #include <linux/init.h>
0006 #include <linux/slab.h>
0007 #include <linux/spinlock.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/dma-mapping.h>
0011 #include <linux/module.h>
0012 
0013 #include <asm/page.h>
0014 #include <asm/amigaints.h>
0015 #include <asm/amigahw.h>
0016 
0017 #include <scsi/scsi.h>
0018 #include <scsi/scsi_cmnd.h>
0019 #include <scsi/scsi_device.h>
0020 #include <scsi/scsi_eh.h>
0021 #include <scsi/scsi_tcq.h>
0022 #include "wd33c93.h"
0023 #include "a3000.h"
0024 
0025 
0026 struct a3000_hostdata {
0027     struct WD33C93_hostdata wh;
0028     struct a3000_scsiregs *regs;
0029     struct device *dev;
0030 };
0031 
0032 #define DMA_DIR(d)   ((d == DATA_OUT_DIR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE)
0033 
0034 static irqreturn_t a3000_intr(int irq, void *data)
0035 {
0036     struct Scsi_Host *instance = data;
0037     struct a3000_hostdata *hdata = shost_priv(instance);
0038     unsigned int status = hdata->regs->ISTR;
0039     unsigned long flags;
0040 
0041     if (!(status & ISTR_INT_P))
0042         return IRQ_NONE;
0043     if (status & ISTR_INTS) {
0044         spin_lock_irqsave(instance->host_lock, flags);
0045         wd33c93_intr(instance);
0046         spin_unlock_irqrestore(instance->host_lock, flags);
0047         return IRQ_HANDLED;
0048     }
0049     pr_warn("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status);
0050     return IRQ_NONE;
0051 }
0052 
0053 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
0054 {
0055     struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(cmd);
0056     unsigned long len = scsi_pointer->this_residual;
0057     struct Scsi_Host *instance = cmd->device->host;
0058     struct a3000_hostdata *hdata = shost_priv(instance);
0059     struct WD33C93_hostdata *wh = &hdata->wh;
0060     struct a3000_scsiregs *regs = hdata->regs;
0061     unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
0062     dma_addr_t addr;
0063 
0064     addr = dma_map_single(hdata->dev, scsi_pointer->ptr,
0065                   len, DMA_DIR(dir_in));
0066     if (dma_mapping_error(hdata->dev, addr)) {
0067         dev_warn(hdata->dev, "cannot map SCSI data block %p\n",
0068              scsi_pointer->ptr);
0069         return 1;
0070     }
0071     scsi_pointer->dma_handle = addr;
0072 
0073     /*
0074      * if the physical address has the wrong alignment, or if
0075      * physical address is bad, or if it is a write and at the
0076      * end of a physical memory chunk, then allocate a bounce
0077      * buffer
0078      * MSch 20220629 - only wrong alignment tested - bounce
0079      * buffer returned by kmalloc is guaranteed to be aligned
0080      */
0081     if (addr & A3000_XFER_MASK) {
0082         WARN_ONCE(1, "Invalid alignment for DMA!");
0083         /* drop useless mapping */
0084         dma_unmap_single(hdata->dev, scsi_pointer->dma_handle,
0085                  scsi_pointer->this_residual,
0086                  DMA_DIR(dir_in));
0087 
0088         wh->dma_bounce_len = (scsi_pointer->this_residual + 511) & ~0x1ff;
0089         wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len,
0090                         GFP_KERNEL);
0091 
0092         /* can't allocate memory; use PIO */
0093         if (!wh->dma_bounce_buffer) {
0094             wh->dma_bounce_len = 0;
0095             scsi_pointer->dma_handle = (dma_addr_t) NULL;
0096             return 1;
0097         }
0098 
0099         if (!dir_in) {
0100             /* copy to bounce buffer for a write */
0101             memcpy(wh->dma_bounce_buffer, scsi_pointer->ptr,
0102                    scsi_pointer->this_residual);
0103         }
0104 
0105         addr = dma_map_single(hdata->dev, scsi_pointer->ptr,
0106                       len, DMA_DIR(dir_in));
0107         if (dma_mapping_error(hdata->dev, addr)) {
0108             dev_warn(hdata->dev,
0109                  "cannot map SCSI data block %p\n",
0110                  scsi_pointer->ptr);
0111             return 1;
0112         }
0113         scsi_pointer->dma_handle = addr;
0114     }
0115 
0116     /* setup dma direction */
0117     if (!dir_in)
0118         cntr |= CNTR_DDIR;
0119 
0120     /* remember direction */
0121     wh->dma_dir = dir_in;
0122 
0123     regs->CNTR = cntr;
0124 
0125     /* setup DMA *physical* address */
0126     regs->ACR = addr;
0127 
0128     /* no more cache flush here - dma_map_single() takes care */
0129 
0130     /* start DMA */
0131     mb();           /* make sure setup is completed */
0132     regs->ST_DMA = 1;
0133     mb();           /* make sure DMA has started before next IO */
0134 
0135     /* return success */
0136     return 0;
0137 }
0138 
0139 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
0140              int status)
0141 {
0142     struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(SCpnt);
0143     struct a3000_hostdata *hdata = shost_priv(instance);
0144     struct WD33C93_hostdata *wh = &hdata->wh;
0145     struct a3000_scsiregs *regs = hdata->regs;
0146 
0147     /* disable SCSI interrupts */
0148     unsigned short cntr = CNTR_PDMD;
0149 
0150     if (!wh->dma_dir)
0151         cntr |= CNTR_DDIR;
0152 
0153     regs->CNTR = cntr;
0154     mb();           /* make sure CNTR is updated before next IO */
0155 
0156     /* flush if we were reading */
0157     if (wh->dma_dir) {
0158         regs->FLUSH = 1;
0159         mb();       /* don't allow prefetch */
0160         while (!(regs->ISTR & ISTR_FE_FLG))
0161             barrier();
0162         mb();       /* no IO until FLUSH is done */
0163     }
0164 
0165     /* clear a possible interrupt */
0166     /* I think that this CINT is only necessary if you are
0167      * using the terminal count features.   HM 7 Mar 1994
0168      */
0169     regs->CINT = 1;
0170 
0171     /* stop DMA */
0172     regs->SP_DMA = 1;
0173     mb();           /* make sure DMA is stopped before next IO */
0174 
0175     /* restore the CONTROL bits (minus the direction flag) */
0176     regs->CNTR = CNTR_PDMD | CNTR_INTEN;
0177     mb();           /* make sure CNTR is updated before next IO */
0178 
0179     dma_unmap_single(hdata->dev, scsi_pointer->dma_handle,
0180              scsi_pointer->this_residual,
0181              DMA_DIR(wh->dma_dir));
0182 
0183     /* copy from a bounce buffer, if necessary */
0184     if (status && wh->dma_bounce_buffer) {
0185         if (SCpnt) {
0186             if (wh->dma_dir && SCpnt)
0187                 memcpy(scsi_pointer->ptr, wh->dma_bounce_buffer,
0188                        scsi_pointer->this_residual);
0189             kfree(wh->dma_bounce_buffer);
0190             wh->dma_bounce_buffer = NULL;
0191             wh->dma_bounce_len = 0;
0192         } else {
0193             kfree(wh->dma_bounce_buffer);
0194             wh->dma_bounce_buffer = NULL;
0195             wh->dma_bounce_len = 0;
0196         }
0197     }
0198 }
0199 
0200 static struct scsi_host_template amiga_a3000_scsi_template = {
0201     .module         = THIS_MODULE,
0202     .name           = "Amiga 3000 built-in SCSI",
0203     .show_info      = wd33c93_show_info,
0204     .write_info     = wd33c93_write_info,
0205     .proc_name      = "A3000",
0206     .queuecommand       = wd33c93_queuecommand,
0207     .eh_abort_handler   = wd33c93_abort,
0208     .eh_host_reset_handler  = wd33c93_host_reset,
0209     .can_queue      = CAN_QUEUE,
0210     .this_id        = 7,
0211     .sg_tablesize       = SG_ALL,
0212     .cmd_per_lun        = CMD_PER_LUN,
0213     .cmd_size       = sizeof(struct scsi_pointer),
0214 };
0215 
0216 static int __init amiga_a3000_scsi_probe(struct platform_device *pdev)
0217 {
0218     struct resource *res;
0219     struct Scsi_Host *instance;
0220     int error;
0221     struct a3000_scsiregs *regs;
0222     wd33c93_regs wdregs;
0223     struct a3000_hostdata *hdata;
0224 
0225     if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) {
0226         dev_warn(&pdev->dev, "cannot use 32 bit DMA\n");
0227         return -ENODEV;
0228     }
0229 
0230     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0231     if (!res)
0232         return -ENODEV;
0233 
0234     if (!request_mem_region(res->start, resource_size(res), "wd33c93"))
0235         return -EBUSY;
0236 
0237     instance = scsi_host_alloc(&amiga_a3000_scsi_template,
0238                    sizeof(struct a3000_hostdata));
0239     if (!instance) {
0240         error = -ENOMEM;
0241         goto fail_alloc;
0242     }
0243 
0244     instance->irq = IRQ_AMIGA_PORTS;
0245 
0246     regs = ZTWO_VADDR(res->start);
0247     regs->DAWR = DAWR_A3000;
0248 
0249     wdregs.SASR = &regs->SASR;
0250     wdregs.SCMD = &regs->SCMD;
0251 
0252     hdata = shost_priv(instance);
0253     hdata->dev = &pdev->dev;
0254     hdata->wh.no_sync = 0xff;
0255     hdata->wh.fast = 0;
0256     hdata->wh.dma_mode = CTRL_DMA;
0257     hdata->regs = regs;
0258 
0259     wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15);
0260     error = request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED,
0261                 "A3000 SCSI", instance);
0262     if (error)
0263         goto fail_irq;
0264 
0265     regs->CNTR = CNTR_PDMD | CNTR_INTEN;
0266 
0267     error = scsi_add_host(instance, NULL);
0268     if (error)
0269         goto fail_host;
0270 
0271     platform_set_drvdata(pdev, instance);
0272 
0273     scsi_scan_host(instance);
0274     return 0;
0275 
0276 fail_host:
0277     free_irq(IRQ_AMIGA_PORTS, instance);
0278 fail_irq:
0279     scsi_host_put(instance);
0280 fail_alloc:
0281     release_mem_region(res->start, resource_size(res));
0282     return error;
0283 }
0284 
0285 static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev)
0286 {
0287     struct Scsi_Host *instance = platform_get_drvdata(pdev);
0288     struct a3000_hostdata *hdata = shost_priv(instance);
0289     struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0290 
0291     hdata->regs->CNTR = 0;
0292     scsi_remove_host(instance);
0293     free_irq(IRQ_AMIGA_PORTS, instance);
0294     scsi_host_put(instance);
0295     release_mem_region(res->start, resource_size(res));
0296     return 0;
0297 }
0298 
0299 static struct platform_driver amiga_a3000_scsi_driver = {
0300     .remove = __exit_p(amiga_a3000_scsi_remove),
0301     .driver   = {
0302         .name   = "amiga-a3000-scsi",
0303     },
0304 };
0305 
0306 module_platform_driver_probe(amiga_a3000_scsi_driver, amiga_a3000_scsi_probe);
0307 
0308 MODULE_DESCRIPTION("Amiga 3000 built-in SCSI");
0309 MODULE_LICENSE("GPL");
0310 MODULE_ALIAS("platform:amiga-a3000-scsi");