162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#include <linux/types.h> 362306a36Sopenharmony_ci#include <linux/init.h> 462306a36Sopenharmony_ci#include <linux/interrupt.h> 562306a36Sopenharmony_ci#include <linux/mm.h> 662306a36Sopenharmony_ci#include <linux/slab.h> 762306a36Sopenharmony_ci#include <linux/spinlock.h> 862306a36Sopenharmony_ci#include <linux/zorro.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <asm/page.h> 1262306a36Sopenharmony_ci#include <asm/amigaints.h> 1362306a36Sopenharmony_ci#include <asm/amigahw.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <scsi/scsi.h> 1662306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 1762306a36Sopenharmony_ci#include <scsi/scsi_device.h> 1862306a36Sopenharmony_ci#include <scsi/scsi_eh.h> 1962306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 2062306a36Sopenharmony_ci#include "wd33c93.h" 2162306a36Sopenharmony_ci#include "gvp11.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define CHECK_WD33C93 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct gvp11_hostdata { 2762306a36Sopenharmony_ci struct WD33C93_hostdata wh; 2862306a36Sopenharmony_ci struct gvp11_scsiregs *regs; 2962306a36Sopenharmony_ci struct device *dev; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define DMA_DIR(d) ((d == DATA_OUT_DIR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE) 3362306a36Sopenharmony_ci#define TO_DMA_MASK(m) (~((unsigned long long)m & 0xffffffff)) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic irqreturn_t gvp11_intr(int irq, void *data) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct Scsi_Host *instance = data; 3862306a36Sopenharmony_ci struct gvp11_hostdata *hdata = shost_priv(instance); 3962306a36Sopenharmony_ci unsigned int status = hdata->regs->CNTR; 4062306a36Sopenharmony_ci unsigned long flags; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (!(status & GVP11_DMAC_INT_PENDING)) 4362306a36Sopenharmony_ci return IRQ_NONE; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci spin_lock_irqsave(instance->host_lock, flags); 4662306a36Sopenharmony_ci wd33c93_intr(instance); 4762306a36Sopenharmony_ci spin_unlock_irqrestore(instance->host_lock, flags); 4862306a36Sopenharmony_ci return IRQ_HANDLED; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic int gvp11_xfer_mask = 0; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int dma_setup(struct scsi_cmnd *cmd, int dir_in) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(cmd); 5662306a36Sopenharmony_ci unsigned long len = scsi_pointer->this_residual; 5762306a36Sopenharmony_ci struct Scsi_Host *instance = cmd->device->host; 5862306a36Sopenharmony_ci struct gvp11_hostdata *hdata = shost_priv(instance); 5962306a36Sopenharmony_ci struct WD33C93_hostdata *wh = &hdata->wh; 6062306a36Sopenharmony_ci struct gvp11_scsiregs *regs = hdata->regs; 6162306a36Sopenharmony_ci unsigned short cntr = GVP11_DMAC_INT_ENABLE; 6262306a36Sopenharmony_ci dma_addr_t addr; 6362306a36Sopenharmony_ci int bank_mask; 6462306a36Sopenharmony_ci static int scsi_alloc_out_of_range = 0; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci addr = dma_map_single(hdata->dev, scsi_pointer->ptr, 6762306a36Sopenharmony_ci len, DMA_DIR(dir_in)); 6862306a36Sopenharmony_ci if (dma_mapping_error(hdata->dev, addr)) { 6962306a36Sopenharmony_ci dev_warn(hdata->dev, "cannot map SCSI data block %p\n", 7062306a36Sopenharmony_ci scsi_pointer->ptr); 7162306a36Sopenharmony_ci return 1; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci scsi_pointer->dma_handle = addr; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* use bounce buffer if the physical address is bad */ 7662306a36Sopenharmony_ci if (addr & wh->dma_xfer_mask) { 7762306a36Sopenharmony_ci /* drop useless mapping */ 7862306a36Sopenharmony_ci dma_unmap_single(hdata->dev, scsi_pointer->dma_handle, 7962306a36Sopenharmony_ci scsi_pointer->this_residual, 8062306a36Sopenharmony_ci DMA_DIR(dir_in)); 8162306a36Sopenharmony_ci scsi_pointer->dma_handle = (dma_addr_t) NULL; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci wh->dma_bounce_len = (scsi_pointer->this_residual + 511) & ~0x1ff; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (!scsi_alloc_out_of_range) { 8662306a36Sopenharmony_ci wh->dma_bounce_buffer = 8762306a36Sopenharmony_ci kmalloc(wh->dma_bounce_len, GFP_KERNEL); 8862306a36Sopenharmony_ci wh->dma_buffer_pool = BUF_SCSI_ALLOCED; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (scsi_alloc_out_of_range || 9262306a36Sopenharmony_ci !wh->dma_bounce_buffer) { 9362306a36Sopenharmony_ci wh->dma_bounce_buffer = 9462306a36Sopenharmony_ci amiga_chip_alloc(wh->dma_bounce_len, 9562306a36Sopenharmony_ci "GVP II SCSI Bounce Buffer"); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (!wh->dma_bounce_buffer) { 9862306a36Sopenharmony_ci wh->dma_bounce_len = 0; 9962306a36Sopenharmony_ci return 1; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci wh->dma_buffer_pool = BUF_CHIP_ALLOCED; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (!dir_in) { 10662306a36Sopenharmony_ci /* copy to bounce buffer for a write */ 10762306a36Sopenharmony_ci memcpy(wh->dma_bounce_buffer, scsi_pointer->ptr, 10862306a36Sopenharmony_ci scsi_pointer->this_residual); 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED) { 11262306a36Sopenharmony_ci /* will flush/invalidate cache for us */ 11362306a36Sopenharmony_ci addr = dma_map_single(hdata->dev, 11462306a36Sopenharmony_ci wh->dma_bounce_buffer, 11562306a36Sopenharmony_ci wh->dma_bounce_len, 11662306a36Sopenharmony_ci DMA_DIR(dir_in)); 11762306a36Sopenharmony_ci /* can't map buffer; use PIO */ 11862306a36Sopenharmony_ci if (dma_mapping_error(hdata->dev, addr)) { 11962306a36Sopenharmony_ci dev_warn(hdata->dev, 12062306a36Sopenharmony_ci "cannot map bounce buffer %p\n", 12162306a36Sopenharmony_ci wh->dma_bounce_buffer); 12262306a36Sopenharmony_ci return 1; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (addr & wh->dma_xfer_mask) { 12762306a36Sopenharmony_ci /* drop useless mapping */ 12862306a36Sopenharmony_ci dma_unmap_single(hdata->dev, scsi_pointer->dma_handle, 12962306a36Sopenharmony_ci scsi_pointer->this_residual, 13062306a36Sopenharmony_ci DMA_DIR(dir_in)); 13162306a36Sopenharmony_ci /* fall back to Chip RAM if address out of range */ 13262306a36Sopenharmony_ci if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED) { 13362306a36Sopenharmony_ci kfree(wh->dma_bounce_buffer); 13462306a36Sopenharmony_ci scsi_alloc_out_of_range = 1; 13562306a36Sopenharmony_ci } else { 13662306a36Sopenharmony_ci amiga_chip_free(wh->dma_bounce_buffer); 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci wh->dma_bounce_buffer = 14062306a36Sopenharmony_ci amiga_chip_alloc(wh->dma_bounce_len, 14162306a36Sopenharmony_ci "GVP II SCSI Bounce Buffer"); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (!wh->dma_bounce_buffer) { 14462306a36Sopenharmony_ci wh->dma_bounce_len = 0; 14562306a36Sopenharmony_ci return 1; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (!dir_in) { 14962306a36Sopenharmony_ci /* copy to bounce buffer for a write */ 15062306a36Sopenharmony_ci memcpy(wh->dma_bounce_buffer, scsi_pointer->ptr, 15162306a36Sopenharmony_ci scsi_pointer->this_residual); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci /* chip RAM can be mapped to phys. address directly */ 15462306a36Sopenharmony_ci addr = virt_to_phys(wh->dma_bounce_buffer); 15562306a36Sopenharmony_ci /* no need to flush/invalidate cache */ 15662306a36Sopenharmony_ci wh->dma_buffer_pool = BUF_CHIP_ALLOCED; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci /* finally, have OK mapping (punted for PIO else) */ 15962306a36Sopenharmony_ci scsi_pointer->dma_handle = addr; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* setup dma direction */ 16462306a36Sopenharmony_ci if (!dir_in) 16562306a36Sopenharmony_ci cntr |= GVP11_DMAC_DIR_WRITE; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci wh->dma_dir = dir_in; 16862306a36Sopenharmony_ci regs->CNTR = cntr; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* setup DMA *physical* address */ 17162306a36Sopenharmony_ci regs->ACR = addr; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* no more cache flush here - dma_map_single() takes care */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci bank_mask = (~wh->dma_xfer_mask >> 18) & 0x01c0; 17662306a36Sopenharmony_ci if (bank_mask) 17762306a36Sopenharmony_ci regs->BANK = bank_mask & (addr >> 18); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* start DMA */ 18062306a36Sopenharmony_ci regs->ST_DMA = 1; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* return success */ 18362306a36Sopenharmony_ci return 0; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, 18762306a36Sopenharmony_ci int status) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(SCpnt); 19062306a36Sopenharmony_ci struct gvp11_hostdata *hdata = shost_priv(instance); 19162306a36Sopenharmony_ci struct WD33C93_hostdata *wh = &hdata->wh; 19262306a36Sopenharmony_ci struct gvp11_scsiregs *regs = hdata->regs; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* stop DMA */ 19562306a36Sopenharmony_ci regs->SP_DMA = 1; 19662306a36Sopenharmony_ci /* remove write bit from CONTROL bits */ 19762306a36Sopenharmony_ci regs->CNTR = GVP11_DMAC_INT_ENABLE; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED) 20062306a36Sopenharmony_ci dma_unmap_single(hdata->dev, scsi_pointer->dma_handle, 20162306a36Sopenharmony_ci scsi_pointer->this_residual, 20262306a36Sopenharmony_ci DMA_DIR(wh->dma_dir)); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* copy from a bounce buffer, if necessary */ 20562306a36Sopenharmony_ci if (status && wh->dma_bounce_buffer) { 20662306a36Sopenharmony_ci if (wh->dma_dir && SCpnt) 20762306a36Sopenharmony_ci memcpy(scsi_pointer->ptr, wh->dma_bounce_buffer, 20862306a36Sopenharmony_ci scsi_pointer->this_residual); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED) 21162306a36Sopenharmony_ci kfree(wh->dma_bounce_buffer); 21262306a36Sopenharmony_ci else 21362306a36Sopenharmony_ci amiga_chip_free(wh->dma_bounce_buffer); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci wh->dma_bounce_buffer = NULL; 21662306a36Sopenharmony_ci wh->dma_bounce_len = 0; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic const struct scsi_host_template gvp11_scsi_template = { 22162306a36Sopenharmony_ci .module = THIS_MODULE, 22262306a36Sopenharmony_ci .name = "GVP Series II SCSI", 22362306a36Sopenharmony_ci .show_info = wd33c93_show_info, 22462306a36Sopenharmony_ci .write_info = wd33c93_write_info, 22562306a36Sopenharmony_ci .proc_name = "GVP11", 22662306a36Sopenharmony_ci .queuecommand = wd33c93_queuecommand, 22762306a36Sopenharmony_ci .eh_abort_handler = wd33c93_abort, 22862306a36Sopenharmony_ci .eh_host_reset_handler = wd33c93_host_reset, 22962306a36Sopenharmony_ci .can_queue = CAN_QUEUE, 23062306a36Sopenharmony_ci .this_id = 7, 23162306a36Sopenharmony_ci .sg_tablesize = SG_ALL, 23262306a36Sopenharmony_ci .cmd_per_lun = CMD_PER_LUN, 23362306a36Sopenharmony_ci .dma_boundary = PAGE_SIZE - 1, 23462306a36Sopenharmony_ci .cmd_size = sizeof(struct scsi_pointer), 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int check_wd33c93(struct gvp11_scsiregs *regs) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci#ifdef CHECK_WD33C93 24062306a36Sopenharmony_ci volatile unsigned char *sasr_3393, *scmd_3393; 24162306a36Sopenharmony_ci unsigned char save_sasr; 24262306a36Sopenharmony_ci unsigned char q, qq; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* 24562306a36Sopenharmony_ci * These darn GVP boards are a problem - it can be tough to tell 24662306a36Sopenharmony_ci * whether or not they include a SCSI controller. This is the 24762306a36Sopenharmony_ci * ultimate Yet-Another-GVP-Detection-Hack in that it actually 24862306a36Sopenharmony_ci * probes for a WD33c93 chip: If we find one, it's extremely 24962306a36Sopenharmony_ci * likely that this card supports SCSI, regardless of Product_ 25062306a36Sopenharmony_ci * Code, Board_Size, etc. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* Get pointers to the presumed register locations and save contents */ 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci sasr_3393 = ®s->SASR; 25662306a36Sopenharmony_ci scmd_3393 = ®s->SCMD; 25762306a36Sopenharmony_ci save_sasr = *sasr_3393; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* First test the AuxStatus Reg */ 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci q = *sasr_3393; /* read it */ 26262306a36Sopenharmony_ci if (q & 0x08) /* bit 3 should always be clear */ 26362306a36Sopenharmony_ci return -ENODEV; 26462306a36Sopenharmony_ci *sasr_3393 = WD_AUXILIARY_STATUS; /* setup indirect address */ 26562306a36Sopenharmony_ci if (*sasr_3393 == WD_AUXILIARY_STATUS) { /* shouldn't retain the write */ 26662306a36Sopenharmony_ci *sasr_3393 = save_sasr; /* Oops - restore this byte */ 26762306a36Sopenharmony_ci return -ENODEV; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci if (*sasr_3393 != q) { /* should still read the same */ 27062306a36Sopenharmony_ci *sasr_3393 = save_sasr; /* Oops - restore this byte */ 27162306a36Sopenharmony_ci return -ENODEV; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci if (*scmd_3393 != q) /* and so should the image at 0x1f */ 27462306a36Sopenharmony_ci return -ENODEV; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* 27762306a36Sopenharmony_ci * Ok, we probably have a wd33c93, but let's check a few other places 27862306a36Sopenharmony_ci * for good measure. Make sure that this works for both 'A and 'B 27962306a36Sopenharmony_ci * chip versions. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci *sasr_3393 = WD_SCSI_STATUS; 28362306a36Sopenharmony_ci q = *scmd_3393; 28462306a36Sopenharmony_ci *sasr_3393 = WD_SCSI_STATUS; 28562306a36Sopenharmony_ci *scmd_3393 = ~q; 28662306a36Sopenharmony_ci *sasr_3393 = WD_SCSI_STATUS; 28762306a36Sopenharmony_ci qq = *scmd_3393; 28862306a36Sopenharmony_ci *sasr_3393 = WD_SCSI_STATUS; 28962306a36Sopenharmony_ci *scmd_3393 = q; 29062306a36Sopenharmony_ci if (qq != q) /* should be read only */ 29162306a36Sopenharmony_ci return -ENODEV; 29262306a36Sopenharmony_ci *sasr_3393 = 0x1e; /* this register is unimplemented */ 29362306a36Sopenharmony_ci q = *scmd_3393; 29462306a36Sopenharmony_ci *sasr_3393 = 0x1e; 29562306a36Sopenharmony_ci *scmd_3393 = ~q; 29662306a36Sopenharmony_ci *sasr_3393 = 0x1e; 29762306a36Sopenharmony_ci qq = *scmd_3393; 29862306a36Sopenharmony_ci *sasr_3393 = 0x1e; 29962306a36Sopenharmony_ci *scmd_3393 = q; 30062306a36Sopenharmony_ci if (qq != q || qq != 0xff) /* should be read only, all 1's */ 30162306a36Sopenharmony_ci return -ENODEV; 30262306a36Sopenharmony_ci *sasr_3393 = WD_TIMEOUT_PERIOD; 30362306a36Sopenharmony_ci q = *scmd_3393; 30462306a36Sopenharmony_ci *sasr_3393 = WD_TIMEOUT_PERIOD; 30562306a36Sopenharmony_ci *scmd_3393 = ~q; 30662306a36Sopenharmony_ci *sasr_3393 = WD_TIMEOUT_PERIOD; 30762306a36Sopenharmony_ci qq = *scmd_3393; 30862306a36Sopenharmony_ci *sasr_3393 = WD_TIMEOUT_PERIOD; 30962306a36Sopenharmony_ci *scmd_3393 = q; 31062306a36Sopenharmony_ci if (qq != (~q & 0xff)) /* should be read/write */ 31162306a36Sopenharmony_ci return -ENODEV; 31262306a36Sopenharmony_ci#endif /* CHECK_WD33C93 */ 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return 0; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic int gvp11_probe(struct zorro_dev *z, const struct zorro_device_id *ent) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct Scsi_Host *instance; 32062306a36Sopenharmony_ci unsigned long address; 32162306a36Sopenharmony_ci int error; 32262306a36Sopenharmony_ci unsigned int epc; 32362306a36Sopenharmony_ci unsigned int default_dma_xfer_mask; 32462306a36Sopenharmony_ci struct gvp11_hostdata *hdata; 32562306a36Sopenharmony_ci struct gvp11_scsiregs *regs; 32662306a36Sopenharmony_ci wd33c93_regs wdregs; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci default_dma_xfer_mask = ent->driver_data; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (dma_set_mask_and_coherent(&z->dev, 33162306a36Sopenharmony_ci TO_DMA_MASK(default_dma_xfer_mask))) { 33262306a36Sopenharmony_ci dev_warn(&z->dev, "cannot use DMA mask %llx\n", 33362306a36Sopenharmony_ci TO_DMA_MASK(default_dma_xfer_mask)); 33462306a36Sopenharmony_ci return -ENODEV; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* 33862306a36Sopenharmony_ci * Rumors state that some GVP ram boards use the same product 33962306a36Sopenharmony_ci * code as the SCSI controllers. Therefore if the board-size 34062306a36Sopenharmony_ci * is not 64KB we assume it is a ram board and bail out. 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_ci if (zorro_resource_len(z) != 0x10000) 34362306a36Sopenharmony_ci return -ENODEV; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci address = z->resource.start; 34662306a36Sopenharmony_ci if (!request_mem_region(address, 256, "wd33c93")) 34762306a36Sopenharmony_ci return -EBUSY; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci regs = ZTWO_VADDR(address); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci error = check_wd33c93(regs); 35262306a36Sopenharmony_ci if (error) 35362306a36Sopenharmony_ci goto fail_check_or_alloc; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci instance = scsi_host_alloc(&gvp11_scsi_template, 35662306a36Sopenharmony_ci sizeof(struct gvp11_hostdata)); 35762306a36Sopenharmony_ci if (!instance) { 35862306a36Sopenharmony_ci error = -ENOMEM; 35962306a36Sopenharmony_ci goto fail_check_or_alloc; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci instance->irq = IRQ_AMIGA_PORTS; 36362306a36Sopenharmony_ci instance->unique_id = z->slotaddr; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci regs->secret2 = 1; 36662306a36Sopenharmony_ci regs->secret1 = 0; 36762306a36Sopenharmony_ci regs->secret3 = 15; 36862306a36Sopenharmony_ci while (regs->CNTR & GVP11_DMAC_BUSY) 36962306a36Sopenharmony_ci ; 37062306a36Sopenharmony_ci regs->CNTR = 0; 37162306a36Sopenharmony_ci regs->BANK = 0; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci wdregs.SASR = ®s->SASR; 37462306a36Sopenharmony_ci wdregs.SCMD = ®s->SCMD; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci hdata = shost_priv(instance); 37762306a36Sopenharmony_ci if (gvp11_xfer_mask) { 37862306a36Sopenharmony_ci hdata->wh.dma_xfer_mask = gvp11_xfer_mask; 37962306a36Sopenharmony_ci if (dma_set_mask_and_coherent(&z->dev, 38062306a36Sopenharmony_ci TO_DMA_MASK(gvp11_xfer_mask))) { 38162306a36Sopenharmony_ci dev_warn(&z->dev, "cannot use DMA mask %llx\n", 38262306a36Sopenharmony_ci TO_DMA_MASK(gvp11_xfer_mask)); 38362306a36Sopenharmony_ci error = -ENODEV; 38462306a36Sopenharmony_ci goto fail_check_or_alloc; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci } else 38762306a36Sopenharmony_ci hdata->wh.dma_xfer_mask = default_dma_xfer_mask; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci hdata->wh.no_sync = 0xff; 39062306a36Sopenharmony_ci hdata->wh.fast = 0; 39162306a36Sopenharmony_ci hdata->wh.dma_mode = CTRL_DMA; 39262306a36Sopenharmony_ci hdata->regs = regs; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* 39562306a36Sopenharmony_ci * Check for 14MHz SCSI clock 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_ci epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000); 39862306a36Sopenharmony_ci wd33c93_init(instance, wdregs, dma_setup, dma_stop, 39962306a36Sopenharmony_ci (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10 40062306a36Sopenharmony_ci : WD33C93_FS_12_15); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci error = request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED, 40362306a36Sopenharmony_ci "GVP11 SCSI", instance); 40462306a36Sopenharmony_ci if (error) 40562306a36Sopenharmony_ci goto fail_irq; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci regs->CNTR = GVP11_DMAC_INT_ENABLE; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci error = scsi_add_host(instance, NULL); 41062306a36Sopenharmony_ci if (error) 41162306a36Sopenharmony_ci goto fail_host; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci zorro_set_drvdata(z, instance); 41462306a36Sopenharmony_ci scsi_scan_host(instance); 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cifail_host: 41862306a36Sopenharmony_ci free_irq(IRQ_AMIGA_PORTS, instance); 41962306a36Sopenharmony_cifail_irq: 42062306a36Sopenharmony_ci scsi_host_put(instance); 42162306a36Sopenharmony_cifail_check_or_alloc: 42262306a36Sopenharmony_ci release_mem_region(address, 256); 42362306a36Sopenharmony_ci return error; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic void gvp11_remove(struct zorro_dev *z) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct Scsi_Host *instance = zorro_get_drvdata(z); 42962306a36Sopenharmony_ci struct gvp11_hostdata *hdata = shost_priv(instance); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci hdata->regs->CNTR = 0; 43262306a36Sopenharmony_ci scsi_remove_host(instance); 43362306a36Sopenharmony_ci free_irq(IRQ_AMIGA_PORTS, instance); 43462306a36Sopenharmony_ci scsi_host_put(instance); 43562306a36Sopenharmony_ci release_mem_region(z->resource.start, 256); 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* 43962306a36Sopenharmony_ci * This should (hopefully) be the correct way to identify 44062306a36Sopenharmony_ci * all the different GVP SCSI controllers (except for the 44162306a36Sopenharmony_ci * SERIES I though). 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic struct zorro_device_id gvp11_zorro_tbl[] = { 44562306a36Sopenharmony_ci { ZORRO_PROD_GVP_COMBO_030_R3_SCSI, ~0x00ffffff }, 44662306a36Sopenharmony_ci { ZORRO_PROD_GVP_SERIES_II, ~0x00ffffff }, 44762306a36Sopenharmony_ci { ZORRO_PROD_GVP_GFORCE_030_SCSI, ~0x01ffffff }, 44862306a36Sopenharmony_ci { ZORRO_PROD_GVP_A530_SCSI, ~0x01ffffff }, 44962306a36Sopenharmony_ci { ZORRO_PROD_GVP_COMBO_030_R4_SCSI, ~0x01ffffff }, 45062306a36Sopenharmony_ci { ZORRO_PROD_GVP_A1291, ~0x07ffffff }, 45162306a36Sopenharmony_ci { ZORRO_PROD_GVP_GFORCE_040_SCSI_1, ~0x07ffffff }, 45262306a36Sopenharmony_ci { 0 } 45362306a36Sopenharmony_ci}; 45462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(zorro, gvp11_zorro_tbl); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic struct zorro_driver gvp11_driver = { 45762306a36Sopenharmony_ci .name = "gvp11", 45862306a36Sopenharmony_ci .id_table = gvp11_zorro_tbl, 45962306a36Sopenharmony_ci .probe = gvp11_probe, 46062306a36Sopenharmony_ci .remove = gvp11_remove, 46162306a36Sopenharmony_ci}; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic int __init gvp11_init(void) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci return zorro_register_driver(&gvp11_driver); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_cimodule_init(gvp11_init); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic void __exit gvp11_exit(void) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci zorro_unregister_driver(&gvp11_driver); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_cimodule_exit(gvp11_exit); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ciMODULE_DESCRIPTION("GVP Series II SCSI"); 47662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 477