mirror of https://gitee.com/openkylin/linux.git
atari_NCR5380: Merge from NCR5380.c
The NCR5380.c core driver has moved on since the atari_NCR5380.c fork. Some of those changes are also relevant to atari_NCR5380.c so apply them there as well. Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Reviewed-by: Hannes Reinecke <hare@suse.de> Tested-by: Michael Schmitz <schmitzmic@gmail.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
8dad0c51da
commit
ff50f9ed0f
|
@ -104,27 +104,7 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Design
|
* Design
|
||||||
* Issues :
|
|
||||||
*
|
*
|
||||||
* The other Linux SCSI drivers were written when Linux was Intel PC-only,
|
|
||||||
* and specifically for each board rather than each chip. This makes their
|
|
||||||
* adaptation to platforms like the Mac (Some of which use NCR5380's)
|
|
||||||
* more difficult than it has to be.
|
|
||||||
*
|
|
||||||
* Also, many of the SCSI drivers were written before the command queuing
|
|
||||||
* routines were implemented, meaning their implementations of queued
|
|
||||||
* commands were hacked on rather than designed in from the start.
|
|
||||||
*
|
|
||||||
* When I designed the Linux SCSI drivers I figured that
|
|
||||||
* while having two different SCSI boards in a system might be useful
|
|
||||||
* for debugging things, two of the same type wouldn't be used.
|
|
||||||
* Well, I was wrong and a number of users have mailed me about running
|
|
||||||
* multiple high-performance SCSI boards in a server.
|
|
||||||
*
|
|
||||||
* Finally, when I get questions from users, I have no idea what
|
|
||||||
* revision of my driver they are running.
|
|
||||||
*
|
|
||||||
* This driver attempts to address these problems :
|
|
||||||
* This is a generic 5380 driver. To use it on a different platform,
|
* This is a generic 5380 driver. To use it on a different platform,
|
||||||
* one simply writes appropriate system specific macros (ie, data
|
* one simply writes appropriate system specific macros (ie, data
|
||||||
* transfer - some PC's will use the I/O bus, 68K's must use
|
* transfer - some PC's will use the I/O bus, 68K's must use
|
||||||
|
@ -139,11 +119,6 @@
|
||||||
* allowing multiple commands to propagate all the way to a SCSI-II device
|
* allowing multiple commands to propagate all the way to a SCSI-II device
|
||||||
* while a command is already executing.
|
* while a command is already executing.
|
||||||
*
|
*
|
||||||
* To solve the multiple-boards-in-the-same-system problem,
|
|
||||||
* there is a separate instance structure for each instance
|
|
||||||
* of a 5380 in the system. So, multiple NCR5380 drivers will
|
|
||||||
* be able to coexist with appropriate changes to the high level
|
|
||||||
* SCSI code.
|
|
||||||
*
|
*
|
||||||
* Issues specific to the NCR5380 :
|
* Issues specific to the NCR5380 :
|
||||||
*
|
*
|
||||||
|
@ -168,19 +143,17 @@
|
||||||
* Architecture :
|
* Architecture :
|
||||||
*
|
*
|
||||||
* At the heart of the design is a coroutine, NCR5380_main,
|
* At the heart of the design is a coroutine, NCR5380_main,
|
||||||
* which is started when not running by the interrupt handler,
|
* which is started from a workqueue for each NCR5380 host in the
|
||||||
* timer, and queue command function. It attempts to establish
|
* system. It attempts to establish I_T_L or I_T_L_Q nexuses by
|
||||||
* I_T_L or I_T_L_Q nexuses by removing the commands from the
|
* removing the commands from the issue queue and calling
|
||||||
* issue queue and calling NCR5380_select() if a nexus
|
* NCR5380_select() if a nexus is not established.
|
||||||
* is not established.
|
|
||||||
*
|
*
|
||||||
* Once a nexus is established, the NCR5380_information_transfer()
|
* Once a nexus is established, the NCR5380_information_transfer()
|
||||||
* phase goes through the various phases as instructed by the target.
|
* phase goes through the various phases as instructed by the target.
|
||||||
* if the target goes into MSG IN and sends a DISCONNECT message,
|
* if the target goes into MSG IN and sends a DISCONNECT message,
|
||||||
* the command structure is placed into the per instance disconnected
|
* the command structure is placed into the per instance disconnected
|
||||||
* queue, and NCR5380_main tries to find more work. If USLEEP
|
* queue, and NCR5380_main tries to find more work. If the target is
|
||||||
* was defined, and the target is idle for too long, the system
|
* idle for too long, the system will try to sleep.
|
||||||
* will try to sleep.
|
|
||||||
*
|
*
|
||||||
* If a command has disconnected, eventually an interrupt will trigger,
|
* If a command has disconnected, eventually an interrupt will trigger,
|
||||||
* calling NCR5380_intr() which will in turn call NCR5380_reselect
|
* calling NCR5380_intr() which will in turn call NCR5380_reselect
|
||||||
|
@ -206,6 +179,9 @@
|
||||||
* AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
|
* AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
|
||||||
* for commands that return with a CHECK CONDITION status.
|
* for commands that return with a CHECK CONDITION status.
|
||||||
*
|
*
|
||||||
|
* DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
|
||||||
|
* transceivers.
|
||||||
|
*
|
||||||
* LINKED - if defined, linked commands are supported.
|
* LINKED - if defined, linked commands are supported.
|
||||||
*
|
*
|
||||||
* REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
|
* REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
|
||||||
|
@ -218,6 +194,9 @@
|
||||||
*
|
*
|
||||||
* NCR5380_write(register, value) - write to the specific register
|
* NCR5380_write(register, value) - write to the specific register
|
||||||
*
|
*
|
||||||
|
* NCR5380_implementation_fields - additional fields needed for this
|
||||||
|
* specific implementation of the NCR5380
|
||||||
|
*
|
||||||
* Either real DMA *or* pseudo DMA may be implemented
|
* Either real DMA *or* pseudo DMA may be implemented
|
||||||
* REAL functions :
|
* REAL functions :
|
||||||
* NCR5380_REAL_DMA should be defined if real DMA is to be used.
|
* NCR5380_REAL_DMA should be defined if real DMA is to be used.
|
||||||
|
@ -236,20 +215,6 @@
|
||||||
* NCR5380_pwrite(instance, src, count)
|
* NCR5380_pwrite(instance, src, count)
|
||||||
* NCR5380_pread(instance, dst, count);
|
* NCR5380_pread(instance, dst, count);
|
||||||
*
|
*
|
||||||
* If nothing specific to this implementation needs doing (ie, with external
|
|
||||||
* hardware), you must also define
|
|
||||||
*
|
|
||||||
* NCR5380_queue_command
|
|
||||||
* NCR5380_reset
|
|
||||||
* NCR5380_abort
|
|
||||||
*
|
|
||||||
* to be the global entry points into the specific driver, ie
|
|
||||||
* #define NCR5380_queue_command t128_queue_command.
|
|
||||||
*
|
|
||||||
* If this is not done, the routines will be defined as static functions
|
|
||||||
* with the NCR5380* names and the user must provide a globally
|
|
||||||
* accessible wrapper function.
|
|
||||||
*
|
|
||||||
* The generic driver is initialized by calling NCR5380_init(instance),
|
* The generic driver is initialized by calling NCR5380_init(instance),
|
||||||
* after setting the appropriate host specific fields and ID. If the
|
* after setting the appropriate host specific fields and ID. If the
|
||||||
* driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
|
* driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
|
||||||
|
@ -489,13 +454,11 @@ static void merge_contiguous_buffers(struct scsi_cmnd *cmd)
|
||||||
#endif /* !defined(CONFIG_SUN3) */
|
#endif /* !defined(CONFIG_SUN3) */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Function : void initialize_SCp(struct scsi_cmnd *cmd)
|
* initialize_SCp - init the scsi pointer field
|
||||||
|
* @cmd: command block to set up
|
||||||
*
|
*
|
||||||
* Purpose : initialize the saved data pointers for cmd to point to the
|
* Set up the internal fields in the SCSI command.
|
||||||
* start of the buffer.
|
|
||||||
*
|
|
||||||
* Inputs : cmd - scsi_cmnd structure to have pointers reset.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline void initialize_SCp(struct scsi_cmnd *cmd)
|
static inline void initialize_SCp(struct scsi_cmnd *cmd)
|
||||||
|
@ -548,12 +511,11 @@ static struct {
|
||||||
{0, NULL}
|
{0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Function : void NCR5380_print(struct Scsi_Host *instance)
|
* NCR5380_print - print scsi bus signals
|
||||||
|
* @instance: adapter state to dump
|
||||||
*
|
*
|
||||||
* Purpose : print the SCSI bus signals for debugging purposes
|
* Print the SCSI bus signals for debugging purposes
|
||||||
*
|
|
||||||
* Input : instance - which NCR5380
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void NCR5380_print(struct Scsi_Host *instance)
|
static void NCR5380_print(struct Scsi_Host *instance)
|
||||||
|
@ -596,12 +558,13 @@ static struct {
|
||||||
{PHASE_UNKNOWN, "UNKNOWN"}
|
{PHASE_UNKNOWN, "UNKNOWN"}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Function : void NCR5380_print_phase(struct Scsi_Host *instance)
|
* NCR5380_print_phase - show SCSI phase
|
||||||
|
* @instance: adapter to dump
|
||||||
*
|
*
|
||||||
* Purpose : print the current SCSI phase for debugging purposes
|
* Print the current SCSI phase for debugging purposes
|
||||||
*
|
*
|
||||||
* Input : instance - which NCR5380
|
* Locks: none
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void NCR5380_print_phase(struct Scsi_Host *instance)
|
static void NCR5380_print_phase(struct Scsi_Host *instance)
|
||||||
|
@ -710,13 +673,12 @@ static void prepare_info(struct Scsi_Host *instance)
|
||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Function : void NCR5380_print_status (struct Scsi_Host *instance)
|
* NCR5380_print_status - dump controller info
|
||||||
|
* @instance: controller to dump
|
||||||
*
|
*
|
||||||
* Purpose : print commands in the various queues, called from
|
* Print commands in the various queues, called from NCR5380_abort
|
||||||
* NCR5380_abort and NCR5380_debug to aid debugging.
|
* to aid debugging.
|
||||||
*
|
|
||||||
* Inputs : instance, pointer to this instance.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd)
|
static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd)
|
||||||
|
@ -807,16 +769,18 @@ static int __maybe_unused NCR5380_show_info(struct seq_file *m,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Function : void NCR5380_init (struct Scsi_Host *instance)
|
* NCR5380_init - initialise an NCR5380
|
||||||
|
* @instance: adapter to configure
|
||||||
|
* @flags: control flags
|
||||||
*
|
*
|
||||||
* Purpose : initializes *instance and corresponding 5380 chip.
|
* Initializes *instance and corresponding 5380 chip,
|
||||||
*
|
* with flags OR'd into the initial flags value.
|
||||||
* Inputs : instance - instantiation of the 5380 driver.
|
|
||||||
*
|
*
|
||||||
* Notes : I assume that the host, hostno, and id bits have been
|
* Notes : I assume that the host, hostno, and id bits have been
|
||||||
* set correctly. I don't care about the irq and other fields.
|
* set correctly. I don't care about the irq and other fields.
|
||||||
*
|
*
|
||||||
|
* Returns 0 for success
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
|
static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
|
||||||
|
@ -861,27 +825,26 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NCR5380_exit - remove an NCR5380
|
||||||
|
* @instance: adapter to remove
|
||||||
|
*
|
||||||
|
* Assumes that no more work can be queued (e.g. by NCR5380_intr).
|
||||||
|
*/
|
||||||
|
|
||||||
static void NCR5380_exit(struct Scsi_Host *instance)
|
static void NCR5380_exit(struct Scsi_Host *instance)
|
||||||
{
|
{
|
||||||
/* Empty, as we didn't schedule any delayed work */
|
cancel_work_sync(&NCR5380_tqueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Function : int NCR5380_queue_command (struct scsi_cmnd *cmd,
|
* NCR5380_queue_command - queue a command
|
||||||
* void (*done)(struct scsi_cmnd *))
|
* @instance: the relevant SCSI adapter
|
||||||
*
|
* @cmd: SCSI command
|
||||||
* Purpose : enqueues a SCSI command
|
|
||||||
*
|
|
||||||
* Inputs : cmd - SCSI command, done - function called on completion, with
|
|
||||||
* a pointer to the command descriptor.
|
|
||||||
*
|
|
||||||
* Returns : 0
|
|
||||||
*
|
|
||||||
* Side effects :
|
|
||||||
* cmd is added to the per instance issue_queue, with minor
|
|
||||||
* twiddling done to the host specific fields of cmd. If the
|
|
||||||
* main coroutine is not running, it is restarted.
|
|
||||||
*
|
*
|
||||||
|
* cmd is added to the per instance issue_queue, with minor
|
||||||
|
* twiddling done to the host specific fields of cmd. If the
|
||||||
|
* main coroutine is not running, it is restarted.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int NCR5380_queue_command(struct Scsi_Host *instance,
|
static int NCR5380_queue_command(struct Scsi_Host *instance,
|
||||||
|
@ -935,6 +898,13 @@ static int NCR5380_queue_command(struct Scsi_Host *instance,
|
||||||
|
|
||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert the cmd into the issue queue. Note that REQUEST SENSE
|
||||||
|
* commands are added to the head of the queue since any command will
|
||||||
|
* clear the contingent allegiance condition that exists and the
|
||||||
|
* sense data is only guaranteed to be valid while the condition exists.
|
||||||
|
*/
|
||||||
|
|
||||||
if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
|
if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
|
||||||
LIST(cmd, hostdata->issue_queue);
|
LIST(cmd, hostdata->issue_queue);
|
||||||
SET_NEXT(cmd, hostdata->issue_queue);
|
SET_NEXT(cmd, hostdata->issue_queue);
|
||||||
|
@ -977,16 +947,15 @@ static inline void maybe_release_dma_irq(struct Scsi_Host *instance)
|
||||||
NCR5380_release_dma_irq(instance);
|
NCR5380_release_dma_irq(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Function : NCR5380_main (void)
|
* NCR5380_main - NCR state machines
|
||||||
*
|
*
|
||||||
* Purpose : NCR5380_main is a coroutine that runs as long as more work can
|
* NCR5380_main is a coroutine that runs as long as more work can
|
||||||
* be done on the NCR5380 host adapters in a system. Both
|
* be done on the NCR5380 host adapters in a system. Both
|
||||||
* NCR5380_queue_command() and NCR5380_intr() will try to start it
|
* NCR5380_queue_command() and NCR5380_intr() will try to start it
|
||||||
* in case it is not running.
|
* in case it is not running.
|
||||||
*
|
*
|
||||||
* NOTE : NCR5380_main exits with interrupts *disabled*, the caller should
|
* Locks: called as its own thread with no locks held.
|
||||||
* reenable them. This prevents reentrancy and kernel stack overflow.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void NCR5380_main(struct work_struct *work)
|
static void NCR5380_main(struct work_struct *work)
|
||||||
|
@ -1239,15 +1208,14 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
|
||||||
#endif /* REAL_DMA */
|
#endif /* REAL_DMA */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Function : void NCR5380_intr (int irq)
|
* NCR5380_intr - generic NCR5380 irq handler
|
||||||
*
|
* @irq: interrupt number
|
||||||
* Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
|
* @dev_id: device info
|
||||||
* from the disconnected queue, and restarting NCR5380_main()
|
|
||||||
* as required.
|
|
||||||
*
|
|
||||||
* Inputs : int irq, irq that caused this interrupt.
|
|
||||||
*
|
*
|
||||||
|
* Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
|
||||||
|
* from the disconnected queue, and restarting NCR5380_main()
|
||||||
|
* as required.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static irqreturn_t NCR5380_intr(int irq, void *dev_id)
|
static irqreturn_t NCR5380_intr(int irq, void *dev_id)
|
||||||
|
@ -1540,7 +1508,7 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
|
||||||
* selection.
|
* selection.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
timeout = jiffies + 25;
|
timeout = jiffies + (250 * HZ / 1000);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX very interesting - we're seeing a bounce where the BSY we
|
* XXX very interesting - we're seeing a bounce where the BSY we
|
||||||
|
@ -2123,9 +2091,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
|
||||||
* If the watchdog timer fires, all future
|
* If the watchdog timer fires, all future
|
||||||
* accesses to this device will use the
|
* accesses to this device will use the
|
||||||
* polled-IO. */
|
* polled-IO. */
|
||||||
printk(KERN_NOTICE "scsi%d: switching target %d "
|
scmd_printk(KERN_INFO, cmd,
|
||||||
"lun %llu to slow handshake\n", HOSTNO,
|
"switching to slow handshake\n");
|
||||||
cmd->device->id, cmd->device->lun);
|
|
||||||
cmd->device->borken = 1;
|
cmd->device->borken = 1;
|
||||||
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
|
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
|
||||||
ICR_ASSERT_ATN);
|
ICR_ASSERT_ATN);
|
||||||
|
@ -2445,20 +2412,18 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
|
||||||
*/
|
*/
|
||||||
default:
|
default:
|
||||||
if (!tmp) {
|
if (!tmp) {
|
||||||
printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
|
printk(KERN_INFO "scsi%d: rejecting message ",
|
||||||
|
instance->host_no);
|
||||||
spi_print_msg(extended_msg);
|
spi_print_msg(extended_msg);
|
||||||
printk("\n");
|
printk("\n");
|
||||||
} else if (tmp != EXTENDED_MESSAGE)
|
} else if (tmp != EXTENDED_MESSAGE)
|
||||||
printk(KERN_DEBUG "scsi%d: rejecting unknown "
|
scmd_printk(KERN_INFO, cmd,
|
||||||
"message %02x from target %d, lun %llu\n",
|
"rejecting unknown message %02x\n",
|
||||||
HOSTNO, tmp, cmd->device->id, cmd->device->lun);
|
tmp);
|
||||||
else
|
else
|
||||||
printk(KERN_DEBUG "scsi%d: rejecting unknown "
|
scmd_printk(KERN_INFO, cmd,
|
||||||
"extended message "
|
"rejecting unknown extended message code %02x, length %d\n",
|
||||||
"code %02x, length %d from target %d, lun %llu\n",
|
extended_msg[1], extended_msg[0]);
|
||||||
HOSTNO, extended_msg[1], extended_msg[0],
|
|
||||||
cmd->device->id, cmd->device->lun);
|
|
||||||
|
|
||||||
|
|
||||||
msgout = MESSAGE_REJECT;
|
msgout = MESSAGE_REJECT;
|
||||||
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
|
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
|
||||||
|
|
Loading…
Reference in New Issue