linux/drivers/scsi/53c700.c

// 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);