mirror of
https://github.com/torvalds/linux.git
synced 2024-12-13 06:32:50 +00:00
ba6d10ab80
This is mostly update of the usual drivers: qla2xxx, hpsa, lpfc, ufs, mpt3sas, ibmvscsi, megaraid_sas, bnx2fc and hisi_sas as well as the removal of the osst driver (I heard from Willem privately that he would like the driver removed because all his test hardware has failed). Plus number of minor changes, spelling fixes and other trivia. Signed-off-by: James E.J. Bottomley <jejb@linux.ibm.com> -----BEGIN PGP SIGNATURE----- iJwEABMIAEQWIQTnYEDbdso9F2cI+arnQslM7pishQUCXSTl4yYcamFtZXMuYm90 dG9tbGV5QGhhbnNlbnBhcnRuZXJzaGlwLmNvbQAKCRDnQslM7pishdcxAQDCJVbd fPUX76/V1ldupunF97+3DTharxxbst+VnkOnCwD8D4c0KFFFOI9+F36cnMGCPegE fjy17dQLvsJ4GsidHy8= =aS5B -----END PGP SIGNATURE----- Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi Pull SCSI updates from James Bottomley: "This is mostly update of the usual drivers: qla2xxx, hpsa, lpfc, ufs, mpt3sas, ibmvscsi, megaraid_sas, bnx2fc and hisi_sas as well as the removal of the osst driver (I heard from Willem privately that he would like the driver removed because all his test hardware has failed). Plus number of minor changes, spelling fixes and other trivia. The big merge conflict this time around is the SPDX licence tags. Following discussion on linux-next, we believe our version to be more accurate than the one in the tree, so the resolution is to take our version for all the SPDX conflicts" Note on the SPDX license tag conversion conflicts: the SCSI tree had done its own SPDX conversion, which in some cases conflicted with the treewide ones done by Thomas & co. In almost all cases, the conflicts were purely syntactic: the SCSI tree used the old-style SPDX tags ("GPL-2.0" and "GPL-2.0+") while the treewide conversion had used the new-style ones ("GPL-2.0-only" and "GPL-2.0-or-later"). In these cases I picked the new-style one. In a few cases, the SPDX conversion was actually different, though. As explained by James above, and in more detail in a pre-pull-request thread: "The other problem is actually substantive: In the libsas code Luben Tuikov originally specified gpl 2.0 only by dint of stating: * This file is licensed under GPLv2. In all the libsas files, but then muddied the water by quoting GPLv2 verbatim (which includes the or later than language). So for these files Christoph did the conversion to v2 only SPDX tags and Thomas converted to v2 or later tags" So in those cases, where the spdx tag substantially mattered, I took the SCSI tree conversion of it, but then also took the opportunity to turn the old-style "GPL-2.0" into a new-style "GPL-2.0-only" tag. Similarly, when there were whitespace differences or other differences to the comments around the copyright notices, I took the version from the SCSI tree as being the more specific conversion. Finally, in the spdx conversions that had no conflicts (because the treewide ones hadn't been done for those files), I just took the SCSI tree version as-is, even if it was old-style. The old-style conversions are perfectly valid, even if the "-only" and "-or-later" versions are perhaps more descriptive. * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (185 commits) scsi: qla2xxx: move IO flush to the front of NVME rport unregistration scsi: qla2xxx: Fix NVME cmd and LS cmd timeout race condition scsi: qla2xxx: on session delete, return nvme cmd scsi: qla2xxx: Fix kernel crash after disconnecting NVMe devices scsi: megaraid_sas: Update driver version to 07.710.06.00-rc1 scsi: megaraid_sas: Introduce various Aero performance modes scsi: megaraid_sas: Use high IOPS queues based on IO workload scsi: megaraid_sas: Set affinity for high IOPS reply queues scsi: megaraid_sas: Enable coalescing for high IOPS queues scsi: megaraid_sas: Add support for High IOPS queues scsi: megaraid_sas: Add support for MPI toolbox commands scsi: megaraid_sas: Offload Aero RAID5/6 division calculations to driver scsi: megaraid_sas: RAID1 PCI bandwidth limit algorithm is applicable for only Ventura scsi: megaraid_sas: megaraid_sas: Add check for count returned by HOST_DEVICE_LIST DCMD scsi: megaraid_sas: Handle sequence JBOD map failure at driver level scsi: megaraid_sas: Don't send FPIO to RL Bypass queue scsi: megaraid_sas: In probe context, retry IOC INIT once if firmware is in fault scsi: megaraid_sas: Release Mutex lock before OCR in case of DCMD timeout scsi: megaraid_sas: Call disable_irq from process IRQ poll scsi: megaraid_sas: Remove few debug counters from IO path ...
548 lines
16 KiB
C
548 lines
16 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Generic Macintosh NCR5380 driver
|
|
*
|
|
* Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
|
|
*
|
|
* Copyright 2019 Finn Thain
|
|
*
|
|
* derived in part from:
|
|
*/
|
|
/*
|
|
* Generic Generic NCR5380 driver
|
|
*
|
|
* Copyright 1995, Russell King
|
|
*/
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/types.h>
|
|
#include <linux/module.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/init.h>
|
|
#include <linux/blkdev.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <asm/hwtest.h>
|
|
#include <asm/io.h>
|
|
#include <asm/macintosh.h>
|
|
#include <asm/macints.h>
|
|
#include <asm/setup.h>
|
|
|
|
#include <scsi/scsi_host.h>
|
|
|
|
/* Definitions for the core NCR5380 driver. */
|
|
|
|
#define NCR5380_implementation_fields int pdma_residual
|
|
|
|
#define NCR5380_read(reg) in_8(hostdata->io + ((reg) << 4))
|
|
#define NCR5380_write(reg, value) out_8(hostdata->io + ((reg) << 4), value)
|
|
|
|
#define NCR5380_dma_xfer_len macscsi_dma_xfer_len
|
|
#define NCR5380_dma_recv_setup macscsi_pread
|
|
#define NCR5380_dma_send_setup macscsi_pwrite
|
|
#define NCR5380_dma_residual macscsi_dma_residual
|
|
|
|
#define NCR5380_intr macscsi_intr
|
|
#define NCR5380_queue_command macscsi_queue_command
|
|
#define NCR5380_abort macscsi_abort
|
|
#define NCR5380_host_reset macscsi_host_reset
|
|
#define NCR5380_info macscsi_info
|
|
|
|
#include "NCR5380.h"
|
|
|
|
static int setup_can_queue = -1;
|
|
module_param(setup_can_queue, int, 0);
|
|
static int setup_cmd_per_lun = -1;
|
|
module_param(setup_cmd_per_lun, int, 0);
|
|
static int setup_sg_tablesize = -1;
|
|
module_param(setup_sg_tablesize, int, 0);
|
|
static int setup_use_pdma = 512;
|
|
module_param(setup_use_pdma, int, 0);
|
|
static int setup_hostid = -1;
|
|
module_param(setup_hostid, int, 0);
|
|
static int setup_toshiba_delay = -1;
|
|
module_param(setup_toshiba_delay, int, 0);
|
|
|
|
#ifndef MODULE
|
|
static int __init mac_scsi_setup(char *str)
|
|
{
|
|
int ints[8];
|
|
|
|
(void)get_options(str, ARRAY_SIZE(ints), ints);
|
|
|
|
if (ints[0] < 1) {
|
|
pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>[,<toshiba_delay>]]]]]]\n");
|
|
return 0;
|
|
}
|
|
if (ints[0] >= 1)
|
|
setup_can_queue = ints[1];
|
|
if (ints[0] >= 2)
|
|
setup_cmd_per_lun = ints[2];
|
|
if (ints[0] >= 3)
|
|
setup_sg_tablesize = ints[3];
|
|
if (ints[0] >= 4)
|
|
setup_hostid = ints[4];
|
|
/* ints[5] (use_tagged_queuing) is ignored */
|
|
if (ints[0] >= 6)
|
|
setup_use_pdma = ints[6];
|
|
if (ints[0] >= 7)
|
|
setup_toshiba_delay = ints[7];
|
|
return 1;
|
|
}
|
|
|
|
__setup("mac5380=", mac_scsi_setup);
|
|
#endif /* !MODULE */
|
|
|
|
/*
|
|
* According to "Inside Macintosh: Devices", Mac OS requires disk drivers to
|
|
* specify the number of bytes between the delays expected from a SCSI target.
|
|
* This allows the operating system to "prevent bus errors when a target fails
|
|
* to deliver the next byte within the processor bus error timeout period."
|
|
* Linux SCSI drivers lack knowledge of the timing behaviour of SCSI targets
|
|
* so bus errors are unavoidable.
|
|
*
|
|
* If a MOVE.B instruction faults, we assume that zero bytes were transferred
|
|
* and simply retry. That assumption probably depends on target behaviour but
|
|
* seems to hold up okay. The NOP provides synchronization: without it the
|
|
* fault can sometimes occur after the program counter has moved past the
|
|
* offending instruction. Post-increment addressing can't be used.
|
|
*/
|
|
|
|
#define MOVE_BYTE(operands) \
|
|
asm volatile ( \
|
|
"1: moveb " operands " \n" \
|
|
"11: nop \n" \
|
|
" addq #1,%0 \n" \
|
|
" subq #1,%1 \n" \
|
|
"40: \n" \
|
|
" \n" \
|
|
".section .fixup,\"ax\" \n" \
|
|
".even \n" \
|
|
"90: movel #1, %2 \n" \
|
|
" jra 40b \n" \
|
|
".previous \n" \
|
|
" \n" \
|
|
".section __ex_table,\"a\" \n" \
|
|
".align 4 \n" \
|
|
".long 1b,90b \n" \
|
|
".long 11b,90b \n" \
|
|
".previous \n" \
|
|
: "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
|
|
|
|
/*
|
|
* If a MOVE.W (or MOVE.L) instruction faults, it cannot be retried because
|
|
* the residual byte count would be uncertain. In that situation the MOVE_WORD
|
|
* macro clears n in the fixup section to abort the transfer.
|
|
*/
|
|
|
|
#define MOVE_WORD(operands) \
|
|
asm volatile ( \
|
|
"1: movew " operands " \n" \
|
|
"11: nop \n" \
|
|
" subq #2,%1 \n" \
|
|
"40: \n" \
|
|
" \n" \
|
|
".section .fixup,\"ax\" \n" \
|
|
".even \n" \
|
|
"90: movel #0, %1 \n" \
|
|
" movel #2, %2 \n" \
|
|
" jra 40b \n" \
|
|
".previous \n" \
|
|
" \n" \
|
|
".section __ex_table,\"a\" \n" \
|
|
".align 4 \n" \
|
|
".long 1b,90b \n" \
|
|
".long 11b,90b \n" \
|
|
".previous \n" \
|
|
: "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
|
|
|
|
#define MOVE_16_WORDS(operands) \
|
|
asm volatile ( \
|
|
"1: movew " operands " \n" \
|
|
"2: movew " operands " \n" \
|
|
"3: movew " operands " \n" \
|
|
"4: movew " operands " \n" \
|
|
"5: movew " operands " \n" \
|
|
"6: movew " operands " \n" \
|
|
"7: movew " operands " \n" \
|
|
"8: movew " operands " \n" \
|
|
"9: movew " operands " \n" \
|
|
"10: movew " operands " \n" \
|
|
"11: movew " operands " \n" \
|
|
"12: movew " operands " \n" \
|
|
"13: movew " operands " \n" \
|
|
"14: movew " operands " \n" \
|
|
"15: movew " operands " \n" \
|
|
"16: movew " operands " \n" \
|
|
"17: nop \n" \
|
|
" subl #32,%1 \n" \
|
|
"40: \n" \
|
|
" \n" \
|
|
".section .fixup,\"ax\" \n" \
|
|
".even \n" \
|
|
"90: movel #0, %1 \n" \
|
|
" movel #2, %2 \n" \
|
|
" jra 40b \n" \
|
|
".previous \n" \
|
|
" \n" \
|
|
".section __ex_table,\"a\" \n" \
|
|
".align 4 \n" \
|
|
".long 1b,90b \n" \
|
|
".long 2b,90b \n" \
|
|
".long 3b,90b \n" \
|
|
".long 4b,90b \n" \
|
|
".long 5b,90b \n" \
|
|
".long 6b,90b \n" \
|
|
".long 7b,90b \n" \
|
|
".long 8b,90b \n" \
|
|
".long 9b,90b \n" \
|
|
".long 10b,90b \n" \
|
|
".long 11b,90b \n" \
|
|
".long 12b,90b \n" \
|
|
".long 13b,90b \n" \
|
|
".long 14b,90b \n" \
|
|
".long 15b,90b \n" \
|
|
".long 16b,90b \n" \
|
|
".long 17b,90b \n" \
|
|
".previous \n" \
|
|
: "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
|
|
|
|
#define MAC_PDMA_DELAY 32
|
|
|
|
static inline int mac_pdma_recv(void __iomem *io, unsigned char *start, int n)
|
|
{
|
|
unsigned char *addr = start;
|
|
int result = 0;
|
|
|
|
if (n >= 1) {
|
|
MOVE_BYTE("%3@,%0@");
|
|
if (result)
|
|
goto out;
|
|
}
|
|
if (n >= 1 && ((unsigned long)addr & 1)) {
|
|
MOVE_BYTE("%3@,%0@");
|
|
if (result)
|
|
goto out;
|
|
}
|
|
while (n >= 32)
|
|
MOVE_16_WORDS("%3@,%0@+");
|
|
while (n >= 2)
|
|
MOVE_WORD("%3@,%0@+");
|
|
if (result)
|
|
return start - addr; /* Negated to indicate uncertain length */
|
|
if (n == 1)
|
|
MOVE_BYTE("%3@,%0@");
|
|
out:
|
|
return addr - start;
|
|
}
|
|
|
|
static inline int mac_pdma_send(unsigned char *start, void __iomem *io, int n)
|
|
{
|
|
unsigned char *addr = start;
|
|
int result = 0;
|
|
|
|
if (n >= 1) {
|
|
MOVE_BYTE("%0@,%3@");
|
|
if (result)
|
|
goto out;
|
|
}
|
|
if (n >= 1 && ((unsigned long)addr & 1)) {
|
|
MOVE_BYTE("%0@,%3@");
|
|
if (result)
|
|
goto out;
|
|
}
|
|
while (n >= 32)
|
|
MOVE_16_WORDS("%0@+,%3@");
|
|
while (n >= 2)
|
|
MOVE_WORD("%0@+,%3@");
|
|
if (result)
|
|
return start - addr; /* Negated to indicate uncertain length */
|
|
if (n == 1)
|
|
MOVE_BYTE("%0@,%3@");
|
|
out:
|
|
return addr - start;
|
|
}
|
|
|
|
/* The "SCSI DMA" chip on the IIfx implements this register. */
|
|
#define CTRL_REG 0x8
|
|
#define CTRL_INTERRUPTS_ENABLE BIT(1)
|
|
#define CTRL_HANDSHAKE_MODE BIT(3)
|
|
|
|
static inline void write_ctrl_reg(struct NCR5380_hostdata *hostdata, u32 value)
|
|
{
|
|
out_be32(hostdata->io + (CTRL_REG << 4), value);
|
|
}
|
|
|
|
static inline int macscsi_pread(struct NCR5380_hostdata *hostdata,
|
|
unsigned char *dst, int len)
|
|
{
|
|
u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4);
|
|
unsigned char *d = dst;
|
|
int result = 0;
|
|
|
|
hostdata->pdma_residual = len;
|
|
|
|
while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
|
|
BASR_DRQ | BASR_PHASE_MATCH,
|
|
BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
|
|
int bytes;
|
|
|
|
if (macintosh_config->ident == MAC_MODEL_IIFX)
|
|
write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
|
|
CTRL_INTERRUPTS_ENABLE);
|
|
|
|
bytes = mac_pdma_recv(s, d, min(hostdata->pdma_residual, 512));
|
|
|
|
if (bytes > 0) {
|
|
d += bytes;
|
|
hostdata->pdma_residual -= bytes;
|
|
}
|
|
|
|
if (hostdata->pdma_residual == 0)
|
|
goto out;
|
|
|
|
if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
|
|
BUS_AND_STATUS_REG, BASR_ACK,
|
|
BASR_ACK, HZ / 64) < 0)
|
|
scmd_printk(KERN_DEBUG, hostdata->connected,
|
|
"%s: !REQ and !ACK\n", __func__);
|
|
if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
|
|
goto out;
|
|
|
|
if (bytes == 0)
|
|
udelay(MAC_PDMA_DELAY);
|
|
|
|
if (bytes >= 0)
|
|
continue;
|
|
|
|
dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
|
|
"%s: bus error (%d/%d)\n", __func__, d - dst, len);
|
|
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
|
|
result = -1;
|
|
goto out;
|
|
}
|
|
|
|
scmd_printk(KERN_ERR, hostdata->connected,
|
|
"%s: phase mismatch or !DRQ\n", __func__);
|
|
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
|
|
result = -1;
|
|
out:
|
|
if (macintosh_config->ident == MAC_MODEL_IIFX)
|
|
write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
|
|
return result;
|
|
}
|
|
|
|
static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata,
|
|
unsigned char *src, int len)
|
|
{
|
|
unsigned char *s = src;
|
|
u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4);
|
|
int result = 0;
|
|
|
|
hostdata->pdma_residual = len;
|
|
|
|
while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
|
|
BASR_DRQ | BASR_PHASE_MATCH,
|
|
BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
|
|
int bytes;
|
|
|
|
if (macintosh_config->ident == MAC_MODEL_IIFX)
|
|
write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
|
|
CTRL_INTERRUPTS_ENABLE);
|
|
|
|
bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512));
|
|
|
|
if (bytes > 0) {
|
|
s += bytes;
|
|
hostdata->pdma_residual -= bytes;
|
|
}
|
|
|
|
if (hostdata->pdma_residual == 0) {
|
|
if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG,
|
|
TCR_LAST_BYTE_SENT,
|
|
TCR_LAST_BYTE_SENT,
|
|
HZ / 64) < 0) {
|
|
scmd_printk(KERN_ERR, hostdata->connected,
|
|
"%s: Last Byte Sent timeout\n", __func__);
|
|
result = -1;
|
|
}
|
|
goto out;
|
|
}
|
|
|
|
if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
|
|
BUS_AND_STATUS_REG, BASR_ACK,
|
|
BASR_ACK, HZ / 64) < 0)
|
|
scmd_printk(KERN_DEBUG, hostdata->connected,
|
|
"%s: !REQ and !ACK\n", __func__);
|
|
if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
|
|
goto out;
|
|
|
|
if (bytes == 0)
|
|
udelay(MAC_PDMA_DELAY);
|
|
|
|
if (bytes >= 0)
|
|
continue;
|
|
|
|
dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
|
|
"%s: bus error (%d/%d)\n", __func__, s - src, len);
|
|
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
|
|
result = -1;
|
|
goto out;
|
|
}
|
|
|
|
scmd_printk(KERN_ERR, hostdata->connected,
|
|
"%s: phase mismatch or !DRQ\n", __func__);
|
|
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
|
|
result = -1;
|
|
out:
|
|
if (macintosh_config->ident == MAC_MODEL_IIFX)
|
|
write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
|
|
return result;
|
|
}
|
|
|
|
static int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
|
|
struct scsi_cmnd *cmd)
|
|
{
|
|
if (hostdata->flags & FLAG_NO_PSEUDO_DMA ||
|
|
cmd->SCp.this_residual < setup_use_pdma)
|
|
return 0;
|
|
|
|
return cmd->SCp.this_residual;
|
|
}
|
|
|
|
static int macscsi_dma_residual(struct NCR5380_hostdata *hostdata)
|
|
{
|
|
return hostdata->pdma_residual;
|
|
}
|
|
|
|
#include "NCR5380.c"
|
|
|
|
#define DRV_MODULE_NAME "mac_scsi"
|
|
#define PFX DRV_MODULE_NAME ": "
|
|
|
|
static struct scsi_host_template mac_scsi_template = {
|
|
.module = THIS_MODULE,
|
|
.proc_name = DRV_MODULE_NAME,
|
|
.name = "Macintosh NCR5380 SCSI",
|
|
.info = macscsi_info,
|
|
.queuecommand = macscsi_queue_command,
|
|
.eh_abort_handler = macscsi_abort,
|
|
.eh_host_reset_handler = macscsi_host_reset,
|
|
.can_queue = 16,
|
|
.this_id = 7,
|
|
.sg_tablesize = 1,
|
|
.cmd_per_lun = 2,
|
|
.dma_boundary = PAGE_SIZE - 1,
|
|
.cmd_size = NCR5380_CMD_SIZE,
|
|
.max_sectors = 128,
|
|
};
|
|
|
|
static int __init mac_scsi_probe(struct platform_device *pdev)
|
|
{
|
|
struct Scsi_Host *instance;
|
|
struct NCR5380_hostdata *hostdata;
|
|
int error;
|
|
int host_flags = 0;
|
|
struct resource *irq, *pio_mem, *pdma_mem = NULL;
|
|
|
|
pio_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
if (!pio_mem)
|
|
return -ENODEV;
|
|
|
|
pdma_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
|
|
|
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
|
|
|
if (!hwreg_present((unsigned char *)pio_mem->start +
|
|
(STATUS_REG << 4))) {
|
|
pr_info(PFX "no device detected at %pap\n", &pio_mem->start);
|
|
return -ENODEV;
|
|
}
|
|
|
|
if (setup_can_queue > 0)
|
|
mac_scsi_template.can_queue = setup_can_queue;
|
|
if (setup_cmd_per_lun > 0)
|
|
mac_scsi_template.cmd_per_lun = setup_cmd_per_lun;
|
|
if (setup_sg_tablesize >= 0)
|
|
mac_scsi_template.sg_tablesize = setup_sg_tablesize;
|
|
if (setup_hostid >= 0)
|
|
mac_scsi_template.this_id = setup_hostid & 7;
|
|
|
|
instance = scsi_host_alloc(&mac_scsi_template,
|
|
sizeof(struct NCR5380_hostdata));
|
|
if (!instance)
|
|
return -ENOMEM;
|
|
|
|
if (irq)
|
|
instance->irq = irq->start;
|
|
else
|
|
instance->irq = NO_IRQ;
|
|
|
|
hostdata = shost_priv(instance);
|
|
hostdata->base = pio_mem->start;
|
|
hostdata->io = (u8 __iomem *)pio_mem->start;
|
|
|
|
if (pdma_mem && setup_use_pdma)
|
|
hostdata->pdma_io = (u8 __iomem *)pdma_mem->start;
|
|
else
|
|
host_flags |= FLAG_NO_PSEUDO_DMA;
|
|
|
|
host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
|
|
|
|
error = NCR5380_init(instance, host_flags | FLAG_LATE_DMA_SETUP);
|
|
if (error)
|
|
goto fail_init;
|
|
|
|
if (instance->irq != NO_IRQ) {
|
|
error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED,
|
|
"NCR5380", instance);
|
|
if (error)
|
|
goto fail_irq;
|
|
}
|
|
|
|
NCR5380_maybe_reset_bus(instance);
|
|
|
|
error = scsi_add_host(instance, NULL);
|
|
if (error)
|
|
goto fail_host;
|
|
|
|
platform_set_drvdata(pdev, instance);
|
|
|
|
scsi_scan_host(instance);
|
|
return 0;
|
|
|
|
fail_host:
|
|
if (instance->irq != NO_IRQ)
|
|
free_irq(instance->irq, instance);
|
|
fail_irq:
|
|
NCR5380_exit(instance);
|
|
fail_init:
|
|
scsi_host_put(instance);
|
|
return error;
|
|
}
|
|
|
|
static int __exit mac_scsi_remove(struct platform_device *pdev)
|
|
{
|
|
struct Scsi_Host *instance = platform_get_drvdata(pdev);
|
|
|
|
scsi_remove_host(instance);
|
|
if (instance->irq != NO_IRQ)
|
|
free_irq(instance->irq, instance);
|
|
NCR5380_exit(instance);
|
|
scsi_host_put(instance);
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver mac_scsi_driver = {
|
|
.remove = __exit_p(mac_scsi_remove),
|
|
.driver = {
|
|
.name = DRV_MODULE_NAME,
|
|
},
|
|
};
|
|
|
|
module_platform_driver_probe(mac_scsi_driver, mac_scsi_probe);
|
|
|
|
MODULE_ALIAS("platform:" DRV_MODULE_NAME);
|
|
MODULE_LICENSE("GPL");
|