// SPDX-License-Identifier: GPL-2.0-or-later /* NCR (or Symbios) 53c700 and 53c700-66 Driver * * Copyright (C) 2001 by [email protected] **----------------------------------------------------------------------------- ** ** **----------------------------------------------------------------------------- */ /* Notes: * * This driver is designed exclusively for these chips (virtually the * earliest of the scripts engine chips). They need their own drivers * because they are missing so many of the scripts and snazzy register * features of their elder brothers (the 710, 720 and 770). * * The 700 is the lowliest of the line, it can only do async SCSI. * The 700-66 can at least do synchronous SCSI up to 10MHz. * * The 700 chip has no host bus interface logic of its own. However, * it is usually mapped to a location with well defined register * offsets. Therefore, if you can determine the base address and the * irq your board incorporating this chip uses, you can probably use * this driver to run it (although you'll probably have to write a * minimal wrapper for the purpose---see the NCR_D700 driver for * details about how to do this). * * * TODO List: * * 1. Better statistics in the proc fs * * 2. Implement message queue (queues SCSI messages like commands) and make * the abort and device reset functions use them. * */ /* CHANGELOG * * Version 2.8 * * Fixed bad bug affecting tag starvation processing (previously the * driver would hang the system if too many tags starved. Also fixed * bad bug having to do with 10 byte command processing and REQUEST * SENSE (the command would loop forever getting a transfer length * mismatch in the CMD phase). * * Version 2.7 * * Fixed scripts problem which caused certain devices (notably CDRWs) * to hang on initial INQUIRY. Updated NCR_700_readl/writel to use * __raw_readl/writel for parisc compatibility (Thomas * Bogendoerfer). Added missing SCp->request_bufflen initialisation * for sense requests (Ryan Bradetich). * * Version 2.6 * * Following test of the 64 bit parisc kernel by Richard Hirst, * several problems have now been corrected. Also adds support for * consistent memory allocation. * * Version 2.5 * * More Compatibility changes for 710 (now actually works). Enhanced * support for odd clock speeds which constrain SDTR negotiations. * correct cacheline separation for scsi messages and status for * incoherent architectures. Use of the pci mapping functions on * buffers to begin support for 64 bit drivers. * * Version 2.4 * * Added support for the 53c710 chip (in 53c700 emulation mode only---no * special 53c710 instructions or registers are used). * * Version 2.3 * * More endianness/cache coherency changes. * * Better bad device handling (handles devices lying about tag * queueing support and devices which fail to provide sense data on * contingent allegiance conditions) * * Many thanks to Richard Hirst <[email protected]> for patiently * debugging this driver on the parisc architecture and suggesting * many improvements and bug fixes. * * Thanks also go to Linuxcare Inc. for providing several PARISC * machines for me to debug the driver on. * * Version 2.2 * * Made the driver mem or io mapped; added endian invariance; added * dma cache flushing operations for architectures which need it; * added support for more varied clocking speeds. * * Version 2.1 * * Initial modularisation from the D700. See NCR_D700.c for the rest of * the changelog. * */ #define NCR_700_VERSION … #include <linux/kernel.h> #include <linux/types.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/ioport.h> #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/completion.h> #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/blkdev.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/device.h> #include <linux/pgtable.h> #include <asm/dma.h> #include <asm/io.h> #include <asm/byteorder.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_dbg.h> #include <scsi/scsi_eh.h> #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> #include <scsi/scsi_transport.h> #include <scsi/scsi_transport_spi.h> #include "53c700.h" /* NOTE: For 64 bit drivers there are points in the code where we use * a non dereferenceable pointer to point to a structure in dma-able * memory (which is 32 bits) so that we can use all of the structure * operations but take the address at the end. This macro allows us * to truncate the 64 bit pointer down to 32 bits without the compiler * complaining */ #define to32bit(x) … #ifdef NCR_700_DEBUG #define STATIC #else #define STATIC … #endif MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …; /* This is the script */ #include "53c700_d.h" STATIC int NCR_700_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *); STATIC int NCR_700_abort(struct scsi_cmnd * SCpnt); STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt); STATIC void NCR_700_chip_setup(struct Scsi_Host *host); STATIC void NCR_700_chip_reset(struct Scsi_Host *host); STATIC int NCR_700_slave_alloc(struct scsi_device *SDpnt); STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt); STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt); static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth); STATIC const struct attribute_group *NCR_700_dev_groups[]; STATIC struct scsi_transport_template *NCR_700_transport_template = …; static char *NCR_700_phase[] = …; static char *NCR_700_condition[] = …; static char *NCR_700_fatal_messages[] = …; static char *NCR_700_SBCL_bits[] = …; static char *NCR_700_SBCL_to_phase[] = …; /* This translates the SDTR message offset and period to a value * which can be loaded into the SXFER_REG. * * NOTE: According to SCSI-2, the true transfer period (in ns) is * actually four times this period value */ static inline __u8 NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata, __u8 offset, __u8 period) { … } static inline __u8 NCR_700_get_SXFER(struct scsi_device *SDp) { … } static inline dma_addr_t virt_to_dma(struct NCR_700_Host_Parameters *h, void *p) { … } static inline void dma_sync_to_dev(struct NCR_700_Host_Parameters *h, void *addr, size_t size) { … } static inline void dma_sync_from_dev(struct NCR_700_Host_Parameters *h, void *addr, size_t size) { … } struct Scsi_Host * NCR_700_detect(struct scsi_host_template *tpnt, struct NCR_700_Host_Parameters *hostdata, struct device *dev) { … } int NCR_700_release(struct Scsi_Host *host) { … } static inline __u8 NCR_700_identify(int can_disconnect, __u8 lun) { … } /* * Function : static int data_residual (Scsi_Host *host) * * Purpose : return residual data count of what's in the chip. If you * really want to know what this function is doing, it's almost a * direct transcription of the algorithm described in the 53c710 * guide, except that the DBC and DFIFO registers are only 6 bits * wide on a 53c700. * * Inputs : host - SCSI host */ static inline int NCR_700_data_residual (struct Scsi_Host *host) { … } /* print out the SCSI wires and corresponding phase from the SBCL register * in the chip */ static inline char * sbcl_to_string(__u8 sbcl) { … } static inline __u8 bitmap_to_number(__u8 bitmap) { … } /* Pull a slot off the free list */ STATIC struct NCR_700_command_slot * find_empty_slot(struct NCR_700_Host_Parameters *hostdata) { … } STATIC void free_slot(struct NCR_700_command_slot *slot, struct NCR_700_Host_Parameters *hostdata) { … } /* This routine really does very little. The command is indexed on the ITL and (if tagged) the ITLQ lists in _queuecommand */ STATIC void save_for_reselection(struct NCR_700_Host_Parameters *hostdata, struct scsi_cmnd *SCp, __u32 dsp) { … } STATIC inline void NCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, struct scsi_cmnd *SCp, struct NCR_700_command_slot *slot) { … } STATIC inline void NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, struct scsi_cmnd *SCp, int result) { … } STATIC void NCR_700_internal_bus_reset(struct Scsi_Host *host) { … } STATIC void NCR_700_chip_setup(struct Scsi_Host *host) { … } STATIC void NCR_700_chip_reset(struct Scsi_Host *host) { … } /* The heart of the message processing engine is that the instruction * immediately after the INT is the normal case (and so must be CLEAR * ACK). If we want to do something else, we call that routine in * scripts and set temp to be the normal case + 8 (skipping the CLEAR * ACK) so that the routine returns correctly to resume its activity * */ STATIC __u32 process_extended_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata, struct scsi_cmnd *SCp, __u32 dsp, __u32 dsps) { … } STATIC __u32 process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata, struct scsi_cmnd *SCp, __u32 dsp, __u32 dsps) { … } STATIC __u32 process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata) { … } /* We run the 53c700 with selection interrupts always enabled. This * means that the chip may be selected as soon as the bus frees. On a * busy bus, this can be before the scripts engine finishes its * processing. Therefore, part of the selection processing has to be * to find out what the scripts engine is doing and complete the * function if necessary (i.e. process the pending disconnect or save * the interrupted initial selection */ STATIC inline __u32 process_selection(struct Scsi_Host *host, __u32 dsp) { … } static inline void NCR_700_clear_fifo(struct Scsi_Host *host) { … } static inline void NCR_700_flush_fifo(struct Scsi_Host *host) { … } /* The queue lock with interrupts disabled must be held on entry to * this function */ STATIC int NCR_700_start_command(struct scsi_cmnd *SCp) { … } irqreturn_t NCR_700_intr(int irq, void *dev_id) { … } static int NCR_700_queuecommand_lck(struct scsi_cmnd *SCp) { … } STATIC DEF_SCSI_QCMD(…) STATIC int NCR_700_abort(struct scsi_cmnd * SCp) { … } STATIC int NCR_700_host_reset(struct scsi_cmnd * SCp) { … } STATIC void NCR_700_set_period(struct scsi_target *STp, int period) { … } STATIC void NCR_700_set_offset(struct scsi_target *STp, int offset) { … } STATIC int NCR_700_slave_alloc(struct scsi_device *SDp) { … } STATIC int NCR_700_slave_configure(struct scsi_device *SDp) { … } STATIC void NCR_700_slave_destroy(struct scsi_device *SDp) { … } static int NCR_700_change_queue_depth(struct scsi_device *SDp, int depth) { … } static ssize_t NCR_700_show_active_tags(struct device *dev, struct device_attribute *attr, char *buf) { … } static struct device_attribute NCR_700_active_tags_attr = …; STATIC struct attribute *NCR_700_dev_attrs[] = …; ATTRIBUTE_GROUPS(…); EXPORT_SYMBOL(…); EXPORT_SYMBOL(…); EXPORT_SYMBOL(…); static struct spi_function_template NCR_700_transport_functions = …; static int __init NCR_700_init(void) { … } static void __exit NCR_700_exit(void) { … } module_init(…) …; module_exit(NCR_700_exit);