Commit 63ad6957 authored by James Bottomley's avatar James Bottomley Committed by James Bottomley

SCSI: implement transport attributes for 53c700

his patch moves the internal storage of the offset and period to the
transport class and adds methods to set them (there's no need for a get
method since the value in the transport class is exactly what the driver
believes the transport agreement to be).

You can see how this type of use of the transport class is supposed to
work: the driver now has init and exit routines attaching and releasing
the transport class (that's the reason for the Makefile perturbation
because it has to init before its users).  The correct attributes are
set up in slave_configure() for negotiation and we now export the period
and offset setting functions.
parent 1b98ec6b
......@@ -137,6 +137,9 @@
#include "scsi.h"
#include "hosts.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
......@@ -173,6 +176,8 @@ STATIC void NCR_700_slave_destroy(Scsi_Device *SDpnt);
STATIC struct device_attribute *NCR_700_dev_attrs[];
STATIC struct scsi_transport_template *NCR_700_transport_template = NULL;
static char *NCR_700_phase[] = {
"",
"after selection",
......@@ -236,6 +241,53 @@ static __u8 NCR_700_SDTR_msg[] = {
NCR_700_MAX_OFFSET
};
/* 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)
{
int XFERP;
__u8 min_xferp = (hostdata->chip710
? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
__u8 max_offset = (hostdata->chip710
? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET);
if(offset == 0)
return 0;
if(period < hostdata->min_period) {
printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4);
period = hostdata->min_period;
}
XFERP = (period*4 * hostdata->sync_clock)/1000 - 4;
if(offset > max_offset) {
printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n",
offset, max_offset);
offset = max_offset;
}
if(XFERP < min_xferp) {
printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n",
XFERP, min_xferp);
XFERP = min_xferp;
}
return (offset & 0x0f) | (XFERP & 0x07)<<4;
}
static inline __u8
NCR_700_get_SXFER(Scsi_Device *SDp)
{
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
return NCR_700_offset_period_to_sxfer(hostdata, spi_offset(SDp),
spi_period(SDp));
}
struct Scsi_Host *
NCR_700_detect(Scsi_Host_Template *tpnt,
struct NCR_700_Host_Parameters *hostdata)
......@@ -326,6 +378,8 @@ NCR_700_detect(Scsi_Host_Template *tpnt,
hostdata->cmd = NULL;
host->max_id = 7;
host->max_lun = NCR_700_MAX_LUNS;
BUG_ON(NCR_700_transport_template == NULL);
host->transportt = NCR_700_transport_template;
host->unique_id = hostdata->base;
host->base = hostdata->base;
hostdata->eh_complete = NULL;
......@@ -520,40 +574,6 @@ save_for_reselection(struct NCR_700_Host_Parameters *hostdata,
hostdata->cmd = NULL;
}
/* 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)
{
int XFERP;
__u8 min_xferp = (hostdata->chip710
? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
__u8 max_offset = (hostdata->chip710
? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET);
/* NOTE: NCR_700_SDTR_msg[3] contains our offer of the minimum
* period. It is set in NCR_700_chip_setup() */
if(period < NCR_700_SDTR_msg[3]) {
printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4);
period = NCR_700_SDTR_msg[3];
}
XFERP = (period*4 * hostdata->sync_clock)/1000 - 4;
if(offset > max_offset) {
printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n",
offset, max_offset);
offset = max_offset;
}
if(XFERP < min_xferp) {
printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n",
XFERP, min_xferp);
XFERP = min_xferp;
}
return (offset & 0x0f) | (XFERP & 0x07)<<4;
}
STATIC inline void
NCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, Scsi_Cmnd *SCp,
struct NCR_700_command_slot *slot)
......@@ -724,11 +744,9 @@ NCR_700_chip_setup(struct Scsi_Host *host)
* exact details of this calculation which is based on a
* setting of the SXFER register */
min_period = 1000*(4+min_xferp)/(4*hostdata->sync_clock);
if(min_period > NCR_700_MIN_PERIOD) {
NCR_700_SDTR_msg[3] = min_period;
}
if(hostdata->chip710)
NCR_700_SDTR_msg[4] = NCR_710_MAX_OFFSET;
hostdata->min_period = NCR_700_MIN_PERIOD;
if(min_period > NCR_700_MIN_PERIOD)
hostdata->min_period = min_period;
}
STATIC void
......@@ -777,20 +795,25 @@ process_extended_message(struct Scsi_Host *host,
if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
__u8 period = hostdata->msgin[3];
__u8 offset = hostdata->msgin[4];
__u8 sxfer;
if(offset != 0 && period != 0)
sxfer = NCR_700_offset_period_to_sxfer(hostdata, offset, period);
else
sxfer = 0;
if(offset == 0 || period == 0) {
offset = 0;
period = 0;
}
if(sxfer != NCR_700_get_SXFER(SCp->device)) {
printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n",
host->host_no, pun, lun,
offset, period*4);
NCR_700_set_SXFER(SCp->device, sxfer);
if(NCR_700_is_flag_set(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION)) {
if(spi_offset(SCp->device) != 0)
printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n",
host->host_no, pun, lun,
offset, period*4);
else
printk(KERN_INFO "scsi%d: (%d:%d) Asynchronous\n",
host->host_no, pun, lun);
NCR_700_clear_flag(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
}
spi_offset(SCp->device) = offset;
spi_period(SCp->device) = period;
NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
......@@ -870,7 +893,7 @@ process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata
case A_REJECT_MSG:
if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
/* Rejected our sync negotiation attempt */
NCR_700_set_SXFER(SCp->device, 0);
spi_period(SCp->device) = spi_offset(SCp->device) = 0;
NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
} else if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) {
......@@ -1396,6 +1419,8 @@ NCR_700_start_command(Scsi_Cmnd *SCp)
NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) {
memcpy(&hostdata->msgout[count], NCR_700_SDTR_msg,
sizeof(NCR_700_SDTR_msg));
hostdata->msgout[count+3] = spi_period(SCp->device);
hostdata->msgout[count+4] = spi_offset(SCp->device);
count += sizeof(NCR_700_SDTR_msg);
NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
}
......@@ -1967,9 +1992,51 @@ NCR_700_host_reset(Scsi_Cmnd * SCp)
return SUCCESS;
}
STATIC void
NCR_700_set_period(struct scsi_device *SDp, int period)
{
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
if(!hostdata->fast || period < hostdata->min_period)
return;
spi_period(SDp) = period;
NCR_700_clear_flag(SDp, NCR_700_DEV_NEGOTIATED_SYNC);
NCR_700_clear_flag(SDp, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
NCR_700_set_flag(SDp, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
}
STATIC void
NCR_700_set_offset(struct scsi_device *SDp, int offset)
{
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
if(!hostdata->fast ||
offset > (hostdata->chip710
? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET))
return;
/* if we're currently async, make sure the period is reasonable */
if(spi_offset(SDp) == 0 && (spi_period(SDp) < hostdata->min_period ||
spi_period(SDp) > 0xff))
spi_period(SDp) = hostdata->min_period;
spi_offset(SDp) = offset;
NCR_700_clear_flag(SDp, NCR_700_DEV_NEGOTIATED_SYNC);
NCR_700_clear_flag(SDp, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
NCR_700_set_flag(SDp, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
}
STATIC int
NCR_700_slave_configure(Scsi_Device *SDp)
{
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
/* to do here: allocate memory; build a queue_full list */
if(SDp->tagged_supported) {
/* do TCQ stuff here */
......@@ -1977,6 +2044,11 @@ NCR_700_slave_configure(Scsi_Device *SDp)
/* initialise to default depth */
scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun);
}
if(hostdata->fast) {
NCR_700_set_period(SDp, hostdata->min_period);
NCR_700_set_offset(SDp, hostdata->chip710
? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET);
}
return 0;
}
......@@ -2033,3 +2105,25 @@ STATIC struct device_attribute *NCR_700_dev_attrs[] = {
EXPORT_SYMBOL(NCR_700_detect);
EXPORT_SYMBOL(NCR_700_release);
EXPORT_SYMBOL(NCR_700_intr);
static struct spi_function_template NCR_700_transport_functions = {
.set_period = NCR_700_set_period,
.set_offset = NCR_700_set_offset,
};
static int __init NCR_700_init(void)
{
NCR_700_transport_template = spi_attach_transport(&NCR_700_transport_functions);
if(!NCR_700_transport_template)
return -ENODEV;
return 0;
}
static void __exit NCR_700_exit(void)
{
spi_release_transport(NCR_700_transport_template);
}
module_init(NCR_700_init);
module_exit(NCR_700_exit);
......@@ -99,18 +99,8 @@ struct NCR_700_SG_List {
#define NCR_700_DEV_NEGOTIATED_SYNC (1<<16)
#define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION (1<<17)
#define NCR_700_DEV_BEGIN_TAG_QUEUEING (1<<18)
#define NCR_700_DEV_TAG_STARVATION_WARNED (1<<19)
#define NCR_700_DEV_PRINT_SYNC_NEGOTIATION (1<<19)
static inline void
NCR_700_set_SXFER(Scsi_Device *SDp, __u8 sxfer)
{
SDp->hostdata = (void *)(((long)SDp->hostdata & 0xffffff00) |
(sxfer & 0xff));
}
static inline __u8 NCR_700_get_SXFER(Scsi_Device *SDp)
{
return (((unsigned long)SDp->hostdata) & 0xff);
}
static inline void
NCR_700_set_depth(Scsi_Device *SDp, __u8 depth)
{
......@@ -215,6 +205,7 @@ struct NCR_700_Host_Parameters {
__u8 tag_negotiated;
__u8 rev;
__u8 reselection_id;
__u8 min_period;
/* Free list, singly linked by ITL_forw elements */
struct NCR_700_command_slot *free_list;
......@@ -439,6 +430,7 @@ struct NCR_700_Host_Parameters {
} \
}
static inline __u8
NCR_700_mem_readb(struct Scsi_Host *host, __u32 reg)
{
......
......@@ -864,6 +864,7 @@ config SCSI_NCR53C406A
config SCSI_NCR_D700
tristate "NCR Dual 700 MCA SCSI support"
depends on MCA && SCSI
select SCSI_SPI_ATTRS
help
This is a driver for the MicroChannel Dual 700 card produced by
NCR and commonly used in 345x/35xx/4100 class machines. It always
......@@ -880,6 +881,7 @@ config 53C700_IO_MAPPED
config SCSI_LASI700
tristate "HP Lasi SCSI support for 53c700/710"
depends on GSC && SCSI
select SCSI_SPI_ATTRS
help
This is a driver for the SCSI controller in the Lasi chip found in
many PA-RISC workstations & servers. If you do not know whether you
......@@ -1231,6 +1233,7 @@ config SCSI_SEAGATE
config SCSI_SIM710
tristate "Simple 53c710 SCSI support (Compaq, NCR machines)"
depends on (EISA || MCA) && SCSI
select SCSI_SPI_ATTR
---help---
This driver for NCR53c710 based SCSI host adapters.
......
......@@ -49,7 +49,7 @@ obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o
obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o
obj-$(CONFIG_MVME16x_SCSI) += mvme16x.o 53c7xx.o
obj-$(CONFIG_BVME6000_SCSI) += bvme6000.o 53c7xx.o
obj-$(CONFIG_SCSI_SIM710) += sim710.o 53c700.o
obj-$(CONFIG_SCSI_SIM710) += 53c700.o sim710.o
obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o
obj-$(CONFIG_SCSI_PCI2000) += pci2000.o
obj-$(CONFIG_SCSI_PCI2220I) += pci2220i.o
......@@ -72,7 +72,7 @@ obj-$(CONFIG_SCSI_IN2000) += in2000.o
obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o
obj-$(CONFIG_SCSI_GENERIC_NCR5380_MMIO) += g_NCR5380_mmio.o
obj-$(CONFIG_SCSI_NCR53C406A) += NCR53c406a.o
obj-$(CONFIG_SCSI_NCR_D700) += NCR_D700.o 53c700.o
obj-$(CONFIG_SCSI_NCR_D700) += 53c700.o NCR_D700.o
obj-$(CONFIG_SCSI_NCR_Q720) += NCR_Q720_mod.o
obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o
obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas.o
......@@ -115,7 +115,7 @@ obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o
obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
obj-$(CONFIG_SCSI_FCAL) += fcal.o
obj-$(CONFIG_SCSI_CPQFCTS) += cpqfc.o
obj-$(CONFIG_SCSI_LASI700) += lasi700.o 53c700.o
obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o
obj-$(CONFIG_SCSI_NSP32) += nsp32.o
obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o
obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment