Release 4.11 drivers/scsi/nsp32.c
/*
* NinjaSCSI-32Bi Cardbus, NinjaSCSI-32UDE PCI/CardBus SCSI driver
* Copyright (C) 2001, 2002, 2003
* YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
* GOTO Masanori <gotom@debian.or.jp>, <gotom@debian.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* Revision History:
* 1.0: Initial Release.
* 1.1: Add /proc SDTR status.
* Remove obsolete error handler nsp32_reset.
* Some clean up.
* 1.2: PowerPC (big endian) support.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <linux/major.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/dma-mapping.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
#include "nsp32.h"
/***********************************************************************
* Module parameters
*/
static int trans_mode = 0;
/* default: BIOS */
module_param (trans_mode, int, 0);
MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS(default) 1: Async 2: Ultra20M");
#define ASYNC_MODE 1
#define ULTRA20M_MODE 2
static bool auto_param = 0;
/* default: ON */
module_param (auto_param, bool, 0);
MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON(default) 1: OFF)");
static bool disc_priv = 1;
/* default: OFF */
module_param (disc_priv, bool, 0);
MODULE_PARM_DESC(disc_priv, "disconnection privilege mode (0: ON 1: OFF(default))");
MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>, GOTO Masanori <gotom@debian.or.jp>");
MODULE_DESCRIPTION("Workbit NinjaSCSI-32Bi/UDE CardBus/PCI SCSI host bus adapter module");
MODULE_LICENSE("GPL");
static const char *nsp32_release_version = "1.2";
/****************************************************************************
* Supported hardware
*/
static struct pci_device_id nsp32_pci_table[] = {
{
.vendor = PCI_VENDOR_ID_IODATA,
.device = PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = MODEL_IODATA,
},
{
.vendor = PCI_VENDOR_ID_WORKBIT,
.device = PCI_DEVICE_ID_NINJASCSI_32BI_KME,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = MODEL_KME,
},
{
.vendor = PCI_VENDOR_ID_WORKBIT,
.device = PCI_DEVICE_ID_NINJASCSI_32BI_WBT,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = MODEL_WORKBIT,
},
{
.vendor = PCI_VENDOR_ID_WORKBIT,
.device = PCI_DEVICE_ID_WORKBIT_STANDARD,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = MODEL_PCI_WORKBIT,
},
{
.vendor = PCI_VENDOR_ID_WORKBIT,
.device = PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = MODEL_LOGITEC,
},
{
.vendor = PCI_VENDOR_ID_WORKBIT,
.device = PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = MODEL_PCI_LOGITEC,
},
{
.vendor = PCI_VENDOR_ID_WORKBIT,
.device = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = MODEL_PCI_MELCO,
},
{
.vendor = PCI_VENDOR_ID_WORKBIT,
.device = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO_II,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = MODEL_PCI_MELCO,
},
{0,0,},
};
MODULE_DEVICE_TABLE(pci, nsp32_pci_table);
static nsp32_hw_data nsp32_data_base;
/* probe <-> detect glue */
/*
* Period/AckWidth speed conversion table
*
* Note: This period/ackwidth speed table must be in descending order.
*/
static nsp32_sync_table nsp32_sync_table_40M[] = {
/* {PNo, AW, SP, EP, SREQ smpl} Speed(MB/s) Period AckWidth */
{0x1, 0, 0x0c, 0x0c, SMPL_40M}, /* 20.0 : 50ns, 25ns */
{0x2, 0, 0x0d, 0x18, SMPL_40M}, /* 13.3 : 75ns, 25ns */
{0x3, 1, 0x19, 0x19, SMPL_40M}, /* 10.0 : 100ns, 50ns */
{0x4, 1, 0x1a, 0x1f, SMPL_20M}, /* 8.0 : 125ns, 50ns */
{0x5, 2, 0x20, 0x25, SMPL_20M}, /* 6.7 : 150ns, 75ns */
{0x6, 2, 0x26, 0x31, SMPL_20M}, /* 5.7 : 175ns, 75ns */
{0x7, 3, 0x32, 0x32, SMPL_20M}, /* 5.0 : 200ns, 100ns */
{0x8, 3, 0x33, 0x38, SMPL_10M}, /* 4.4 : 225ns, 100ns */
{0x9, 3, 0x39, 0x3e, SMPL_10M}, /* 4.0 : 250ns, 100ns */
};
static nsp32_sync_table nsp32_sync_table_20M[] = {
{0x1, 0, 0x19, 0x19, SMPL_40M}, /* 10.0 : 100ns, 50ns */
{0x2, 0, 0x1a, 0x25, SMPL_20M}, /* 6.7 : 150ns, 50ns */
{0x3, 1, 0x26, 0x32, SMPL_20M}, /* 5.0 : 200ns, 100ns */
{0x4, 1, 0x33, 0x3e, SMPL_10M}, /* 4.0 : 250ns, 100ns */
{0x5, 2, 0x3f, 0x4b, SMPL_10M}, /* 3.3 : 300ns, 150ns */
{0x6, 2, 0x4c, 0x57, SMPL_10M}, /* 2.8 : 350ns, 150ns */
{0x7, 3, 0x58, 0x64, SMPL_10M}, /* 2.5 : 400ns, 200ns */
{0x8, 3, 0x65, 0x70, SMPL_10M}, /* 2.2 : 450ns, 200ns */
{0x9, 3, 0x71, 0x7d, SMPL_10M}, /* 2.0 : 500ns, 200ns */
};
static nsp32_sync_table nsp32_sync_table_pci[] = {
{0x1, 0, 0x0c, 0x0f, SMPL_40M}, /* 16.6 : 60ns, 30ns */
{0x2, 0, 0x10, 0x16, SMPL_40M}, /* 11.1 : 90ns, 30ns */
{0x3, 1, 0x17, 0x1e, SMPL_20M}, /* 8.3 : 120ns, 60ns */
{0x4, 1, 0x1f, 0x25, SMPL_20M}, /* 6.7 : 150ns, 60ns */
{0x5, 2, 0x26, 0x2d, SMPL_20M}, /* 5.6 : 180ns, 90ns */
{0x6, 2, 0x2e, 0x34, SMPL_10M}, /* 4.8 : 210ns, 90ns */
{0x7, 3, 0x35, 0x3c, SMPL_10M}, /* 4.2 : 240ns, 120ns */
{0x8, 3, 0x3d, 0x43, SMPL_10M}, /* 3.7 : 270ns, 120ns */
{0x9, 3, 0x44, 0x4b, SMPL_10M}, /* 3.3 : 300ns, 120ns */
};
/*
* function declaration
*/
/* module entry point */
static int nsp32_probe (struct pci_dev *, const struct pci_device_id *);
static void nsp32_remove(struct pci_dev *);
static int __init init_nsp32 (void);
static void __exit exit_nsp32 (void);
/* struct struct scsi_host_template */
static int nsp32_show_info (struct seq_file *, struct Scsi_Host *);
static int nsp32_detect (struct pci_dev *pdev);
static int nsp32_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
static const char *nsp32_info (struct Scsi_Host *);
static int nsp32_release (struct Scsi_Host *);
/* SCSI error handler */
static int nsp32_eh_abort (struct scsi_cmnd *);
static int nsp32_eh_bus_reset (struct scsi_cmnd *);
static int nsp32_eh_host_reset(struct scsi_cmnd *);
/* generate SCSI message */
static void nsp32_build_identify(struct scsi_cmnd *);
static void nsp32_build_nop (struct scsi_cmnd *);
static void nsp32_build_reject (struct scsi_cmnd *);
static void nsp32_build_sdtr (struct scsi_cmnd *, unsigned char, unsigned char);
/* SCSI message handler */
static int nsp32_busfree_occur(struct scsi_cmnd *, unsigned short);
static void nsp32_msgout_occur (struct scsi_cmnd *);
static void nsp32_msgin_occur (struct scsi_cmnd *, unsigned long, unsigned short);
static int nsp32_setup_sg_table (struct scsi_cmnd *);
static int nsp32_selection_autopara(struct scsi_cmnd *);
static int nsp32_selection_autoscsi(struct scsi_cmnd *);
static void nsp32_scsi_done (struct scsi_cmnd *);
static int nsp32_arbitration (struct scsi_cmnd *, unsigned int);
static int nsp32_reselection (struct scsi_cmnd *, unsigned char);
static void nsp32_adjust_busfree (struct scsi_cmnd *, unsigned int);
static void nsp32_restart_autoscsi (struct scsi_cmnd *, unsigned short);
/* SCSI SDTR */
static void nsp32_analyze_sdtr (struct scsi_cmnd *);
static int nsp32_search_period_entry(nsp32_hw_data *, nsp32_target *, unsigned char);
static void nsp32_set_async (nsp32_hw_data *, nsp32_target *);
static void nsp32_set_max_sync (nsp32_hw_data *, nsp32_target *, unsigned char *, unsigned char *);
static void nsp32_set_sync_entry (nsp32_hw_data *, nsp32_target *, int, unsigned char);
/* SCSI bus status handler */
static void nsp32_wait_req (nsp32_hw_data *, int);
static void nsp32_wait_sack (nsp32_hw_data *, int);
static void nsp32_sack_assert (nsp32_hw_data *);
static void nsp32_sack_negate (nsp32_hw_data *);
static void nsp32_do_bus_reset(nsp32_hw_data *);
/* hardware interrupt handler */
static irqreturn_t do_nsp32_isr(int, void *);
/* initialize hardware */
static int nsp32hw_init(nsp32_hw_data *);
/* EEPROM handler */
static int nsp32_getprom_param (nsp32_hw_data *);
static int nsp32_getprom_at24 (nsp32_hw_data *);
static int nsp32_getprom_c16 (nsp32_hw_data *);
static void nsp32_prom_start (nsp32_hw_data *);
static void nsp32_prom_stop (nsp32_hw_data *);
static int nsp32_prom_read (nsp32_hw_data *, int);
static int nsp32_prom_read_bit (nsp32_hw_data *);
static void nsp32_prom_write_bit(nsp32_hw_data *, int);
static void nsp32_prom_set (nsp32_hw_data *, int, int);
static int nsp32_prom_get (nsp32_hw_data *, int);
/* debug/warning/info message */
static void nsp32_message (const char *, int, char *, char *, ...);
#ifdef NSP32_DEBUG
static void nsp32_dmessage(const char *, int, int, char *, ...);
#endif
/*
* max_sectors is currently limited up to 128.
*/
static struct scsi_host_template nsp32_template = {
.proc_name = "nsp32",
.name = "Workbit NinjaSCSI-32Bi/UDE",
.show_info = nsp32_show_info,
.info = nsp32_info,
.queuecommand = nsp32_queuecommand,
.can_queue = 1,
.sg_tablesize = NSP32_SG_SIZE,
.max_sectors = 128,
.this_id = NSP32_HOST_SCSIID,
.use_clustering = DISABLE_CLUSTERING,
.eh_abort_handler = nsp32_eh_abort,
.eh_bus_reset_handler = nsp32_eh_bus_reset,
.eh_host_reset_handler = nsp32_eh_host_reset,
/* .highmem_io = 1, */
};
#include "nsp32_io.h"
/***********************************************************************
* debug, error print
*/
#ifndef NSP32_DEBUG
# define NSP32_DEBUG_MASK 0x000000
# define nsp32_msg(type, args...) nsp32_message ("", 0, (type), args)
# define nsp32_dbg(mask, args...)
/* */
#else
# define NSP32_DEBUG_MASK 0xffffff
# define nsp32_msg(type, args...) \
nsp32_message (__func__, __LINE__, (type), args)
# define nsp32_dbg(mask, args...) \
nsp32_dmessage(__func__, __LINE__, (mask), args)
#endif
#define NSP32_DEBUG_QUEUECOMMAND BIT(0)
#define NSP32_DEBUG_REGISTER BIT(1)
#define NSP32_DEBUG_AUTOSCSI BIT(2)
#define NSP32_DEBUG_INTR BIT(3)
#define NSP32_DEBUG_SGLIST BIT(4)
#define NSP32_DEBUG_BUSFREE BIT(5)
#define NSP32_DEBUG_CDB_CONTENTS BIT(6)
#define NSP32_DEBUG_RESELECTION BIT(7)
#define NSP32_DEBUG_MSGINOCCUR BIT(8)
#define NSP32_DEBUG_EEPROM BIT(9)
#define NSP32_DEBUG_MSGOUTOCCUR BIT(10)
#define NSP32_DEBUG_BUSRESET BIT(11)
#define NSP32_DEBUG_RESTART BIT(12)
#define NSP32_DEBUG_SYNC BIT(13)
#define NSP32_DEBUG_WAIT BIT(14)
#define NSP32_DEBUG_TARGETFLAG BIT(15)
#define NSP32_DEBUG_PROC BIT(16)
#define NSP32_DEBUG_INIT BIT(17)
#define NSP32_SPECIAL_PRINT_REGISTER BIT(20)
#define NSP32_DEBUG_BUF_LEN 100
static void nsp32_message(const char *func, int line, char *type, char *fmt, ...)
{
va_list args;
char buf[NSP32_DEBUG_BUF_LEN];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
#ifndef NSP32_DEBUG
printk("%snsp32: %s\n", type, buf);
#else
printk("%snsp32: %s (%d): %s\n", type, func, line, buf);
#endif
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds | 80 | 90.91% | 1 | 50.00% |
Goto Masanori | 8 | 9.09% | 1 | 50.00% |
Total | 88 | 100.00% | 2 | 100.00% |
#ifdef NSP32_DEBUG
static void nsp32_dmessage(const char *func, int line, int mask, char *fmt, ...)
{
va_list args;
char buf[NSP32_DEBUG_BUF_LEN];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
if (mask & NSP32_DEBUG_MASK) {
printk("nsp32-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds | 66 | 83.54% | 1 | 50.00% |
Goto Masanori | 13 | 16.46% | 1 | 50.00% |
Total | 79 | 100.00% | 2 | 100.00% |
#endif
#ifdef NSP32_DEBUG
# include "nsp32_debug.c"
#else
# define show_command(arg)
/* */
# define show_busphase(arg)
/* */
# define show_autophase(arg)
/* */
#endif
/*
* IDENTIFY Message
*/
static void nsp32_build_identify(struct scsi_cmnd *SCpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
int pos = data->msgout_len;
int mode = FALSE;
/* XXX: Auto DiscPriv detection is progressing... */
if (disc_priv == 0) {
/* mode = TRUE; */
}
data->msgoutbuf[pos] = IDENTIFY(mode, SCpnt->device->lun); pos++;
data->msgout_len = pos;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds | 74 | 97.37% | 1 | 50.00% |
Christoph Hellwig | 2 | 2.63% | 1 | 50.00% |
Total | 76 | 100.00% | 2 | 100.00% |
/*
* SDTR Message Routine
*/
static void nsp32_build_sdtr(struct scsi_cmnd *SCpnt,
unsigned char period,
unsigned char offset)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
int pos = data->msgout_len;
data->msgoutbuf[pos] = EXTENDED_MESSAGE; pos++;
data->msgoutbuf[pos] = EXTENDED_SDTR_LEN; pos++;
data->msgoutbuf[pos] = EXTENDED_SDTR; pos++;
data->msgoutbuf[pos] = period; pos++;
data->msgoutbuf[pos] = offset; pos++;
data->msgout_len = pos;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds | 93 | 86.11% | 1 | 33.33% |
Goto Masanori | 13 | 12.04% | 1 | 33.33% |
Christoph Hellwig | 2 | 1.85% | 1 | 33.33% |
Total | 108 | 100.00% | 3 | 100.00% |
/*
* No Operation Message
*/
static void nsp32_build_nop(struct scsi_cmnd *SCpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
int pos = data->msgout_len;
if (pos != 0) {
nsp32_msg(KERN_WARNING,
"Some messages are already contained!");
return;
}
data->msgoutbuf[pos] = NOP; pos++;
data->msgout_len = pos;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds | 59 | 86.76% | 1 | 33.33% |
Goto Masanori | 7 | 10.29% | 1 | 33.33% |
Christoph Hellwig | 2 | 2.94% | 1 | 33.33% |
Total | 68 | 100.00% | 3 | 100.00% |
/*
* Reject Message
*/
static void nsp32_build_reject(struct scsi_cmnd *SCpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
int pos = data->msgout_len;
data->msgoutbuf[pos] = MESSAGE_REJECT; pos++;
data->msgout_len = pos;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds | 47 | 90.38% | 1 | 33.33% |
Goto Masanori | 3 | 5.77% | 1 | 33.33% |
Christoph Hellwig | 2 | 3.85% | 1 | 33.33% |
Total | 52 | 100.00% | 3 | 100.00% |
/*
* timer
*/
#if 0
static void nsp32_start_timer(struct scsi_cmnd *SCpnt, int time)
{
unsigned int base = SCpnt->host->io_port;
nsp32_dbg(NSP32_DEBUG_INTR, "timer=%d", time);
if (time & (~TIMER_CNT_MASK)) {
nsp32_dbg(NSP32_DEBUG_INTR, "timer set overflow");
}
nsp32_write2(base, TIMER_SET, time & TIMER_CNT_MASK);
}
#endif
/*
* set SCSI command and other parameter to asic, and start selection phase
*/
static int nsp32_selection_autopara(struct scsi_cmnd *SCpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
unsigned int base = SCpnt->device->host->io_port;
unsigned int host_id = SCpnt->device->host->this_id;
unsigned char target = scmd_id(SCpnt);
nsp32_autoparam *param = data->autoparam;
unsigned char phase;
int i, ret;
unsigned int msgout;
u16_le s;
nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in");
/*
* check bus free
*/
phase = nsp32_read1(base, SCSI_BUS_MONITOR);
if (phase != BUSMON_BUS_FREE) {
nsp32_msg(KERN_WARNING, "bus busy");
show_busphase(phase & BUSMON_PHASE_MASK);
SCpnt->result = DID_BUS_BUSY << 16;
return FALSE;
}
/*
* message out
*
* Note: If the range of msgout_len is 1 - 3, fill scsi_msgout.
* over 3 messages needs another routine.
*/
if (data->msgout_len == 0) {
nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!");
SCpnt->result = DID_ERROR << 16;
return FALSE;
} else if (data->msgout_len > 0 && data->msgout_len <= 3) {
msgout = 0;
for (i = 0; i < data->msgout_len; i++) {
/*
* the sending order of the message is:
* MCNT 3: MSG#0 -> MSG#1 -> MSG#2
* MCNT 2: MSG#1 -> MSG#2
* MCNT 1: MSG#2
*/
msgout >>= 8;
msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24);
}
msgout |= MV_VALID; /* MV valid */
msgout |= (unsigned int)data->msgout_len; /* len */
} else {
/* data->msgout_len > 3 */
msgout = 0;
}
// nsp_dbg(NSP32_DEBUG_AUTOSCSI, "sel time out=0x%x\n", nsp32_read2(base, SEL_TIME_OUT));
// nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME);
/*
* setup asic parameter
*/
memset(param, 0, sizeof(nsp32_autoparam));
/* cdb */
for (i = 0; i < SCpnt->cmd_len; i++) {
param->cdb[4 * i] = SCpnt->cmnd[i];
}
/* outgoing messages */
param->msgout = cpu_to_le32(msgout);
/* syncreg, ackwidth, target id, SREQ sampling rate */
param->syncreg = data->cur_target->syncreg;
param->ackwidth = data->cur_target->ackwidth;
param->target_id = BIT(host_id) | BIT(target);
param->sample_reg = data->cur_target->sample_reg;
// nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "sample rate=0x%x\n", data->cur_target->sample_reg);
/* command control */
param->command_control = cpu_to_le16(CLEAR_CDB_FIFO_POINTER |
AUTOSCSI_START |
AUTO_MSGIN_00_OR_04 |
AUTO_MSGIN_02 |
AUTO_ATN );
/* transfer control */
s = 0;
switch (data->trans_method) {
case NSP32_TRANSFER_BUSMASTER:
s |= BM_START;
break;
case NSP32_TRANSFER_MMIO:
s |= CB_MMIO_MODE;
break;
case NSP32_TRANSFER_PIO:
s |= CB_IO_MODE;
break;
default:
nsp32_msg(KERN_ERR, "unknown trans_method");
break;
}
/*
* OR-ed BLIEND_MODE, FIFO intr is decreased, instead of PCI bus waits.
* For bus master transfer, it's taken off.
*/
s |= (TRANSFER_GO | ALL_COUNTER_CLR);
param->transfer_control = cpu_to_le16(s);
/* sg table addr */
param->sgt_pointer = cpu_to_le32(data->cur_lunt->sglun_paddr);
/*
* transfer parameter to ASIC
*/
nsp32_write4(base, SGT_ADR, data->auto_paddr);
nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER |
AUTO_PARAMETER );
/*
* Check arbitration
*/
ret = nsp32_arbitration(SCpnt, base);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds | 389 | 80.04% | 1 | 20.00% |
Goto Masanori | 91 | 18.72% | 1 | 20.00% |
Jeff Garzik | 3 | 0.62% | 1 | 20.00% |
Christoph Hellwig | 2 | 0.41% | 1 | 20.00% |
Luben Tuikov | 1 | 0.21% | 1 | 20.00% |
Total | 486 | 100.00% | 5 | 100.00% |
/*
* Selection with AUTO SCSI (without AUTO PARAMETER)
*/
static int nsp32_selection_autoscsi(struct scsi_cmnd *SCpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
unsigned int base = SCpnt->device->host->io_port;
unsigned int host_id = SCpnt->device->host->this_id;
unsigned char target = scmd_id(SCpnt);
unsigned char phase;
int status;
unsigned short command = 0;
unsigned int msgout = 0;
unsigned short execph;
int i;
nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in");
/*
* IRQ disable
*/
nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
/*
* check bus line
*/
phase = nsp32_read1(base, SCSI_BUS_MONITOR);
if(((phase & BUSMON_BSY) == 1) || (phase & BUSMON_SEL) == 1) {
nsp32_msg(KERN_WARNING, "bus busy");
SCpnt->result = DID_BUS_BUSY << 16;
status = 1;
goto out;
}
/*
* clear execph
*/
execph = nsp32_read2(base, SCSI_EXECUTE_PHASE);
/*
* clear FIFO counter to set CDBs
*/
nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER);
/*
* set CDB0 - CDB15
*/
for (i = 0; i < SCpnt->cmd_len; i++) {
nsp32_write1(base, COMMAND_DATA, SCpnt->cmnd[i]);
}
nsp32_dbg(NSP32_DEBUG_CDB_CONTENTS, "CDB[0]=[0x%x]", SCpnt->cmnd[0]);
/*
* set SCSIOUT LATCH(initiator)/TARGET(target) (OR-ed) ID
*/
nsp32_write1(base, SCSI_OUT_LATCH_TARGET_ID, BIT(host_id) | BIT(target));
/*
* set SCSI MSGOUT REG
*
* Note: If the range of msgout_len is 1 - 3, fill scsi_msgout.
* over 3 messages needs another routine.
*/
if (data->msgout_len == 0) {
nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!");
SCpnt->result = DID_ERROR << 16;
status = 1;
goto out;
} else if (data->msgout_len > 0 && data->msgout_len <= 3) {
msgout = 0;
for (i = 0; i < data->msgout_len; i++) {
/*
* the sending order of the message is:
* MCNT 3: MSG#0 -> MSG#1 -> MSG#2
* MCNT 2: MSG#1 -> MSG#2
* MCNT 1: MSG#2
*/
msgout >>= 8;
msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24);