162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Generic Macintosh NCR5380 driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright 2019 Finn Thain 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * derived in part from: 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci/* 1262306a36Sopenharmony_ci * Generic Generic NCR5380 driver 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Copyright 1995, Russell King 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/delay.h> 1862306a36Sopenharmony_ci#include <linux/types.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/ioport.h> 2162306a36Sopenharmony_ci#include <linux/init.h> 2262306a36Sopenharmony_ci#include <linux/blkdev.h> 2362306a36Sopenharmony_ci#include <linux/interrupt.h> 2462306a36Sopenharmony_ci#include <linux/platform_device.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <asm/hwtest.h> 2762306a36Sopenharmony_ci#include <asm/io.h> 2862306a36Sopenharmony_ci#include <asm/macintosh.h> 2962306a36Sopenharmony_ci#include <asm/macints.h> 3062306a36Sopenharmony_ci#include <asm/setup.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <scsi/scsi_host.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Definitions for the core NCR5380 driver. */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define NCR5380_implementation_fields int pdma_residual 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define NCR5380_read(reg) in_8(hostdata->io + ((reg) << 4)) 3962306a36Sopenharmony_ci#define NCR5380_write(reg, value) out_8(hostdata->io + ((reg) << 4), value) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define NCR5380_dma_xfer_len macscsi_dma_xfer_len 4262306a36Sopenharmony_ci#define NCR5380_dma_recv_setup macscsi_pread 4362306a36Sopenharmony_ci#define NCR5380_dma_send_setup macscsi_pwrite 4462306a36Sopenharmony_ci#define NCR5380_dma_residual macscsi_dma_residual 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define NCR5380_intr macscsi_intr 4762306a36Sopenharmony_ci#define NCR5380_queue_command macscsi_queue_command 4862306a36Sopenharmony_ci#define NCR5380_abort macscsi_abort 4962306a36Sopenharmony_ci#define NCR5380_host_reset macscsi_host_reset 5062306a36Sopenharmony_ci#define NCR5380_info macscsi_info 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#include "NCR5380.h" 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic int setup_can_queue = -1; 5562306a36Sopenharmony_cimodule_param(setup_can_queue, int, 0); 5662306a36Sopenharmony_cistatic int setup_cmd_per_lun = -1; 5762306a36Sopenharmony_cimodule_param(setup_cmd_per_lun, int, 0); 5862306a36Sopenharmony_cistatic int setup_sg_tablesize = -1; 5962306a36Sopenharmony_cimodule_param(setup_sg_tablesize, int, 0); 6062306a36Sopenharmony_cistatic int setup_use_pdma = 512; 6162306a36Sopenharmony_cimodule_param(setup_use_pdma, int, 0); 6262306a36Sopenharmony_cistatic int setup_hostid = -1; 6362306a36Sopenharmony_cimodule_param(setup_hostid, int, 0); 6462306a36Sopenharmony_cistatic int setup_toshiba_delay = -1; 6562306a36Sopenharmony_cimodule_param(setup_toshiba_delay, int, 0); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#ifndef MODULE 6862306a36Sopenharmony_cistatic int __init mac_scsi_setup(char *str) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci int ints[8]; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci (void)get_options(str, ARRAY_SIZE(ints), ints); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (ints[0] < 1) { 7562306a36Sopenharmony_ci pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>[,<toshiba_delay>]]]]]]\n"); 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci if (ints[0] >= 1) 7962306a36Sopenharmony_ci setup_can_queue = ints[1]; 8062306a36Sopenharmony_ci if (ints[0] >= 2) 8162306a36Sopenharmony_ci setup_cmd_per_lun = ints[2]; 8262306a36Sopenharmony_ci if (ints[0] >= 3) 8362306a36Sopenharmony_ci setup_sg_tablesize = ints[3]; 8462306a36Sopenharmony_ci if (ints[0] >= 4) 8562306a36Sopenharmony_ci setup_hostid = ints[4]; 8662306a36Sopenharmony_ci /* ints[5] (use_tagged_queuing) is ignored */ 8762306a36Sopenharmony_ci if (ints[0] >= 6) 8862306a36Sopenharmony_ci setup_use_pdma = ints[6]; 8962306a36Sopenharmony_ci if (ints[0] >= 7) 9062306a36Sopenharmony_ci setup_toshiba_delay = ints[7]; 9162306a36Sopenharmony_ci return 1; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci__setup("mac5380=", mac_scsi_setup); 9562306a36Sopenharmony_ci#endif /* !MODULE */ 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* 9862306a36Sopenharmony_ci * According to "Inside Macintosh: Devices", Mac OS requires disk drivers to 9962306a36Sopenharmony_ci * specify the number of bytes between the delays expected from a SCSI target. 10062306a36Sopenharmony_ci * This allows the operating system to "prevent bus errors when a target fails 10162306a36Sopenharmony_ci * to deliver the next byte within the processor bus error timeout period." 10262306a36Sopenharmony_ci * Linux SCSI drivers lack knowledge of the timing behaviour of SCSI targets 10362306a36Sopenharmony_ci * so bus errors are unavoidable. 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * If a MOVE.B instruction faults, we assume that zero bytes were transferred 10662306a36Sopenharmony_ci * and simply retry. That assumption probably depends on target behaviour but 10762306a36Sopenharmony_ci * seems to hold up okay. The NOP provides synchronization: without it the 10862306a36Sopenharmony_ci * fault can sometimes occur after the program counter has moved past the 10962306a36Sopenharmony_ci * offending instruction. Post-increment addressing can't be used. 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci#define MOVE_BYTE(operands) \ 11362306a36Sopenharmony_ci asm volatile ( \ 11462306a36Sopenharmony_ci "1: moveb " operands " \n" \ 11562306a36Sopenharmony_ci "11: nop \n" \ 11662306a36Sopenharmony_ci " addq #1,%0 \n" \ 11762306a36Sopenharmony_ci " subq #1,%1 \n" \ 11862306a36Sopenharmony_ci "40: \n" \ 11962306a36Sopenharmony_ci " \n" \ 12062306a36Sopenharmony_ci ".section .fixup,\"ax\" \n" \ 12162306a36Sopenharmony_ci ".even \n" \ 12262306a36Sopenharmony_ci "90: movel #1, %2 \n" \ 12362306a36Sopenharmony_ci " jra 40b \n" \ 12462306a36Sopenharmony_ci ".previous \n" \ 12562306a36Sopenharmony_ci " \n" \ 12662306a36Sopenharmony_ci ".section __ex_table,\"a\" \n" \ 12762306a36Sopenharmony_ci ".align 4 \n" \ 12862306a36Sopenharmony_ci ".long 1b,90b \n" \ 12962306a36Sopenharmony_ci ".long 11b,90b \n" \ 13062306a36Sopenharmony_ci ".previous \n" \ 13162306a36Sopenharmony_ci : "+a" (addr), "+r" (n), "+r" (result) : "a" (io)) 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* 13462306a36Sopenharmony_ci * If a MOVE.W (or MOVE.L) instruction faults, it cannot be retried because 13562306a36Sopenharmony_ci * the residual byte count would be uncertain. In that situation the MOVE_WORD 13662306a36Sopenharmony_ci * macro clears n in the fixup section to abort the transfer. 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#define MOVE_WORD(operands) \ 14062306a36Sopenharmony_ci asm volatile ( \ 14162306a36Sopenharmony_ci "1: movew " operands " \n" \ 14262306a36Sopenharmony_ci "11: nop \n" \ 14362306a36Sopenharmony_ci " subq #2,%1 \n" \ 14462306a36Sopenharmony_ci "40: \n" \ 14562306a36Sopenharmony_ci " \n" \ 14662306a36Sopenharmony_ci ".section .fixup,\"ax\" \n" \ 14762306a36Sopenharmony_ci ".even \n" \ 14862306a36Sopenharmony_ci "90: movel #0, %1 \n" \ 14962306a36Sopenharmony_ci " movel #2, %2 \n" \ 15062306a36Sopenharmony_ci " jra 40b \n" \ 15162306a36Sopenharmony_ci ".previous \n" \ 15262306a36Sopenharmony_ci " \n" \ 15362306a36Sopenharmony_ci ".section __ex_table,\"a\" \n" \ 15462306a36Sopenharmony_ci ".align 4 \n" \ 15562306a36Sopenharmony_ci ".long 1b,90b \n" \ 15662306a36Sopenharmony_ci ".long 11b,90b \n" \ 15762306a36Sopenharmony_ci ".previous \n" \ 15862306a36Sopenharmony_ci : "+a" (addr), "+r" (n), "+r" (result) : "a" (io)) 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci#define MOVE_16_WORDS(operands) \ 16162306a36Sopenharmony_ci asm volatile ( \ 16262306a36Sopenharmony_ci "1: movew " operands " \n" \ 16362306a36Sopenharmony_ci "2: movew " operands " \n" \ 16462306a36Sopenharmony_ci "3: movew " operands " \n" \ 16562306a36Sopenharmony_ci "4: movew " operands " \n" \ 16662306a36Sopenharmony_ci "5: movew " operands " \n" \ 16762306a36Sopenharmony_ci "6: movew " operands " \n" \ 16862306a36Sopenharmony_ci "7: movew " operands " \n" \ 16962306a36Sopenharmony_ci "8: movew " operands " \n" \ 17062306a36Sopenharmony_ci "9: movew " operands " \n" \ 17162306a36Sopenharmony_ci "10: movew " operands " \n" \ 17262306a36Sopenharmony_ci "11: movew " operands " \n" \ 17362306a36Sopenharmony_ci "12: movew " operands " \n" \ 17462306a36Sopenharmony_ci "13: movew " operands " \n" \ 17562306a36Sopenharmony_ci "14: movew " operands " \n" \ 17662306a36Sopenharmony_ci "15: movew " operands " \n" \ 17762306a36Sopenharmony_ci "16: movew " operands " \n" \ 17862306a36Sopenharmony_ci "17: nop \n" \ 17962306a36Sopenharmony_ci " subl #32,%1 \n" \ 18062306a36Sopenharmony_ci "40: \n" \ 18162306a36Sopenharmony_ci " \n" \ 18262306a36Sopenharmony_ci ".section .fixup,\"ax\" \n" \ 18362306a36Sopenharmony_ci ".even \n" \ 18462306a36Sopenharmony_ci "90: movel #0, %1 \n" \ 18562306a36Sopenharmony_ci " movel #2, %2 \n" \ 18662306a36Sopenharmony_ci " jra 40b \n" \ 18762306a36Sopenharmony_ci ".previous \n" \ 18862306a36Sopenharmony_ci " \n" \ 18962306a36Sopenharmony_ci ".section __ex_table,\"a\" \n" \ 19062306a36Sopenharmony_ci ".align 4 \n" \ 19162306a36Sopenharmony_ci ".long 1b,90b \n" \ 19262306a36Sopenharmony_ci ".long 2b,90b \n" \ 19362306a36Sopenharmony_ci ".long 3b,90b \n" \ 19462306a36Sopenharmony_ci ".long 4b,90b \n" \ 19562306a36Sopenharmony_ci ".long 5b,90b \n" \ 19662306a36Sopenharmony_ci ".long 6b,90b \n" \ 19762306a36Sopenharmony_ci ".long 7b,90b \n" \ 19862306a36Sopenharmony_ci ".long 8b,90b \n" \ 19962306a36Sopenharmony_ci ".long 9b,90b \n" \ 20062306a36Sopenharmony_ci ".long 10b,90b \n" \ 20162306a36Sopenharmony_ci ".long 11b,90b \n" \ 20262306a36Sopenharmony_ci ".long 12b,90b \n" \ 20362306a36Sopenharmony_ci ".long 13b,90b \n" \ 20462306a36Sopenharmony_ci ".long 14b,90b \n" \ 20562306a36Sopenharmony_ci ".long 15b,90b \n" \ 20662306a36Sopenharmony_ci ".long 16b,90b \n" \ 20762306a36Sopenharmony_ci ".long 17b,90b \n" \ 20862306a36Sopenharmony_ci ".previous \n" \ 20962306a36Sopenharmony_ci : "+a" (addr), "+r" (n), "+r" (result) : "a" (io)) 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci#define MAC_PDMA_DELAY 32 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic inline int mac_pdma_recv(void __iomem *io, unsigned char *start, int n) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci unsigned char *addr = start; 21662306a36Sopenharmony_ci int result = 0; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (n >= 1) { 21962306a36Sopenharmony_ci MOVE_BYTE("%3@,%0@"); 22062306a36Sopenharmony_ci if (result) 22162306a36Sopenharmony_ci goto out; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci if (n >= 1 && ((unsigned long)addr & 1)) { 22462306a36Sopenharmony_ci MOVE_BYTE("%3@,%0@"); 22562306a36Sopenharmony_ci if (result) 22662306a36Sopenharmony_ci goto out; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci while (n >= 32) 22962306a36Sopenharmony_ci MOVE_16_WORDS("%3@,%0@+"); 23062306a36Sopenharmony_ci while (n >= 2) 23162306a36Sopenharmony_ci MOVE_WORD("%3@,%0@+"); 23262306a36Sopenharmony_ci if (result) 23362306a36Sopenharmony_ci return start - addr; /* Negated to indicate uncertain length */ 23462306a36Sopenharmony_ci if (n == 1) 23562306a36Sopenharmony_ci MOVE_BYTE("%3@,%0@"); 23662306a36Sopenharmony_ciout: 23762306a36Sopenharmony_ci return addr - start; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic inline int mac_pdma_send(unsigned char *start, void __iomem *io, int n) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci unsigned char *addr = start; 24362306a36Sopenharmony_ci int result = 0; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (n >= 1) { 24662306a36Sopenharmony_ci MOVE_BYTE("%0@,%3@"); 24762306a36Sopenharmony_ci if (result) 24862306a36Sopenharmony_ci goto out; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci if (n >= 1 && ((unsigned long)addr & 1)) { 25162306a36Sopenharmony_ci MOVE_BYTE("%0@,%3@"); 25262306a36Sopenharmony_ci if (result) 25362306a36Sopenharmony_ci goto out; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci while (n >= 32) 25662306a36Sopenharmony_ci MOVE_16_WORDS("%0@+,%3@"); 25762306a36Sopenharmony_ci while (n >= 2) 25862306a36Sopenharmony_ci MOVE_WORD("%0@+,%3@"); 25962306a36Sopenharmony_ci if (result) 26062306a36Sopenharmony_ci return start - addr; /* Negated to indicate uncertain length */ 26162306a36Sopenharmony_ci if (n == 1) 26262306a36Sopenharmony_ci MOVE_BYTE("%0@,%3@"); 26362306a36Sopenharmony_ciout: 26462306a36Sopenharmony_ci return addr - start; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/* The "SCSI DMA" chip on the IIfx implements this register. */ 26862306a36Sopenharmony_ci#define CTRL_REG 0x8 26962306a36Sopenharmony_ci#define CTRL_INTERRUPTS_ENABLE BIT(1) 27062306a36Sopenharmony_ci#define CTRL_HANDSHAKE_MODE BIT(3) 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic inline void write_ctrl_reg(struct NCR5380_hostdata *hostdata, u32 value) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci out_be32(hostdata->io + (CTRL_REG << 4), value); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic inline int macscsi_pread(struct NCR5380_hostdata *hostdata, 27862306a36Sopenharmony_ci unsigned char *dst, int len) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4); 28162306a36Sopenharmony_ci unsigned char *d = dst; 28262306a36Sopenharmony_ci int result = 0; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci hostdata->pdma_residual = len; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, 28762306a36Sopenharmony_ci BASR_DRQ | BASR_PHASE_MATCH, 28862306a36Sopenharmony_ci BASR_DRQ | BASR_PHASE_MATCH, 0)) { 28962306a36Sopenharmony_ci int bytes; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (macintosh_config->ident == MAC_MODEL_IIFX) 29262306a36Sopenharmony_ci write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE | 29362306a36Sopenharmony_ci CTRL_INTERRUPTS_ENABLE); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci bytes = mac_pdma_recv(s, d, min(hostdata->pdma_residual, 512)); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (bytes > 0) { 29862306a36Sopenharmony_ci d += bytes; 29962306a36Sopenharmony_ci hostdata->pdma_residual -= bytes; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (hostdata->pdma_residual == 0) 30362306a36Sopenharmony_ci goto out; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, 30662306a36Sopenharmony_ci BUS_AND_STATUS_REG, BASR_ACK, 30762306a36Sopenharmony_ci BASR_ACK, 0) < 0) 30862306a36Sopenharmony_ci scmd_printk(KERN_DEBUG, hostdata->connected, 30962306a36Sopenharmony_ci "%s: !REQ and !ACK\n", __func__); 31062306a36Sopenharmony_ci if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) 31162306a36Sopenharmony_ci goto out; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (bytes == 0) 31462306a36Sopenharmony_ci udelay(MAC_PDMA_DELAY); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (bytes >= 0) 31762306a36Sopenharmony_ci continue; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host, 32062306a36Sopenharmony_ci "%s: bus error (%d/%d)\n", __func__, d - dst, len); 32162306a36Sopenharmony_ci NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); 32262306a36Sopenharmony_ci result = -1; 32362306a36Sopenharmony_ci goto out; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci scmd_printk(KERN_ERR, hostdata->connected, 32762306a36Sopenharmony_ci "%s: phase mismatch or !DRQ\n", __func__); 32862306a36Sopenharmony_ci NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); 32962306a36Sopenharmony_ci result = -1; 33062306a36Sopenharmony_ciout: 33162306a36Sopenharmony_ci if (macintosh_config->ident == MAC_MODEL_IIFX) 33262306a36Sopenharmony_ci write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE); 33362306a36Sopenharmony_ci return result; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, 33762306a36Sopenharmony_ci unsigned char *src, int len) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci unsigned char *s = src; 34062306a36Sopenharmony_ci u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4); 34162306a36Sopenharmony_ci int result = 0; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci hostdata->pdma_residual = len; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, 34662306a36Sopenharmony_ci BASR_DRQ | BASR_PHASE_MATCH, 34762306a36Sopenharmony_ci BASR_DRQ | BASR_PHASE_MATCH, 0)) { 34862306a36Sopenharmony_ci int bytes; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (macintosh_config->ident == MAC_MODEL_IIFX) 35162306a36Sopenharmony_ci write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE | 35262306a36Sopenharmony_ci CTRL_INTERRUPTS_ENABLE); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512)); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (bytes > 0) { 35762306a36Sopenharmony_ci s += bytes; 35862306a36Sopenharmony_ci hostdata->pdma_residual -= bytes; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (hostdata->pdma_residual == 0) { 36262306a36Sopenharmony_ci if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG, 36362306a36Sopenharmony_ci TCR_LAST_BYTE_SENT, 36462306a36Sopenharmony_ci TCR_LAST_BYTE_SENT, 36562306a36Sopenharmony_ci 0) < 0) { 36662306a36Sopenharmony_ci scmd_printk(KERN_ERR, hostdata->connected, 36762306a36Sopenharmony_ci "%s: Last Byte Sent timeout\n", __func__); 36862306a36Sopenharmony_ci result = -1; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci goto out; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, 37462306a36Sopenharmony_ci BUS_AND_STATUS_REG, BASR_ACK, 37562306a36Sopenharmony_ci BASR_ACK, 0) < 0) 37662306a36Sopenharmony_ci scmd_printk(KERN_DEBUG, hostdata->connected, 37762306a36Sopenharmony_ci "%s: !REQ and !ACK\n", __func__); 37862306a36Sopenharmony_ci if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) 37962306a36Sopenharmony_ci goto out; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (bytes == 0) 38262306a36Sopenharmony_ci udelay(MAC_PDMA_DELAY); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (bytes >= 0) 38562306a36Sopenharmony_ci continue; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host, 38862306a36Sopenharmony_ci "%s: bus error (%d/%d)\n", __func__, s - src, len); 38962306a36Sopenharmony_ci NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); 39062306a36Sopenharmony_ci result = -1; 39162306a36Sopenharmony_ci goto out; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci scmd_printk(KERN_ERR, hostdata->connected, 39562306a36Sopenharmony_ci "%s: phase mismatch or !DRQ\n", __func__); 39662306a36Sopenharmony_ci NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); 39762306a36Sopenharmony_ci result = -1; 39862306a36Sopenharmony_ciout: 39962306a36Sopenharmony_ci if (macintosh_config->ident == MAC_MODEL_IIFX) 40062306a36Sopenharmony_ci write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE); 40162306a36Sopenharmony_ci return result; 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata, 40562306a36Sopenharmony_ci struct scsi_cmnd *cmd) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci int resid = NCR5380_to_ncmd(cmd)->this_residual; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (hostdata->flags & FLAG_NO_PSEUDO_DMA || resid < setup_use_pdma) 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return resid; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int macscsi_dma_residual(struct NCR5380_hostdata *hostdata) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci return hostdata->pdma_residual; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci#include "NCR5380.c" 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci#define DRV_MODULE_NAME "mac_scsi" 42362306a36Sopenharmony_ci#define PFX DRV_MODULE_NAME ": " 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic struct scsi_host_template mac_scsi_template = { 42662306a36Sopenharmony_ci .module = THIS_MODULE, 42762306a36Sopenharmony_ci .proc_name = DRV_MODULE_NAME, 42862306a36Sopenharmony_ci .name = "Macintosh NCR5380 SCSI", 42962306a36Sopenharmony_ci .info = macscsi_info, 43062306a36Sopenharmony_ci .queuecommand = macscsi_queue_command, 43162306a36Sopenharmony_ci .eh_abort_handler = macscsi_abort, 43262306a36Sopenharmony_ci .eh_host_reset_handler = macscsi_host_reset, 43362306a36Sopenharmony_ci .can_queue = 16, 43462306a36Sopenharmony_ci .this_id = 7, 43562306a36Sopenharmony_ci .sg_tablesize = 1, 43662306a36Sopenharmony_ci .cmd_per_lun = 2, 43762306a36Sopenharmony_ci .dma_boundary = PAGE_SIZE - 1, 43862306a36Sopenharmony_ci .cmd_size = sizeof(struct NCR5380_cmd), 43962306a36Sopenharmony_ci .max_sectors = 128, 44062306a36Sopenharmony_ci}; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic int __init mac_scsi_probe(struct platform_device *pdev) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct Scsi_Host *instance; 44562306a36Sopenharmony_ci struct NCR5380_hostdata *hostdata; 44662306a36Sopenharmony_ci int error; 44762306a36Sopenharmony_ci int host_flags = 0; 44862306a36Sopenharmony_ci struct resource *irq, *pio_mem, *pdma_mem = NULL; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci pio_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 45162306a36Sopenharmony_ci if (!pio_mem) 45262306a36Sopenharmony_ci return -ENODEV; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci pdma_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (!hwreg_present((unsigned char *)pio_mem->start + 45962306a36Sopenharmony_ci (STATUS_REG << 4))) { 46062306a36Sopenharmony_ci pr_info(PFX "no device detected at %pap\n", &pio_mem->start); 46162306a36Sopenharmony_ci return -ENODEV; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (setup_can_queue > 0) 46562306a36Sopenharmony_ci mac_scsi_template.can_queue = setup_can_queue; 46662306a36Sopenharmony_ci if (setup_cmd_per_lun > 0) 46762306a36Sopenharmony_ci mac_scsi_template.cmd_per_lun = setup_cmd_per_lun; 46862306a36Sopenharmony_ci if (setup_sg_tablesize > 0) 46962306a36Sopenharmony_ci mac_scsi_template.sg_tablesize = setup_sg_tablesize; 47062306a36Sopenharmony_ci if (setup_hostid >= 0) 47162306a36Sopenharmony_ci mac_scsi_template.this_id = setup_hostid & 7; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci instance = scsi_host_alloc(&mac_scsi_template, 47462306a36Sopenharmony_ci sizeof(struct NCR5380_hostdata)); 47562306a36Sopenharmony_ci if (!instance) 47662306a36Sopenharmony_ci return -ENOMEM; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (irq) 47962306a36Sopenharmony_ci instance->irq = irq->start; 48062306a36Sopenharmony_ci else 48162306a36Sopenharmony_ci instance->irq = NO_IRQ; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci hostdata = shost_priv(instance); 48462306a36Sopenharmony_ci hostdata->base = pio_mem->start; 48562306a36Sopenharmony_ci hostdata->io = (u8 __iomem *)pio_mem->start; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (pdma_mem && setup_use_pdma) 48862306a36Sopenharmony_ci hostdata->pdma_io = (u8 __iomem *)pdma_mem->start; 48962306a36Sopenharmony_ci else 49062306a36Sopenharmony_ci host_flags |= FLAG_NO_PSEUDO_DMA; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci error = NCR5380_init(instance, host_flags | FLAG_LATE_DMA_SETUP); 49562306a36Sopenharmony_ci if (error) 49662306a36Sopenharmony_ci goto fail_init; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (instance->irq != NO_IRQ) { 49962306a36Sopenharmony_ci error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED, 50062306a36Sopenharmony_ci "NCR5380", instance); 50162306a36Sopenharmony_ci if (error) 50262306a36Sopenharmony_ci goto fail_irq; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci NCR5380_maybe_reset_bus(instance); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci error = scsi_add_host(instance, NULL); 50862306a36Sopenharmony_ci if (error) 50962306a36Sopenharmony_ci goto fail_host; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci platform_set_drvdata(pdev, instance); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci scsi_scan_host(instance); 51462306a36Sopenharmony_ci return 0; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cifail_host: 51762306a36Sopenharmony_ci if (instance->irq != NO_IRQ) 51862306a36Sopenharmony_ci free_irq(instance->irq, instance); 51962306a36Sopenharmony_cifail_irq: 52062306a36Sopenharmony_ci NCR5380_exit(instance); 52162306a36Sopenharmony_cifail_init: 52262306a36Sopenharmony_ci scsi_host_put(instance); 52362306a36Sopenharmony_ci return error; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic int __exit mac_scsi_remove(struct platform_device *pdev) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci struct Scsi_Host *instance = platform_get_drvdata(pdev); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci scsi_remove_host(instance); 53162306a36Sopenharmony_ci if (instance->irq != NO_IRQ) 53262306a36Sopenharmony_ci free_irq(instance->irq, instance); 53362306a36Sopenharmony_ci NCR5380_exit(instance); 53462306a36Sopenharmony_ci scsi_host_put(instance); 53562306a36Sopenharmony_ci return 0; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic struct platform_driver mac_scsi_driver = { 53962306a36Sopenharmony_ci .remove = __exit_p(mac_scsi_remove), 54062306a36Sopenharmony_ci .driver = { 54162306a36Sopenharmony_ci .name = DRV_MODULE_NAME, 54262306a36Sopenharmony_ci }, 54362306a36Sopenharmony_ci}; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cimodule_platform_driver_probe(mac_scsi_driver, mac_scsi_probe); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ciMODULE_ALIAS("platform:" DRV_MODULE_NAME); 54862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 549