162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * NinjaSCSI-32Bi Cardbus, NinjaSCSI-32UDE PCI/CardBus SCSI driver
462306a36Sopenharmony_ci * Copyright (C) 2001, 2002, 2003
562306a36Sopenharmony_ci *      YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
662306a36Sopenharmony_ci *      GOTO Masanori <gotom@debian.or.jp>, <gotom@debian.org>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Revision History:
962306a36Sopenharmony_ci *   1.0: Initial Release.
1062306a36Sopenharmony_ci *   1.1: Add /proc SDTR status.
1162306a36Sopenharmony_ci *        Remove obsolete error handler nsp32_reset.
1262306a36Sopenharmony_ci *        Some clean up.
1362306a36Sopenharmony_ci *   1.2: PowerPC (big endian) support.
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/init.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/string.h>
2062306a36Sopenharmony_ci#include <linux/timer.h>
2162306a36Sopenharmony_ci#include <linux/ioport.h>
2262306a36Sopenharmony_ci#include <linux/major.h>
2362306a36Sopenharmony_ci#include <linux/blkdev.h>
2462306a36Sopenharmony_ci#include <linux/interrupt.h>
2562306a36Sopenharmony_ci#include <linux/pci.h>
2662306a36Sopenharmony_ci#include <linux/delay.h>
2762306a36Sopenharmony_ci#include <linux/ctype.h>
2862306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include <asm/dma.h>
3162306a36Sopenharmony_ci#include <asm/io.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <scsi/scsi.h>
3462306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
3562306a36Sopenharmony_ci#include <scsi/scsi_device.h>
3662306a36Sopenharmony_ci#include <scsi/scsi_host.h>
3762306a36Sopenharmony_ci#include <scsi/scsi_ioctl.h>
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#include "nsp32.h"
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/***********************************************************************
4362306a36Sopenharmony_ci * Module parameters
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_cistatic int       trans_mode = 0;	/* default: BIOS */
4662306a36Sopenharmony_cimodule_param     (trans_mode, int, 0);
4762306a36Sopenharmony_ciMODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS(default) 1: Async 2: Ultra20M");
4862306a36Sopenharmony_ci#define ASYNC_MODE    1
4962306a36Sopenharmony_ci#define ULTRA20M_MODE 2
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic bool      auto_param = 0;	/* default: ON */
5262306a36Sopenharmony_cimodule_param     (auto_param, bool, 0);
5362306a36Sopenharmony_ciMODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON(default) 1: OFF)");
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic bool      disc_priv  = 1;	/* default: OFF */
5662306a36Sopenharmony_cimodule_param     (disc_priv, bool, 0);
5762306a36Sopenharmony_ciMODULE_PARM_DESC(disc_priv,  "disconnection privilege mode (0: ON 1: OFF(default))");
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ciMODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>, GOTO Masanori <gotom@debian.or.jp>");
6062306a36Sopenharmony_ciMODULE_DESCRIPTION("Workbit NinjaSCSI-32Bi/UDE CardBus/PCI SCSI host bus adapter module");
6162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic const char *nsp32_release_version = "1.2";
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/****************************************************************************
6762306a36Sopenharmony_ci * Supported hardware
6862306a36Sopenharmony_ci */
6962306a36Sopenharmony_cistatic struct pci_device_id nsp32_pci_table[] = {
7062306a36Sopenharmony_ci	{
7162306a36Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_IODATA,
7262306a36Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II,
7362306a36Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
7462306a36Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
7562306a36Sopenharmony_ci		.driver_data = MODEL_IODATA,
7662306a36Sopenharmony_ci	},
7762306a36Sopenharmony_ci	{
7862306a36Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
7962306a36Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_KME,
8062306a36Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
8162306a36Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
8262306a36Sopenharmony_ci		.driver_data = MODEL_KME,
8362306a36Sopenharmony_ci	},
8462306a36Sopenharmony_ci	{
8562306a36Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
8662306a36Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_WBT,
8762306a36Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
8862306a36Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
8962306a36Sopenharmony_ci		.driver_data = MODEL_WORKBIT,
9062306a36Sopenharmony_ci	},
9162306a36Sopenharmony_ci	{
9262306a36Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
9362306a36Sopenharmony_ci		.device      = PCI_DEVICE_ID_WORKBIT_STANDARD,
9462306a36Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
9562306a36Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
9662306a36Sopenharmony_ci		.driver_data = MODEL_PCI_WORKBIT,
9762306a36Sopenharmony_ci	},
9862306a36Sopenharmony_ci	{
9962306a36Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
10062306a36Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC,
10162306a36Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
10262306a36Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
10362306a36Sopenharmony_ci		.driver_data = MODEL_LOGITEC,
10462306a36Sopenharmony_ci	},
10562306a36Sopenharmony_ci	{
10662306a36Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
10762306a36Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC,
10862306a36Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
10962306a36Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
11062306a36Sopenharmony_ci		.driver_data = MODEL_PCI_LOGITEC,
11162306a36Sopenharmony_ci	},
11262306a36Sopenharmony_ci	{
11362306a36Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
11462306a36Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO,
11562306a36Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
11662306a36Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
11762306a36Sopenharmony_ci		.driver_data = MODEL_PCI_MELCO,
11862306a36Sopenharmony_ci	},
11962306a36Sopenharmony_ci	{
12062306a36Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
12162306a36Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO_II,
12262306a36Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
12362306a36Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
12462306a36Sopenharmony_ci		.driver_data = MODEL_PCI_MELCO,
12562306a36Sopenharmony_ci	},
12662306a36Sopenharmony_ci	{0,0,},
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, nsp32_pci_table);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic nsp32_hw_data nsp32_data_base;  /* probe <-> detect glue */
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/*
13462306a36Sopenharmony_ci * Period/AckWidth speed conversion table
13562306a36Sopenharmony_ci *
13662306a36Sopenharmony_ci * Note: This period/ackwidth speed table must be in descending order.
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_cistatic nsp32_sync_table nsp32_sync_table_40M[] = {
13962306a36Sopenharmony_ci     /* {PNo, AW,   SP,   EP, SREQ smpl}  Speed(MB/s) Period AckWidth */
14062306a36Sopenharmony_ci	{0x1,  0, 0x0c, 0x0c, SMPL_40M},  /*  20.0 :  50ns,  25ns */
14162306a36Sopenharmony_ci	{0x2,  0, 0x0d, 0x18, SMPL_40M},  /*  13.3 :  75ns,  25ns */
14262306a36Sopenharmony_ci	{0x3,  1, 0x19, 0x19, SMPL_40M},  /*  10.0 : 100ns,  50ns */
14362306a36Sopenharmony_ci	{0x4,  1, 0x1a, 0x1f, SMPL_20M},  /*   8.0 : 125ns,  50ns */
14462306a36Sopenharmony_ci	{0x5,  2, 0x20, 0x25, SMPL_20M},  /*   6.7 : 150ns,  75ns */
14562306a36Sopenharmony_ci	{0x6,  2, 0x26, 0x31, SMPL_20M},  /*   5.7 : 175ns,  75ns */
14662306a36Sopenharmony_ci	{0x7,  3, 0x32, 0x32, SMPL_20M},  /*   5.0 : 200ns, 100ns */
14762306a36Sopenharmony_ci	{0x8,  3, 0x33, 0x38, SMPL_10M},  /*   4.4 : 225ns, 100ns */
14862306a36Sopenharmony_ci	{0x9,  3, 0x39, 0x3e, SMPL_10M},  /*   4.0 : 250ns, 100ns */
14962306a36Sopenharmony_ci};
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic nsp32_sync_table nsp32_sync_table_20M[] = {
15262306a36Sopenharmony_ci	{0x1,  0, 0x19, 0x19, SMPL_40M},  /* 10.0 : 100ns,  50ns */
15362306a36Sopenharmony_ci	{0x2,  0, 0x1a, 0x25, SMPL_20M},  /*  6.7 : 150ns,  50ns */
15462306a36Sopenharmony_ci	{0x3,  1, 0x26, 0x32, SMPL_20M},  /*  5.0 : 200ns, 100ns */
15562306a36Sopenharmony_ci	{0x4,  1, 0x33, 0x3e, SMPL_10M},  /*  4.0 : 250ns, 100ns */
15662306a36Sopenharmony_ci	{0x5,  2, 0x3f, 0x4b, SMPL_10M},  /*  3.3 : 300ns, 150ns */
15762306a36Sopenharmony_ci	{0x6,  2, 0x4c, 0x57, SMPL_10M},  /*  2.8 : 350ns, 150ns */
15862306a36Sopenharmony_ci	{0x7,  3, 0x58, 0x64, SMPL_10M},  /*  2.5 : 400ns, 200ns */
15962306a36Sopenharmony_ci	{0x8,  3, 0x65, 0x70, SMPL_10M},  /*  2.2 : 450ns, 200ns */
16062306a36Sopenharmony_ci	{0x9,  3, 0x71, 0x7d, SMPL_10M},  /*  2.0 : 500ns, 200ns */
16162306a36Sopenharmony_ci};
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic nsp32_sync_table nsp32_sync_table_pci[] = {
16462306a36Sopenharmony_ci	{0x1,  0, 0x0c, 0x0f, SMPL_40M},  /* 16.6 :  60ns,  30ns */
16562306a36Sopenharmony_ci	{0x2,  0, 0x10, 0x16, SMPL_40M},  /* 11.1 :  90ns,  30ns */
16662306a36Sopenharmony_ci	{0x3,  1, 0x17, 0x1e, SMPL_20M},  /*  8.3 : 120ns,  60ns */
16762306a36Sopenharmony_ci	{0x4,  1, 0x1f, 0x25, SMPL_20M},  /*  6.7 : 150ns,  60ns */
16862306a36Sopenharmony_ci	{0x5,  2, 0x26, 0x2d, SMPL_20M},  /*  5.6 : 180ns,  90ns */
16962306a36Sopenharmony_ci	{0x6,  2, 0x2e, 0x34, SMPL_10M},  /*  4.8 : 210ns,  90ns */
17062306a36Sopenharmony_ci	{0x7,  3, 0x35, 0x3c, SMPL_10M},  /*  4.2 : 240ns, 120ns */
17162306a36Sopenharmony_ci	{0x8,  3, 0x3d, 0x43, SMPL_10M},  /*  3.7 : 270ns, 120ns */
17262306a36Sopenharmony_ci	{0x9,  3, 0x44, 0x4b, SMPL_10M},  /*  3.3 : 300ns, 120ns */
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci/*
17662306a36Sopenharmony_ci * function declaration
17762306a36Sopenharmony_ci */
17862306a36Sopenharmony_ci/* module entry point */
17962306a36Sopenharmony_cistatic int nsp32_probe (struct pci_dev *, const struct pci_device_id *);
18062306a36Sopenharmony_cistatic void nsp32_remove(struct pci_dev *);
18162306a36Sopenharmony_cistatic int  __init init_nsp32  (void);
18262306a36Sopenharmony_cistatic void __exit exit_nsp32  (void);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci/* struct struct scsi_host_template */
18562306a36Sopenharmony_cistatic int	   nsp32_show_info   (struct seq_file *, struct Scsi_Host *);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic int	   nsp32_detect      (struct pci_dev *pdev);
18862306a36Sopenharmony_cistatic int	   nsp32_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
18962306a36Sopenharmony_cistatic const char *nsp32_info	     (struct Scsi_Host *);
19062306a36Sopenharmony_cistatic int	   nsp32_release     (struct Scsi_Host *);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/* SCSI error handler */
19362306a36Sopenharmony_cistatic int	   nsp32_eh_abort     (struct scsi_cmnd *);
19462306a36Sopenharmony_cistatic int	   nsp32_eh_host_reset(struct scsi_cmnd *);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci/* generate SCSI message */
19762306a36Sopenharmony_cistatic void nsp32_build_identify(struct scsi_cmnd *);
19862306a36Sopenharmony_cistatic void nsp32_build_nop     (struct scsi_cmnd *);
19962306a36Sopenharmony_cistatic void nsp32_build_reject  (struct scsi_cmnd *);
20062306a36Sopenharmony_cistatic void nsp32_build_sdtr    (struct scsi_cmnd *, unsigned char,
20162306a36Sopenharmony_ci				 unsigned char);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/* SCSI message handler */
20462306a36Sopenharmony_cistatic int  nsp32_busfree_occur(struct scsi_cmnd *, unsigned short);
20562306a36Sopenharmony_cistatic void nsp32_msgout_occur (struct scsi_cmnd *);
20662306a36Sopenharmony_cistatic void nsp32_msgin_occur  (struct scsi_cmnd *, unsigned long,
20762306a36Sopenharmony_ci				unsigned short);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic int  nsp32_setup_sg_table    (struct scsi_cmnd *);
21062306a36Sopenharmony_cistatic int  nsp32_selection_autopara(struct scsi_cmnd *);
21162306a36Sopenharmony_cistatic int  nsp32_selection_autoscsi(struct scsi_cmnd *);
21262306a36Sopenharmony_cistatic void nsp32_scsi_done	    (struct scsi_cmnd *);
21362306a36Sopenharmony_cistatic int  nsp32_arbitration       (struct scsi_cmnd *, unsigned int);
21462306a36Sopenharmony_cistatic int  nsp32_reselection       (struct scsi_cmnd *, unsigned char);
21562306a36Sopenharmony_cistatic void nsp32_adjust_busfree    (struct scsi_cmnd *, unsigned int);
21662306a36Sopenharmony_cistatic void nsp32_restart_autoscsi  (struct scsi_cmnd *, unsigned short);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci/* SCSI SDTR */
21962306a36Sopenharmony_cistatic void nsp32_analyze_sdtr       (struct scsi_cmnd *);
22062306a36Sopenharmony_cistatic int  nsp32_search_period_entry(nsp32_hw_data *, nsp32_target *,
22162306a36Sopenharmony_ci				      unsigned char);
22262306a36Sopenharmony_cistatic void nsp32_set_async	     (nsp32_hw_data *, nsp32_target *);
22362306a36Sopenharmony_cistatic void nsp32_set_max_sync       (nsp32_hw_data *, nsp32_target *,
22462306a36Sopenharmony_ci				      unsigned char *, unsigned char *);
22562306a36Sopenharmony_cistatic void nsp32_set_sync_entry     (nsp32_hw_data *, nsp32_target *,
22662306a36Sopenharmony_ci				      int, unsigned char);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci/* SCSI bus status handler */
22962306a36Sopenharmony_cistatic void nsp32_wait_req    (nsp32_hw_data *, int);
23062306a36Sopenharmony_cistatic void nsp32_wait_sack   (nsp32_hw_data *, int);
23162306a36Sopenharmony_cistatic void nsp32_sack_assert (nsp32_hw_data *);
23262306a36Sopenharmony_cistatic void nsp32_sack_negate (nsp32_hw_data *);
23362306a36Sopenharmony_cistatic void nsp32_do_bus_reset(nsp32_hw_data *);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci/* hardware interrupt handler */
23662306a36Sopenharmony_cistatic irqreturn_t do_nsp32_isr(int, void *);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci/* initialize hardware */
23962306a36Sopenharmony_cistatic int  nsp32hw_init(nsp32_hw_data *);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci/* EEPROM handler */
24262306a36Sopenharmony_cistatic int  nsp32_getprom_param (nsp32_hw_data *);
24362306a36Sopenharmony_cistatic int  nsp32_getprom_at24  (nsp32_hw_data *);
24462306a36Sopenharmony_cistatic int  nsp32_getprom_c16   (nsp32_hw_data *);
24562306a36Sopenharmony_cistatic void nsp32_prom_start    (nsp32_hw_data *);
24662306a36Sopenharmony_cistatic void nsp32_prom_stop     (nsp32_hw_data *);
24762306a36Sopenharmony_cistatic int  nsp32_prom_read     (nsp32_hw_data *, int);
24862306a36Sopenharmony_cistatic int  nsp32_prom_read_bit (nsp32_hw_data *);
24962306a36Sopenharmony_cistatic void nsp32_prom_write_bit(nsp32_hw_data *, int);
25062306a36Sopenharmony_cistatic void nsp32_prom_set      (nsp32_hw_data *, int, int);
25162306a36Sopenharmony_cistatic int  nsp32_prom_get      (nsp32_hw_data *, int);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci/* debug/warning/info message */
25462306a36Sopenharmony_cistatic void nsp32_message (const char *, int, char *, char *, ...);
25562306a36Sopenharmony_ci#ifdef NSP32_DEBUG
25662306a36Sopenharmony_cistatic void nsp32_dmessage(const char *, int, int,    char *, ...);
25762306a36Sopenharmony_ci#endif
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci/*
26062306a36Sopenharmony_ci * max_sectors is currently limited up to 128.
26162306a36Sopenharmony_ci */
26262306a36Sopenharmony_cistatic const struct scsi_host_template nsp32_template = {
26362306a36Sopenharmony_ci	.proc_name			= "nsp32",
26462306a36Sopenharmony_ci	.name				= "Workbit NinjaSCSI-32Bi/UDE",
26562306a36Sopenharmony_ci	.show_info			= nsp32_show_info,
26662306a36Sopenharmony_ci	.info				= nsp32_info,
26762306a36Sopenharmony_ci	.queuecommand			= nsp32_queuecommand,
26862306a36Sopenharmony_ci	.can_queue			= 1,
26962306a36Sopenharmony_ci	.sg_tablesize			= NSP32_SG_SIZE,
27062306a36Sopenharmony_ci	.max_sectors			= 128,
27162306a36Sopenharmony_ci	.this_id			= NSP32_HOST_SCSIID,
27262306a36Sopenharmony_ci	.dma_boundary			= PAGE_SIZE - 1,
27362306a36Sopenharmony_ci	.eh_abort_handler		= nsp32_eh_abort,
27462306a36Sopenharmony_ci	.eh_host_reset_handler		= nsp32_eh_host_reset,
27562306a36Sopenharmony_ci/*	.highmem_io			= 1, */
27662306a36Sopenharmony_ci	.cmd_size			= sizeof(struct nsp32_cmd_priv),
27762306a36Sopenharmony_ci};
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci#include "nsp32_io.h"
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/***********************************************************************
28262306a36Sopenharmony_ci * debug, error print
28362306a36Sopenharmony_ci */
28462306a36Sopenharmony_ci#ifndef NSP32_DEBUG
28562306a36Sopenharmony_ci# define NSP32_DEBUG_MASK	      0x000000
28662306a36Sopenharmony_ci# define nsp32_msg(type, args...)     nsp32_message ("", 0, (type), args)
28762306a36Sopenharmony_ci# define nsp32_dbg(mask, args...)     /* */
28862306a36Sopenharmony_ci#else
28962306a36Sopenharmony_ci# define NSP32_DEBUG_MASK	      0xffffff
29062306a36Sopenharmony_ci# define nsp32_msg(type, args...) \
29162306a36Sopenharmony_ci	nsp32_message (__func__, __LINE__, (type), args)
29262306a36Sopenharmony_ci# define nsp32_dbg(mask, args...) \
29362306a36Sopenharmony_ci	nsp32_dmessage(__func__, __LINE__, (mask), args)
29462306a36Sopenharmony_ci#endif
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci#define NSP32_DEBUG_QUEUECOMMAND	BIT(0)
29762306a36Sopenharmony_ci#define NSP32_DEBUG_REGISTER		BIT(1)
29862306a36Sopenharmony_ci#define NSP32_DEBUG_AUTOSCSI		BIT(2)
29962306a36Sopenharmony_ci#define NSP32_DEBUG_INTR		BIT(3)
30062306a36Sopenharmony_ci#define NSP32_DEBUG_SGLIST		BIT(4)
30162306a36Sopenharmony_ci#define NSP32_DEBUG_BUSFREE		BIT(5)
30262306a36Sopenharmony_ci#define NSP32_DEBUG_CDB_CONTENTS	BIT(6)
30362306a36Sopenharmony_ci#define NSP32_DEBUG_RESELECTION		BIT(7)
30462306a36Sopenharmony_ci#define NSP32_DEBUG_MSGINOCCUR		BIT(8)
30562306a36Sopenharmony_ci#define NSP32_DEBUG_EEPROM		BIT(9)
30662306a36Sopenharmony_ci#define NSP32_DEBUG_MSGOUTOCCUR		BIT(10)
30762306a36Sopenharmony_ci#define NSP32_DEBUG_BUSRESET		BIT(11)
30862306a36Sopenharmony_ci#define NSP32_DEBUG_RESTART		BIT(12)
30962306a36Sopenharmony_ci#define NSP32_DEBUG_SYNC		BIT(13)
31062306a36Sopenharmony_ci#define NSP32_DEBUG_WAIT		BIT(14)
31162306a36Sopenharmony_ci#define NSP32_DEBUG_TARGETFLAG		BIT(15)
31262306a36Sopenharmony_ci#define NSP32_DEBUG_PROC		BIT(16)
31362306a36Sopenharmony_ci#define NSP32_DEBUG_INIT		BIT(17)
31462306a36Sopenharmony_ci#define NSP32_SPECIAL_PRINT_REGISTER	BIT(20)
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci#define NSP32_DEBUG_BUF_LEN		100
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci__printf(4, 5)
31962306a36Sopenharmony_cistatic void nsp32_message(const char *func, int line, char *type, char *fmt, ...)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	va_list args;
32262306a36Sopenharmony_ci	char buf[NSP32_DEBUG_BUF_LEN];
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	va_start(args, fmt);
32562306a36Sopenharmony_ci	vsnprintf(buf, sizeof(buf), fmt, args);
32662306a36Sopenharmony_ci	va_end(args);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci#ifndef NSP32_DEBUG
32962306a36Sopenharmony_ci	printk("%snsp32: %s\n", type, buf);
33062306a36Sopenharmony_ci#else
33162306a36Sopenharmony_ci	printk("%snsp32: %s (%d): %s\n", type, func, line, buf);
33262306a36Sopenharmony_ci#endif
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci#ifdef NSP32_DEBUG
33662306a36Sopenharmony_cistatic void nsp32_dmessage(const char *func, int line, int mask, char *fmt, ...)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	va_list args;
33962306a36Sopenharmony_ci	char buf[NSP32_DEBUG_BUF_LEN];
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	va_start(args, fmt);
34262306a36Sopenharmony_ci	vsnprintf(buf, sizeof(buf), fmt, args);
34362306a36Sopenharmony_ci	va_end(args);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (mask & NSP32_DEBUG_MASK) {
34662306a36Sopenharmony_ci		printk("nsp32-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci#endif
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci#ifdef NSP32_DEBUG
35262306a36Sopenharmony_ci# include "nsp32_debug.c"
35362306a36Sopenharmony_ci#else
35462306a36Sopenharmony_ci# define show_command(arg)   /* */
35562306a36Sopenharmony_ci# define show_busphase(arg)  /* */
35662306a36Sopenharmony_ci# define show_autophase(arg) /* */
35762306a36Sopenharmony_ci#endif
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci/*
36062306a36Sopenharmony_ci * IDENTIFY Message
36162306a36Sopenharmony_ci */
36262306a36Sopenharmony_cistatic void nsp32_build_identify(struct scsi_cmnd *SCpnt)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
36562306a36Sopenharmony_ci	int pos		    = data->msgout_len;
36662306a36Sopenharmony_ci	int mode	    = FALSE;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	/* XXX: Auto DiscPriv detection is progressing... */
36962306a36Sopenharmony_ci	if (disc_priv == 0) {
37062306a36Sopenharmony_ci		/* mode = TRUE; */
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	data->msgoutbuf[pos] = IDENTIFY(mode, SCpnt->device->lun); pos++;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	data->msgout_len = pos;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci/*
37962306a36Sopenharmony_ci * SDTR Message Routine
38062306a36Sopenharmony_ci */
38162306a36Sopenharmony_cistatic void nsp32_build_sdtr(struct scsi_cmnd    *SCpnt,
38262306a36Sopenharmony_ci			     unsigned char period,
38362306a36Sopenharmony_ci			     unsigned char offset)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
38662306a36Sopenharmony_ci	int pos = data->msgout_len;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	data->msgoutbuf[pos] = EXTENDED_MESSAGE;  pos++;
38962306a36Sopenharmony_ci	data->msgoutbuf[pos] = EXTENDED_SDTR_LEN; pos++;
39062306a36Sopenharmony_ci	data->msgoutbuf[pos] = EXTENDED_SDTR;     pos++;
39162306a36Sopenharmony_ci	data->msgoutbuf[pos] = period;		  pos++;
39262306a36Sopenharmony_ci	data->msgoutbuf[pos] = offset;		  pos++;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	data->msgout_len = pos;
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci/*
39862306a36Sopenharmony_ci * No Operation Message
39962306a36Sopenharmony_ci */
40062306a36Sopenharmony_cistatic void nsp32_build_nop(struct scsi_cmnd *SCpnt)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
40362306a36Sopenharmony_ci	int pos  = data->msgout_len;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (pos != 0) {
40662306a36Sopenharmony_ci		nsp32_msg(KERN_WARNING,
40762306a36Sopenharmony_ci			  "Some messages are already contained!");
40862306a36Sopenharmony_ci		return;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	data->msgoutbuf[pos] = NOP; pos++;
41262306a36Sopenharmony_ci	data->msgout_len = pos;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/*
41662306a36Sopenharmony_ci * Reject Message
41762306a36Sopenharmony_ci */
41862306a36Sopenharmony_cistatic void nsp32_build_reject(struct scsi_cmnd *SCpnt)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
42162306a36Sopenharmony_ci	int pos  = data->msgout_len;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	data->msgoutbuf[pos] = MESSAGE_REJECT; pos++;
42462306a36Sopenharmony_ci	data->msgout_len = pos;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/*
42862306a36Sopenharmony_ci * timer
42962306a36Sopenharmony_ci */
43062306a36Sopenharmony_ci#if 0
43162306a36Sopenharmony_cistatic void nsp32_start_timer(struct scsi_cmnd *SCpnt, int time)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	unsigned int base = SCpnt->host->io_port;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_INTR, "timer=%d", time);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	if (time & (~TIMER_CNT_MASK)) {
43862306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INTR, "timer set overflow");
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	nsp32_write2(base, TIMER_SET, time & TIMER_CNT_MASK);
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci#endif
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci/*
44762306a36Sopenharmony_ci * set SCSI command and other parameter to asic, and start selection phase
44862306a36Sopenharmony_ci */
44962306a36Sopenharmony_cistatic int nsp32_selection_autopara(struct scsi_cmnd *SCpnt)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	nsp32_hw_data  *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
45262306a36Sopenharmony_ci	unsigned int	base    = SCpnt->device->host->io_port;
45362306a36Sopenharmony_ci	unsigned int	host_id = SCpnt->device->host->this_id;
45462306a36Sopenharmony_ci	unsigned char	target  = scmd_id(SCpnt);
45562306a36Sopenharmony_ci	nsp32_autoparam *param  = data->autoparam;
45662306a36Sopenharmony_ci	unsigned char	phase;
45762306a36Sopenharmony_ci	int		i, ret;
45862306a36Sopenharmony_ci	unsigned int	msgout;
45962306a36Sopenharmony_ci	u16_le		s;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in");
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	/*
46462306a36Sopenharmony_ci	 * check bus free
46562306a36Sopenharmony_ci	 */
46662306a36Sopenharmony_ci	phase = nsp32_read1(base, SCSI_BUS_MONITOR);
46762306a36Sopenharmony_ci	if (phase != BUSMON_BUS_FREE) {
46862306a36Sopenharmony_ci		nsp32_msg(KERN_WARNING, "bus busy");
46962306a36Sopenharmony_ci		show_busphase(phase & BUSMON_PHASE_MASK);
47062306a36Sopenharmony_ci		SCpnt->result = DID_BUS_BUSY << 16;
47162306a36Sopenharmony_ci		return FALSE;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	/*
47562306a36Sopenharmony_ci	 * message out
47662306a36Sopenharmony_ci	 *
47762306a36Sopenharmony_ci	 * Note: If the range of msgout_len is 1 - 3, fill scsi_msgout.
47862306a36Sopenharmony_ci	 *       over 3 messages needs another routine.
47962306a36Sopenharmony_ci	 */
48062306a36Sopenharmony_ci	if (data->msgout_len == 0) {
48162306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!");
48262306a36Sopenharmony_ci		SCpnt->result = DID_ERROR << 16;
48362306a36Sopenharmony_ci		return FALSE;
48462306a36Sopenharmony_ci	} else if (data->msgout_len > 0 && data->msgout_len <= 3) {
48562306a36Sopenharmony_ci		msgout = 0;
48662306a36Sopenharmony_ci		for (i = 0; i < data->msgout_len; i++) {
48762306a36Sopenharmony_ci			/*
48862306a36Sopenharmony_ci			 * the sending order of the message is:
48962306a36Sopenharmony_ci			 *  MCNT 3: MSG#0 -> MSG#1 -> MSG#2
49062306a36Sopenharmony_ci			 *  MCNT 2:          MSG#1 -> MSG#2
49162306a36Sopenharmony_ci			 *  MCNT 1:                   MSG#2
49262306a36Sopenharmony_ci			 */
49362306a36Sopenharmony_ci			msgout >>= 8;
49462306a36Sopenharmony_ci			msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24);
49562306a36Sopenharmony_ci		}
49662306a36Sopenharmony_ci		msgout |= MV_VALID;	/* MV valid */
49762306a36Sopenharmony_ci		msgout |= (unsigned int)data->msgout_len; /* len */
49862306a36Sopenharmony_ci	} else {
49962306a36Sopenharmony_ci		/* data->msgout_len > 3 */
50062306a36Sopenharmony_ci		msgout = 0;
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	// nsp_dbg(NSP32_DEBUG_AUTOSCSI, "sel time out=0x%x\n",
50462306a36Sopenharmony_ci	// nsp32_read2(base, SEL_TIME_OUT));
50562306a36Sopenharmony_ci	// nsp32_write2(base, SEL_TIME_OUT,   SEL_TIMEOUT_TIME);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	/*
50862306a36Sopenharmony_ci	 * setup asic parameter
50962306a36Sopenharmony_ci	 */
51062306a36Sopenharmony_ci	memset(param, 0, sizeof(nsp32_autoparam));
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/* cdb */
51362306a36Sopenharmony_ci	for (i = 0; i < SCpnt->cmd_len; i++) {
51462306a36Sopenharmony_ci		param->cdb[4 * i] = SCpnt->cmnd[i];
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	/* outgoing messages */
51862306a36Sopenharmony_ci	param->msgout = cpu_to_le32(msgout);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	/* syncreg, ackwidth, target id, SREQ sampling rate */
52162306a36Sopenharmony_ci	param->syncreg    = data->cur_target->syncreg;
52262306a36Sopenharmony_ci	param->ackwidth   = data->cur_target->ackwidth;
52362306a36Sopenharmony_ci	param->target_id  = BIT(host_id) | BIT(target);
52462306a36Sopenharmony_ci	param->sample_reg = data->cur_target->sample_reg;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	// nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "sample rate=0x%x\n", data->cur_target->sample_reg);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	/* command control */
52962306a36Sopenharmony_ci	param->command_control = cpu_to_le16(CLEAR_CDB_FIFO_POINTER |
53062306a36Sopenharmony_ci					     AUTOSCSI_START |
53162306a36Sopenharmony_ci					     AUTO_MSGIN_00_OR_04 |
53262306a36Sopenharmony_ci					     AUTO_MSGIN_02 |
53362306a36Sopenharmony_ci					     AUTO_ATN );
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* transfer control */
53762306a36Sopenharmony_ci	s = 0;
53862306a36Sopenharmony_ci	switch (data->trans_method) {
53962306a36Sopenharmony_ci	case NSP32_TRANSFER_BUSMASTER:
54062306a36Sopenharmony_ci		s |= BM_START;
54162306a36Sopenharmony_ci		break;
54262306a36Sopenharmony_ci	case NSP32_TRANSFER_MMIO:
54362306a36Sopenharmony_ci		s |= CB_MMIO_MODE;
54462306a36Sopenharmony_ci		break;
54562306a36Sopenharmony_ci	case NSP32_TRANSFER_PIO:
54662306a36Sopenharmony_ci		s |= CB_IO_MODE;
54762306a36Sopenharmony_ci		break;
54862306a36Sopenharmony_ci	default:
54962306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "unknown trans_method");
55062306a36Sopenharmony_ci		break;
55162306a36Sopenharmony_ci	}
55262306a36Sopenharmony_ci	/*
55362306a36Sopenharmony_ci	 * OR-ed BLIEND_MODE, FIFO intr is decreased, instead of PCI bus waits.
55462306a36Sopenharmony_ci	 * For bus master transfer, it's taken off.
55562306a36Sopenharmony_ci	 */
55662306a36Sopenharmony_ci	s |= (TRANSFER_GO | ALL_COUNTER_CLR);
55762306a36Sopenharmony_ci	param->transfer_control = cpu_to_le16(s);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/* sg table addr */
56062306a36Sopenharmony_ci	param->sgt_pointer = cpu_to_le32(data->cur_lunt->sglun_paddr);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	/*
56362306a36Sopenharmony_ci	 * transfer parameter to ASIC
56462306a36Sopenharmony_ci	 */
56562306a36Sopenharmony_ci	nsp32_write4(base, SGT_ADR, data->auto_paddr);
56662306a36Sopenharmony_ci	nsp32_write2(base, COMMAND_CONTROL,
56762306a36Sopenharmony_ci		     CLEAR_CDB_FIFO_POINTER | AUTO_PARAMETER );
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	/*
57062306a36Sopenharmony_ci	 * Check arbitration
57162306a36Sopenharmony_ci	 */
57262306a36Sopenharmony_ci	ret = nsp32_arbitration(SCpnt, base);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	return ret;
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci/*
57962306a36Sopenharmony_ci * Selection with AUTO SCSI (without AUTO PARAMETER)
58062306a36Sopenharmony_ci */
58162306a36Sopenharmony_cistatic int nsp32_selection_autoscsi(struct scsi_cmnd *SCpnt)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	nsp32_hw_data  *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
58462306a36Sopenharmony_ci	unsigned int	base    = SCpnt->device->host->io_port;
58562306a36Sopenharmony_ci	unsigned int	host_id = SCpnt->device->host->this_id;
58662306a36Sopenharmony_ci	unsigned char	target  = scmd_id(SCpnt);
58762306a36Sopenharmony_ci	unsigned char	phase;
58862306a36Sopenharmony_ci	int		status;
58962306a36Sopenharmony_ci	unsigned short	command	= 0;
59062306a36Sopenharmony_ci	unsigned int	msgout  = 0;
59162306a36Sopenharmony_ci	int		i;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in");
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	/*
59662306a36Sopenharmony_ci	 * IRQ disable
59762306a36Sopenharmony_ci	 */
59862306a36Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	/*
60162306a36Sopenharmony_ci	 * check bus line
60262306a36Sopenharmony_ci	 */
60362306a36Sopenharmony_ci	phase = nsp32_read1(base, SCSI_BUS_MONITOR);
60462306a36Sopenharmony_ci	if ((phase & BUSMON_BSY) || (phase & BUSMON_SEL)) {
60562306a36Sopenharmony_ci		nsp32_msg(KERN_WARNING, "bus busy");
60662306a36Sopenharmony_ci		SCpnt->result = DID_BUS_BUSY << 16;
60762306a36Sopenharmony_ci		status = 1;
60862306a36Sopenharmony_ci		goto out;
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	/*
61262306a36Sopenharmony_ci	 * clear execph
61362306a36Sopenharmony_ci	 */
61462306a36Sopenharmony_ci	nsp32_read2(base, SCSI_EXECUTE_PHASE);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/*
61762306a36Sopenharmony_ci	 * clear FIFO counter to set CDBs
61862306a36Sopenharmony_ci	 */
61962306a36Sopenharmony_ci	nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/*
62262306a36Sopenharmony_ci	 * set CDB0 - CDB15
62362306a36Sopenharmony_ci	 */
62462306a36Sopenharmony_ci	for (i = 0; i < SCpnt->cmd_len; i++) {
62562306a36Sopenharmony_ci		nsp32_write1(base, COMMAND_DATA, SCpnt->cmnd[i]);
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_CDB_CONTENTS, "CDB[0]=[0x%x]", SCpnt->cmnd[0]);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	/*
63062306a36Sopenharmony_ci	 * set SCSIOUT LATCH(initiator)/TARGET(target) (OR-ed) ID
63162306a36Sopenharmony_ci	 */
63262306a36Sopenharmony_ci	nsp32_write1(base, SCSI_OUT_LATCH_TARGET_ID,
63362306a36Sopenharmony_ci		     BIT(host_id) | BIT(target));
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	/*
63662306a36Sopenharmony_ci	 * set SCSI MSGOUT REG
63762306a36Sopenharmony_ci	 *
63862306a36Sopenharmony_ci	 * Note: If the range of msgout_len is 1 - 3, fill scsi_msgout.
63962306a36Sopenharmony_ci	 *       over 3 messages needs another routine.
64062306a36Sopenharmony_ci	 */
64162306a36Sopenharmony_ci	if (data->msgout_len == 0) {
64262306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!");
64362306a36Sopenharmony_ci		SCpnt->result = DID_ERROR << 16;
64462306a36Sopenharmony_ci		status = 1;
64562306a36Sopenharmony_ci		goto out;
64662306a36Sopenharmony_ci	} else if (data->msgout_len > 0 && data->msgout_len <= 3) {
64762306a36Sopenharmony_ci		msgout = 0;
64862306a36Sopenharmony_ci		for (i = 0; i < data->msgout_len; i++) {
64962306a36Sopenharmony_ci			/*
65062306a36Sopenharmony_ci			 * the sending order of the message is:
65162306a36Sopenharmony_ci			 *  MCNT 3: MSG#0 -> MSG#1 -> MSG#2
65262306a36Sopenharmony_ci			 *  MCNT 2:          MSG#1 -> MSG#2
65362306a36Sopenharmony_ci			 *  MCNT 1:                   MSG#2
65462306a36Sopenharmony_ci			 */
65562306a36Sopenharmony_ci			msgout >>= 8;
65662306a36Sopenharmony_ci			msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24);
65762306a36Sopenharmony_ci		}
65862306a36Sopenharmony_ci		msgout |= MV_VALID;	/* MV valid */
65962306a36Sopenharmony_ci		msgout |= (unsigned int)data->msgout_len; /* len */
66062306a36Sopenharmony_ci		nsp32_write4(base, SCSI_MSG_OUT, msgout);
66162306a36Sopenharmony_ci	} else {
66262306a36Sopenharmony_ci		/* data->msgout_len > 3 */
66362306a36Sopenharmony_ci		nsp32_write4(base, SCSI_MSG_OUT, 0);
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	/*
66762306a36Sopenharmony_ci	 * set selection timeout(= 250ms)
66862306a36Sopenharmony_ci	 */
66962306a36Sopenharmony_ci	nsp32_write2(base, SEL_TIME_OUT,   SEL_TIMEOUT_TIME);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	/*
67262306a36Sopenharmony_ci	 * set SREQ hazard killer sampling rate
67362306a36Sopenharmony_ci	 *
67462306a36Sopenharmony_ci	 * TODO: sample_rate (BASE+0F) is 0 when internal clock = 40MHz.
67562306a36Sopenharmony_ci	 *      check other internal clock!
67662306a36Sopenharmony_ci	 */
67762306a36Sopenharmony_ci	nsp32_write1(base, SREQ_SMPL_RATE, data->cur_target->sample_reg);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	/*
68062306a36Sopenharmony_ci	 * clear Arbit
68162306a36Sopenharmony_ci	 */
68262306a36Sopenharmony_ci	nsp32_write1(base, SET_ARBIT,      ARBIT_CLEAR);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/*
68562306a36Sopenharmony_ci	 * set SYNCREG
68662306a36Sopenharmony_ci	 * Don't set BM_START_ADR before setting this register.
68762306a36Sopenharmony_ci	 */
68862306a36Sopenharmony_ci	nsp32_write1(base, SYNC_REG,  data->cur_target->syncreg);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	/*
69162306a36Sopenharmony_ci	 * set ACKWIDTH
69262306a36Sopenharmony_ci	 */
69362306a36Sopenharmony_ci	nsp32_write1(base, ACK_WIDTH, data->cur_target->ackwidth);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_AUTOSCSI,
69662306a36Sopenharmony_ci		  "syncreg=0x%x, ackwidth=0x%x, sgtpaddr=0x%x, id=0x%x",
69762306a36Sopenharmony_ci		  nsp32_read1(base, SYNC_REG), nsp32_read1(base, ACK_WIDTH),
69862306a36Sopenharmony_ci		  nsp32_read4(base, SGT_ADR),
69962306a36Sopenharmony_ci		  nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID));
70062306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "msgout_len=%d, msgout=0x%x",
70162306a36Sopenharmony_ci		  data->msgout_len, msgout);
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	/*
70462306a36Sopenharmony_ci	 * set SGT ADDR (physical address)
70562306a36Sopenharmony_ci	 */
70662306a36Sopenharmony_ci	nsp32_write4(base, SGT_ADR, data->cur_lunt->sglun_paddr);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/*
70962306a36Sopenharmony_ci	 * set TRANSFER CONTROL REG
71062306a36Sopenharmony_ci	 */
71162306a36Sopenharmony_ci	command = 0;
71262306a36Sopenharmony_ci	command |= (TRANSFER_GO | ALL_COUNTER_CLR);
71362306a36Sopenharmony_ci	if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
71462306a36Sopenharmony_ci		if (scsi_bufflen(SCpnt) > 0) {
71562306a36Sopenharmony_ci			command |= BM_START;
71662306a36Sopenharmony_ci		}
71762306a36Sopenharmony_ci	} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
71862306a36Sopenharmony_ci		command |= CB_MMIO_MODE;
71962306a36Sopenharmony_ci	} else if (data->trans_method & NSP32_TRANSFER_PIO) {
72062306a36Sopenharmony_ci		command |= CB_IO_MODE;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL, command);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/*
72562306a36Sopenharmony_ci	 * start AUTO SCSI, kick off arbitration
72662306a36Sopenharmony_ci	 */
72762306a36Sopenharmony_ci	command = (CLEAR_CDB_FIFO_POINTER |
72862306a36Sopenharmony_ci		   AUTOSCSI_START	  |
72962306a36Sopenharmony_ci		   AUTO_MSGIN_00_OR_04    |
73062306a36Sopenharmony_ci		   AUTO_MSGIN_02	  |
73162306a36Sopenharmony_ci		   AUTO_ATN);
73262306a36Sopenharmony_ci	nsp32_write2(base, COMMAND_CONTROL, command);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	/*
73562306a36Sopenharmony_ci	 * Check arbitration
73662306a36Sopenharmony_ci	 */
73762306a36Sopenharmony_ci	status = nsp32_arbitration(SCpnt, base);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci out:
74062306a36Sopenharmony_ci	/*
74162306a36Sopenharmony_ci	 * IRQ enable
74262306a36Sopenharmony_ci	 */
74362306a36Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, 0);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	return status;
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci/*
75062306a36Sopenharmony_ci * Arbitration Status Check
75162306a36Sopenharmony_ci *
75262306a36Sopenharmony_ci * Note: Arbitration counter is waited during ARBIT_GO is not lifting.
75362306a36Sopenharmony_ci *	 Using udelay(1) consumes CPU time and system time, but
75462306a36Sopenharmony_ci *	 arbitration delay time is defined minimal 2.4us in SCSI
75562306a36Sopenharmony_ci *	 specification, thus udelay works as coarse grained wait timer.
75662306a36Sopenharmony_ci */
75762306a36Sopenharmony_cistatic int nsp32_arbitration(struct scsi_cmnd *SCpnt, unsigned int base)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	unsigned char arbit;
76062306a36Sopenharmony_ci	int	      status = TRUE;
76162306a36Sopenharmony_ci	int	      time   = 0;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	do {
76462306a36Sopenharmony_ci		arbit = nsp32_read1(base, ARBIT_STATUS);
76562306a36Sopenharmony_ci		time++;
76662306a36Sopenharmony_ci	} while ((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
76762306a36Sopenharmony_ci		 (time <= ARBIT_TIMEOUT_TIME));
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_AUTOSCSI,
77062306a36Sopenharmony_ci		  "arbit: 0x%x, delay time: %d", arbit, time);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	if (arbit & ARBIT_WIN) {
77362306a36Sopenharmony_ci		/* Arbitration succeeded */
77462306a36Sopenharmony_ci		SCpnt->result = DID_OK << 16;
77562306a36Sopenharmony_ci		nsp32_index_write1(base, EXT_PORT, LED_ON); /* PCI LED on */
77662306a36Sopenharmony_ci	} else if (arbit & ARBIT_FAIL) {
77762306a36Sopenharmony_ci		/* Arbitration failed */
77862306a36Sopenharmony_ci		SCpnt->result = DID_BUS_BUSY << 16;
77962306a36Sopenharmony_ci		status = FALSE;
78062306a36Sopenharmony_ci	} else {
78162306a36Sopenharmony_ci		/*
78262306a36Sopenharmony_ci		 * unknown error or ARBIT_GO timeout,
78362306a36Sopenharmony_ci		 * something lock up! guess no connection.
78462306a36Sopenharmony_ci		 */
78562306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit timeout");
78662306a36Sopenharmony_ci		SCpnt->result = DID_NO_CONNECT << 16;
78762306a36Sopenharmony_ci		status = FALSE;
78862306a36Sopenharmony_ci	}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	/*
79162306a36Sopenharmony_ci	 * clear Arbit
79262306a36Sopenharmony_ci	 */
79362306a36Sopenharmony_ci	nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	return status;
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci/*
80062306a36Sopenharmony_ci * reselection
80162306a36Sopenharmony_ci *
80262306a36Sopenharmony_ci * Note: This reselection routine is called from msgin_occur,
80362306a36Sopenharmony_ci *	 reselection target id&lun must be already set.
80462306a36Sopenharmony_ci *	 SCSI-2 says IDENTIFY implies RESTORE_POINTER operation.
80562306a36Sopenharmony_ci */
80662306a36Sopenharmony_cistatic int nsp32_reselection(struct scsi_cmnd *SCpnt, unsigned char newlun)
80762306a36Sopenharmony_ci{
80862306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
80962306a36Sopenharmony_ci	unsigned int   host_id = SCpnt->device->host->this_id;
81062306a36Sopenharmony_ci	unsigned int   base    = SCpnt->device->host->io_port;
81162306a36Sopenharmony_ci	unsigned char  tmpid, newid;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_RESELECTION, "enter");
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	/*
81662306a36Sopenharmony_ci	 * calculate reselected SCSI ID
81762306a36Sopenharmony_ci	 */
81862306a36Sopenharmony_ci	tmpid = nsp32_read1(base, RESELECT_ID);
81962306a36Sopenharmony_ci	tmpid &= (~BIT(host_id));
82062306a36Sopenharmony_ci	newid = 0;
82162306a36Sopenharmony_ci	while (tmpid) {
82262306a36Sopenharmony_ci		if (tmpid & 1) {
82362306a36Sopenharmony_ci			break;
82462306a36Sopenharmony_ci		}
82562306a36Sopenharmony_ci		tmpid >>= 1;
82662306a36Sopenharmony_ci		newid++;
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	/*
83062306a36Sopenharmony_ci	 * If reselected New ID:LUN is not existed
83162306a36Sopenharmony_ci	 * or current nexus is not existed, unexpected
83262306a36Sopenharmony_ci	 * reselection is occurred. Send reject message.
83362306a36Sopenharmony_ci	 */
83462306a36Sopenharmony_ci	if (newid >= ARRAY_SIZE(data->lunt) ||
83562306a36Sopenharmony_ci	    newlun >= ARRAY_SIZE(data->lunt[0])) {
83662306a36Sopenharmony_ci		nsp32_msg(KERN_WARNING, "unknown id/lun");
83762306a36Sopenharmony_ci		return FALSE;
83862306a36Sopenharmony_ci	} else if(data->lunt[newid][newlun].SCpnt == NULL) {
83962306a36Sopenharmony_ci		nsp32_msg(KERN_WARNING, "no SCSI command is processing");
84062306a36Sopenharmony_ci		return FALSE;
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	data->cur_id    = newid;
84462306a36Sopenharmony_ci	data->cur_lun   = newlun;
84562306a36Sopenharmony_ci	data->cur_target = &(data->target[newid]);
84662306a36Sopenharmony_ci	data->cur_lunt   = &(data->lunt[newid][newlun]);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	/* reset SACK/SavedACK counter (or ALL clear?) */
84962306a36Sopenharmony_ci	nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	return TRUE;
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci/*
85662306a36Sopenharmony_ci * nsp32_setup_sg_table - build scatter gather list for transfer data
85762306a36Sopenharmony_ci *			    with bus master.
85862306a36Sopenharmony_ci *
85962306a36Sopenharmony_ci * Note: NinjaSCSI-32Bi/UDE bus master can not transfer over 64KB at a time.
86062306a36Sopenharmony_ci */
86162306a36Sopenharmony_cistatic int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
86462306a36Sopenharmony_ci	struct scatterlist *sg;
86562306a36Sopenharmony_ci	nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt;
86662306a36Sopenharmony_ci	int num, i;
86762306a36Sopenharmony_ci	u32_le l;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	if (sgt == NULL) {
87062306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_SGLIST, "SGT == null");
87162306a36Sopenharmony_ci		return FALSE;
87262306a36Sopenharmony_ci	}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	num = scsi_dma_map(SCpnt);
87562306a36Sopenharmony_ci	if (!num)
87662306a36Sopenharmony_ci		return TRUE;
87762306a36Sopenharmony_ci	else if (num < 0)
87862306a36Sopenharmony_ci		return FALSE;
87962306a36Sopenharmony_ci	else {
88062306a36Sopenharmony_ci		scsi_for_each_sg(SCpnt, sg, num, i) {
88162306a36Sopenharmony_ci			/*
88262306a36Sopenharmony_ci			 * Build nsp32_sglist, substitute sg dma addresses.
88362306a36Sopenharmony_ci			 */
88462306a36Sopenharmony_ci			sgt[i].addr = cpu_to_le32(sg_dma_address(sg));
88562306a36Sopenharmony_ci			sgt[i].len  = cpu_to_le32(sg_dma_len(sg));
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci			if (le32_to_cpu(sgt[i].len) > 0x10000) {
88862306a36Sopenharmony_ci				nsp32_msg(KERN_ERR,
88962306a36Sopenharmony_ci					"can't transfer over 64KB at a time, "
89062306a36Sopenharmony_ci					"size=0x%x", le32_to_cpu(sgt[i].len));
89162306a36Sopenharmony_ci				return FALSE;
89262306a36Sopenharmony_ci			}
89362306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_SGLIST,
89462306a36Sopenharmony_ci				  "num 0x%x : addr 0x%lx len 0x%lx",
89562306a36Sopenharmony_ci				  i,
89662306a36Sopenharmony_ci				  le32_to_cpu(sgt[i].addr),
89762306a36Sopenharmony_ci				  le32_to_cpu(sgt[i].len ));
89862306a36Sopenharmony_ci		}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci		/* set end mark */
90162306a36Sopenharmony_ci		l = le32_to_cpu(sgt[num-1].len);
90262306a36Sopenharmony_ci		sgt[num-1].len = cpu_to_le32(l | SGTEND);
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	return TRUE;
90662306a36Sopenharmony_ci}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_cistatic int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	void (*done)(struct scsi_cmnd *) = scsi_done;
91162306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
91262306a36Sopenharmony_ci	nsp32_target *target;
91362306a36Sopenharmony_ci	nsp32_lunt   *cur_lunt;
91462306a36Sopenharmony_ci	int ret;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
91762306a36Sopenharmony_ci		  "enter. target: 0x%x LUN: 0x%llx cmnd: 0x%x cmndlen: 0x%x "
91862306a36Sopenharmony_ci		  "use_sg: 0x%x reqbuf: 0x%lx reqlen: 0x%x",
91962306a36Sopenharmony_ci		  SCpnt->device->id, SCpnt->device->lun, SCpnt->cmnd[0],
92062306a36Sopenharmony_ci		  SCpnt->cmd_len, scsi_sg_count(SCpnt), scsi_sglist(SCpnt),
92162306a36Sopenharmony_ci		  scsi_bufflen(SCpnt));
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (data->CurrentSC != NULL) {
92462306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "Currentsc != NULL. Cancel this command request");
92562306a36Sopenharmony_ci		data->CurrentSC = NULL;
92662306a36Sopenharmony_ci		SCpnt->result   = DID_NO_CONNECT << 16;
92762306a36Sopenharmony_ci		done(SCpnt);
92862306a36Sopenharmony_ci		return 0;
92962306a36Sopenharmony_ci	}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	/* check target ID is not same as this initiator ID */
93262306a36Sopenharmony_ci	if (scmd_id(SCpnt) == SCpnt->device->host->this_id) {
93362306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "target==host???");
93462306a36Sopenharmony_ci		SCpnt->result = DID_BAD_TARGET << 16;
93562306a36Sopenharmony_ci		done(SCpnt);
93662306a36Sopenharmony_ci		return 0;
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	/* check target LUN is allowable value */
94062306a36Sopenharmony_ci	if (SCpnt->device->lun >= MAX_LUN) {
94162306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "no more lun");
94262306a36Sopenharmony_ci		SCpnt->result = DID_BAD_TARGET << 16;
94362306a36Sopenharmony_ci		done(SCpnt);
94462306a36Sopenharmony_ci		return 0;
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	show_command(SCpnt);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	data->CurrentSC      = SCpnt;
95062306a36Sopenharmony_ci	nsp32_priv(SCpnt)->status = SAM_STAT_CHECK_CONDITION;
95162306a36Sopenharmony_ci	scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	/* initialize data */
95462306a36Sopenharmony_ci	data->msgout_len	= 0;
95562306a36Sopenharmony_ci	data->msgin_len		= 0;
95662306a36Sopenharmony_ci	cur_lunt		= &(data->lunt[SCpnt->device->id][SCpnt->device->lun]);
95762306a36Sopenharmony_ci	cur_lunt->SCpnt		= SCpnt;
95862306a36Sopenharmony_ci	cur_lunt->save_datp	= 0;
95962306a36Sopenharmony_ci	cur_lunt->msgin03	= FALSE;
96062306a36Sopenharmony_ci	data->cur_lunt		= cur_lunt;
96162306a36Sopenharmony_ci	data->cur_id		= SCpnt->device->id;
96262306a36Sopenharmony_ci	data->cur_lun		= SCpnt->device->lun;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	ret = nsp32_setup_sg_table(SCpnt);
96562306a36Sopenharmony_ci	if (ret == FALSE) {
96662306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "SGT fail");
96762306a36Sopenharmony_ci		SCpnt->result = DID_ERROR << 16;
96862306a36Sopenharmony_ci		nsp32_scsi_done(SCpnt);
96962306a36Sopenharmony_ci		return 0;
97062306a36Sopenharmony_ci	}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	/* Build IDENTIFY */
97362306a36Sopenharmony_ci	nsp32_build_identify(SCpnt);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	/*
97662306a36Sopenharmony_ci	 * If target is the first time to transfer after the reset
97762306a36Sopenharmony_ci	 * (target don't have SDTR_DONE and SDTR_INITIATOR), sync
97862306a36Sopenharmony_ci	 * message SDTR is needed to do synchronous transfer.
97962306a36Sopenharmony_ci	 */
98062306a36Sopenharmony_ci	target = &data->target[scmd_id(SCpnt)];
98162306a36Sopenharmony_ci	data->cur_target = target;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	if (!(target->sync_flag & (SDTR_DONE | SDTR_INITIATOR | SDTR_TARGET))) {
98462306a36Sopenharmony_ci		unsigned char period, offset;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci		if (trans_mode != ASYNC_MODE) {
98762306a36Sopenharmony_ci			nsp32_set_max_sync(data, target, &period, &offset);
98862306a36Sopenharmony_ci			nsp32_build_sdtr(SCpnt, period, offset);
98962306a36Sopenharmony_ci			target->sync_flag |= SDTR_INITIATOR;
99062306a36Sopenharmony_ci		} else {
99162306a36Sopenharmony_ci			nsp32_set_async(data, target);
99262306a36Sopenharmony_ci			target->sync_flag |= SDTR_DONE;
99362306a36Sopenharmony_ci		}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
99662306a36Sopenharmony_ci			  "SDTR: entry: %d start_period: 0x%x offset: 0x%x\n",
99762306a36Sopenharmony_ci			  target->limit_entry, period, offset);
99862306a36Sopenharmony_ci	} else if (target->sync_flag & SDTR_INITIATOR) {
99962306a36Sopenharmony_ci		/*
100062306a36Sopenharmony_ci		 * It was negotiating SDTR with target, sending from the
100162306a36Sopenharmony_ci		 * initiator, but there are no chance to remove this flag.
100262306a36Sopenharmony_ci		 * Set async because we don't get proper negotiation.
100362306a36Sopenharmony_ci		 */
100462306a36Sopenharmony_ci		nsp32_set_async(data, target);
100562306a36Sopenharmony_ci		target->sync_flag &= ~SDTR_INITIATOR;
100662306a36Sopenharmony_ci		target->sync_flag |= SDTR_DONE;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
100962306a36Sopenharmony_ci			  "SDTR_INITIATOR: fall back to async");
101062306a36Sopenharmony_ci	} else if (target->sync_flag & SDTR_TARGET) {
101162306a36Sopenharmony_ci		/*
101262306a36Sopenharmony_ci		 * It was negotiating SDTR with target, sending from target,
101362306a36Sopenharmony_ci		 * but there are no chance to remove this flag.  Set async
101462306a36Sopenharmony_ci		 * because we don't get proper negotiation.
101562306a36Sopenharmony_ci		 */
101662306a36Sopenharmony_ci		nsp32_set_async(data, target);
101762306a36Sopenharmony_ci		target->sync_flag &= ~SDTR_TARGET;
101862306a36Sopenharmony_ci		target->sync_flag |= SDTR_DONE;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
102162306a36Sopenharmony_ci			  "Unknown SDTR from target is reached, fall back to async.");
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_TARGETFLAG,
102562306a36Sopenharmony_ci		  "target: %d sync_flag: 0x%x syncreg: 0x%x ackwidth: 0x%x",
102662306a36Sopenharmony_ci		  SCpnt->device->id, target->sync_flag, target->syncreg,
102762306a36Sopenharmony_ci		  target->ackwidth);
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	/* Selection */
103062306a36Sopenharmony_ci	if (auto_param == 0) {
103162306a36Sopenharmony_ci		ret = nsp32_selection_autopara(SCpnt);
103262306a36Sopenharmony_ci	} else {
103362306a36Sopenharmony_ci		ret = nsp32_selection_autoscsi(SCpnt);
103462306a36Sopenharmony_ci	}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	if (ret != TRUE) {
103762306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "selection fail");
103862306a36Sopenharmony_ci		nsp32_scsi_done(SCpnt);
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	return 0;
104262306a36Sopenharmony_ci}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_cistatic DEF_SCSI_QCMD(nsp32_queuecommand)
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci/* initialize asic */
104762306a36Sopenharmony_cistatic int nsp32hw_init(nsp32_hw_data *data)
104862306a36Sopenharmony_ci{
104962306a36Sopenharmony_ci	unsigned int   base = data->BaseAddress;
105062306a36Sopenharmony_ci	unsigned short irq_stat;
105162306a36Sopenharmony_ci	unsigned long  lc_reg;
105262306a36Sopenharmony_ci	unsigned char  power;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	lc_reg = nsp32_index_read4(base, CFG_LATE_CACHE);
105562306a36Sopenharmony_ci	if ((lc_reg & 0xff00) == 0) {
105662306a36Sopenharmony_ci		lc_reg |= (0x20 << 8);
105762306a36Sopenharmony_ci		nsp32_index_write2(base, CFG_LATE_CACHE, lc_reg & 0xffff);
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
106162306a36Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL, 0);
106262306a36Sopenharmony_ci	nsp32_write4(base, BM_CNT, 0);
106362306a36Sopenharmony_ci	nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	do {
106662306a36Sopenharmony_ci		irq_stat = nsp32_read2(base, IRQ_STATUS);
106762306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INIT, "irq_stat 0x%x", irq_stat);
106862306a36Sopenharmony_ci	} while (irq_stat & IRQSTATUS_ANY_IRQ);
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	/*
107162306a36Sopenharmony_ci	 * Fill FIFO_FULL_SHLD, FIFO_EMPTY_SHLD. Below parameter is
107262306a36Sopenharmony_ci	 *  designated by specification.
107362306a36Sopenharmony_ci	 */
107462306a36Sopenharmony_ci	if ((data->trans_method & NSP32_TRANSFER_PIO) ||
107562306a36Sopenharmony_ci	    (data->trans_method & NSP32_TRANSFER_MMIO)) {
107662306a36Sopenharmony_ci		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT,  0x40);
107762306a36Sopenharmony_ci		nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x40);
107862306a36Sopenharmony_ci	} else if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
107962306a36Sopenharmony_ci		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT,  0x10);
108062306a36Sopenharmony_ci		nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x60);
108162306a36Sopenharmony_ci	} else {
108262306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INIT, "unknown transfer mode");
108362306a36Sopenharmony_ci	}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_INIT, "full 0x%x emp 0x%x",
108662306a36Sopenharmony_ci		  nsp32_index_read1(base, FIFO_FULL_SHLD_COUNT),
108762306a36Sopenharmony_ci		  nsp32_index_read1(base, FIFO_EMPTY_SHLD_COUNT));
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	nsp32_index_write1(base, CLOCK_DIV, data->clock);
109062306a36Sopenharmony_ci	nsp32_index_write1(base, BM_CYCLE,
109162306a36Sopenharmony_ci			   MEMRD_CMD1 | SGT_AUTO_PARA_MEMED_CMD);
109262306a36Sopenharmony_ci	nsp32_write1(base, PARITY_CONTROL, 0);	/* parity check is disable */
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	/*
109562306a36Sopenharmony_ci	 * initialize MISC_WRRD register
109662306a36Sopenharmony_ci	 *
109762306a36Sopenharmony_ci	 * Note: Designated parameters is obeyed as following:
109862306a36Sopenharmony_ci	 *	MISC_SCSI_DIRECTION_DETECTOR_SELECT: It must be set.
109962306a36Sopenharmony_ci	 *	MISC_MASTER_TERMINATION_SELECT:      It must be set.
110062306a36Sopenharmony_ci	 *	MISC_BMREQ_NEGATE_TIMING_SEL:	     It should be set.
110162306a36Sopenharmony_ci	 *	MISC_AUTOSEL_TIMING_SEL:	     It should be set.
110262306a36Sopenharmony_ci	 *	MISC_BMSTOP_CHANGE2_NONDATA_PHASE:   It should be set.
110362306a36Sopenharmony_ci	 *	MISC_DELAYED_BMSTART:		     It's selected for safety.
110462306a36Sopenharmony_ci	 *
110562306a36Sopenharmony_ci	 * Note: If MISC_BMSTOP_CHANGE2_NONDATA_PHASE is set, then
110662306a36Sopenharmony_ci	 *	we have to set TRANSFERCONTROL_BM_START as 0 and set
110762306a36Sopenharmony_ci	 *	appropriate value before restarting bus master transfer.
110862306a36Sopenharmony_ci	 */
110962306a36Sopenharmony_ci	nsp32_index_write2(base, MISC_WR,
111062306a36Sopenharmony_ci			   (SCSI_DIRECTION_DETECTOR_SELECT |
111162306a36Sopenharmony_ci			    DELAYED_BMSTART |
111262306a36Sopenharmony_ci			    MASTER_TERMINATION_SELECT |
111362306a36Sopenharmony_ci			    BMREQ_NEGATE_TIMING_SEL |
111462306a36Sopenharmony_ci			    AUTOSEL_TIMING_SEL |
111562306a36Sopenharmony_ci			    BMSTOP_CHANGE2_NONDATA_PHASE));
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	nsp32_index_write1(base, TERM_PWR_CONTROL, 0);
111862306a36Sopenharmony_ci	power = nsp32_index_read1(base, TERM_PWR_CONTROL);
111962306a36Sopenharmony_ci	if (!(power & SENSE)) {
112062306a36Sopenharmony_ci		nsp32_msg(KERN_INFO, "term power on");
112162306a36Sopenharmony_ci		nsp32_index_write1(base, TERM_PWR_CONTROL, BPWR);
112262306a36Sopenharmony_ci	}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	nsp32_write2(base, TIMER_SET, TIMER_STOP);
112562306a36Sopenharmony_ci	nsp32_write2(base, TIMER_SET, TIMER_STOP); /* Required 2 times */
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	nsp32_write1(base, SYNC_REG,     0);
112862306a36Sopenharmony_ci	nsp32_write1(base, ACK_WIDTH,    0);
112962306a36Sopenharmony_ci	nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	/*
113262306a36Sopenharmony_ci	 * enable to select designated IRQ (except for
113362306a36Sopenharmony_ci	 * IRQSELECT_SERR, IRQSELECT_PERR, IRQSELECT_BMCNTERR)
113462306a36Sopenharmony_ci	 */
113562306a36Sopenharmony_ci	nsp32_index_write2(base, IRQ_SELECT,
113662306a36Sopenharmony_ci			   IRQSELECT_TIMER_IRQ |
113762306a36Sopenharmony_ci			   IRQSELECT_SCSIRESET_IRQ |
113862306a36Sopenharmony_ci			   IRQSELECT_FIFO_SHLD_IRQ |
113962306a36Sopenharmony_ci			   IRQSELECT_RESELECT_IRQ |
114062306a36Sopenharmony_ci			   IRQSELECT_PHASE_CHANGE_IRQ |
114162306a36Sopenharmony_ci			   IRQSELECT_AUTO_SCSI_SEQ_IRQ |
114262306a36Sopenharmony_ci			   //   IRQSELECT_BMCNTERR_IRQ      |
114362306a36Sopenharmony_ci			   IRQSELECT_TARGET_ABORT_IRQ |
114462306a36Sopenharmony_ci			   IRQSELECT_MASTER_ABORT_IRQ );
114562306a36Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, 0);
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	/* PCI LED off */
114862306a36Sopenharmony_ci	nsp32_index_write1(base, EXT_PORT_DDR, LED_OFF);
114962306a36Sopenharmony_ci	nsp32_index_write1(base, EXT_PORT,     LED_OFF);
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	return TRUE;
115262306a36Sopenharmony_ci}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci/* interrupt routine */
115662306a36Sopenharmony_cistatic irqreturn_t do_nsp32_isr(int irq, void *dev_id)
115762306a36Sopenharmony_ci{
115862306a36Sopenharmony_ci	nsp32_hw_data *data = dev_id;
115962306a36Sopenharmony_ci	unsigned int base = data->BaseAddress;
116062306a36Sopenharmony_ci	struct scsi_cmnd *SCpnt = data->CurrentSC;
116162306a36Sopenharmony_ci	unsigned short auto_stat, irq_stat, trans_stat;
116262306a36Sopenharmony_ci	unsigned char busmon, busphase;
116362306a36Sopenharmony_ci	unsigned long flags;
116462306a36Sopenharmony_ci	int ret;
116562306a36Sopenharmony_ci	int handled = 0;
116662306a36Sopenharmony_ci	struct Scsi_Host *host = data->Host;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	spin_lock_irqsave(host->host_lock, flags);
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	/*
117162306a36Sopenharmony_ci	 * IRQ check, then enable IRQ mask
117262306a36Sopenharmony_ci	 */
117362306a36Sopenharmony_ci	irq_stat = nsp32_read2(base, IRQ_STATUS);
117462306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_INTR,
117562306a36Sopenharmony_ci		  "enter IRQ: %d, IRQstatus: 0x%x", irq, irq_stat);
117662306a36Sopenharmony_ci	/* is this interrupt comes from Ninja asic? */
117762306a36Sopenharmony_ci	if ((irq_stat & IRQSTATUS_ANY_IRQ) == 0) {
117862306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INTR,
117962306a36Sopenharmony_ci			  "shared interrupt: irq other 0x%x", irq_stat);
118062306a36Sopenharmony_ci		goto out2;
118162306a36Sopenharmony_ci	}
118262306a36Sopenharmony_ci	handled = 1;
118362306a36Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	busmon = nsp32_read1(base, SCSI_BUS_MONITOR);
118662306a36Sopenharmony_ci	busphase = busmon & BUSMON_PHASE_MASK;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	trans_stat = nsp32_read2(base, TRANSFER_STATUS);
118962306a36Sopenharmony_ci	if ((irq_stat == 0xffff) && (trans_stat == 0xffff)) {
119062306a36Sopenharmony_ci		nsp32_msg(KERN_INFO, "card disconnect");
119162306a36Sopenharmony_ci		if (data->CurrentSC != NULL) {
119262306a36Sopenharmony_ci			nsp32_msg(KERN_INFO, "clean up current SCSI command");
119362306a36Sopenharmony_ci			SCpnt->result = DID_BAD_TARGET << 16;
119462306a36Sopenharmony_ci			nsp32_scsi_done(SCpnt);
119562306a36Sopenharmony_ci		}
119662306a36Sopenharmony_ci		goto out;
119762306a36Sopenharmony_ci	}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	/* Timer IRQ */
120062306a36Sopenharmony_ci	if (irq_stat & IRQSTATUS_TIMER_IRQ) {
120162306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INTR, "timer stop");
120262306a36Sopenharmony_ci		nsp32_write2(base, TIMER_SET, TIMER_STOP);
120362306a36Sopenharmony_ci		goto out;
120462306a36Sopenharmony_ci	}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	/* SCSI reset */
120762306a36Sopenharmony_ci	if (irq_stat & IRQSTATUS_SCSIRESET_IRQ) {
120862306a36Sopenharmony_ci		nsp32_msg(KERN_INFO, "detected someone do bus reset");
120962306a36Sopenharmony_ci		nsp32_do_bus_reset(data);
121062306a36Sopenharmony_ci		if (SCpnt != NULL) {
121162306a36Sopenharmony_ci			SCpnt->result = DID_RESET << 16;
121262306a36Sopenharmony_ci			nsp32_scsi_done(SCpnt);
121362306a36Sopenharmony_ci		}
121462306a36Sopenharmony_ci		goto out;
121562306a36Sopenharmony_ci	}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	if (SCpnt == NULL) {
121862306a36Sopenharmony_ci		nsp32_msg(KERN_WARNING, "SCpnt==NULL this can't be happened");
121962306a36Sopenharmony_ci		nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x",
122062306a36Sopenharmony_ci			  irq_stat, trans_stat);
122162306a36Sopenharmony_ci		goto out;
122262306a36Sopenharmony_ci	}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	/*
122562306a36Sopenharmony_ci	 * AutoSCSI Interrupt.
122662306a36Sopenharmony_ci	 * Note: This interrupt is occurred when AutoSCSI is finished.  Then
122762306a36Sopenharmony_ci	 * check SCSIEXECUTEPHASE, and do appropriate action.  Each phases are
122862306a36Sopenharmony_ci	 * recorded when AutoSCSI sequencer has been processed.
122962306a36Sopenharmony_ci	 */
123062306a36Sopenharmony_ci	if(irq_stat & IRQSTATUS_AUTOSCSI_IRQ) {
123162306a36Sopenharmony_ci		/* getting SCSI executed phase */
123262306a36Sopenharmony_ci		auto_stat = nsp32_read2(base, SCSI_EXECUTE_PHASE);
123362306a36Sopenharmony_ci		nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci		/* Selection Timeout, go busfree phase. */
123662306a36Sopenharmony_ci		if (auto_stat & SELECTION_TIMEOUT) {
123762306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR,
123862306a36Sopenharmony_ci				  "selection timeout occurred");
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci			SCpnt->result = DID_TIME_OUT << 16;
124162306a36Sopenharmony_ci			nsp32_scsi_done(SCpnt);
124262306a36Sopenharmony_ci			goto out;
124362306a36Sopenharmony_ci		}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci		if (auto_stat & MSGOUT_PHASE) {
124662306a36Sopenharmony_ci			/*
124762306a36Sopenharmony_ci			 * MsgOut phase was processed.
124862306a36Sopenharmony_ci			 * If MSG_IN_OCCUER is not set, then MsgOut phase is
124962306a36Sopenharmony_ci			 * completed. Thus, msgout_len must reset.  Otherwise,
125062306a36Sopenharmony_ci			 * nothing to do here. If MSG_OUT_OCCUER is occurred,
125162306a36Sopenharmony_ci			 * then we will encounter the condition and check.
125262306a36Sopenharmony_ci			 */
125362306a36Sopenharmony_ci			if (!(auto_stat & MSG_IN_OCCUER) &&
125462306a36Sopenharmony_ci			     (data->msgout_len <= 3)) {
125562306a36Sopenharmony_ci				/*
125662306a36Sopenharmony_ci				 * !MSG_IN_OCCUER && msgout_len <=3
125762306a36Sopenharmony_ci				 *   ---> AutoSCSI with MSGOUTreg is processed.
125862306a36Sopenharmony_ci				 */
125962306a36Sopenharmony_ci				data->msgout_len = 0;
126062306a36Sopenharmony_ci			}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "MsgOut phase processed");
126362306a36Sopenharmony_ci		}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci		if ((auto_stat & DATA_IN_PHASE) &&
126662306a36Sopenharmony_ci		    (scsi_get_resid(SCpnt) > 0) &&
126762306a36Sopenharmony_ci		    ((nsp32_read2(base, FIFO_REST_CNT) & FIFO_REST_MASK) != 0)) {
126862306a36Sopenharmony_ci			printk( "auto+fifo\n");
126962306a36Sopenharmony_ci			//nsp32_pio_read(SCpnt);
127062306a36Sopenharmony_ci		}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci		if (auto_stat & (DATA_IN_PHASE | DATA_OUT_PHASE)) {
127362306a36Sopenharmony_ci			/* DATA_IN_PHASE/DATA_OUT_PHASE was processed. */
127462306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR,
127562306a36Sopenharmony_ci				  "Data in/out phase processed");
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci			/* read BMCNT, SGT pointer addr */
127862306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "BMCNT=0x%lx",
127962306a36Sopenharmony_ci				    nsp32_read4(base, BM_CNT));
128062306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "addr=0x%lx",
128162306a36Sopenharmony_ci				    nsp32_read4(base, SGT_ADR));
128262306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "SACK=0x%lx",
128362306a36Sopenharmony_ci				    nsp32_read4(base, SACK_CNT));
128462306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx",
128562306a36Sopenharmony_ci				    nsp32_read4(base, SAVED_SACK_CNT));
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci			scsi_set_resid(SCpnt, 0); /* all data transferred! */
128862306a36Sopenharmony_ci		}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci		/*
129162306a36Sopenharmony_ci		 * MsgIn Occur
129262306a36Sopenharmony_ci		 */
129362306a36Sopenharmony_ci		if (auto_stat & MSG_IN_OCCUER) {
129462306a36Sopenharmony_ci			nsp32_msgin_occur(SCpnt, irq_stat, auto_stat);
129562306a36Sopenharmony_ci		}
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci		/*
129862306a36Sopenharmony_ci		 * MsgOut Occur
129962306a36Sopenharmony_ci		 */
130062306a36Sopenharmony_ci		if (auto_stat & MSG_OUT_OCCUER) {
130162306a36Sopenharmony_ci			nsp32_msgout_occur(SCpnt);
130262306a36Sopenharmony_ci		}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci		/*
130562306a36Sopenharmony_ci		 * Bus Free Occur
130662306a36Sopenharmony_ci		 */
130762306a36Sopenharmony_ci		if (auto_stat & BUS_FREE_OCCUER) {
130862306a36Sopenharmony_ci			ret = nsp32_busfree_occur(SCpnt, auto_stat);
130962306a36Sopenharmony_ci			if (ret == TRUE) {
131062306a36Sopenharmony_ci				goto out;
131162306a36Sopenharmony_ci			}
131262306a36Sopenharmony_ci		}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci		if (auto_stat & STATUS_PHASE) {
131562306a36Sopenharmony_ci			/*
131662306a36Sopenharmony_ci			 * Read CSB and substitute CSB for SCpnt->result
131762306a36Sopenharmony_ci			 * to save status phase stutas byte.
131862306a36Sopenharmony_ci			 * scsi error handler checks host_byte (DID_*:
131962306a36Sopenharmony_ci			 * low level driver to indicate status), then checks
132062306a36Sopenharmony_ci			 * status_byte (SCSI status byte).
132162306a36Sopenharmony_ci			 */
132262306a36Sopenharmony_ci			SCpnt->result =	(int)nsp32_read1(base, SCSI_CSB_IN);
132362306a36Sopenharmony_ci		}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci		if (auto_stat & ILLEGAL_PHASE) {
132662306a36Sopenharmony_ci			/* Illegal phase is detected. SACK is not back. */
132762306a36Sopenharmony_ci			nsp32_msg(KERN_WARNING,
132862306a36Sopenharmony_ci				  "AUTO SCSI ILLEGAL PHASE OCCUR!!!!");
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci			/* TODO: currently we don't have any action... bus reset? */
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci			/*
133362306a36Sopenharmony_ci			 * To send back SACK, assert, wait, and negate.
133462306a36Sopenharmony_ci			 */
133562306a36Sopenharmony_ci			nsp32_sack_assert(data);
133662306a36Sopenharmony_ci			nsp32_wait_req(data, NEGATE);
133762306a36Sopenharmony_ci			nsp32_sack_negate(data);
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci		}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci		if (auto_stat & COMMAND_PHASE) {
134262306a36Sopenharmony_ci			/* nothing to do */
134362306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "Command phase processed");
134462306a36Sopenharmony_ci		}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci		if (auto_stat & AUTOSCSI_BUSY) {
134762306a36Sopenharmony_ci			/* AutoSCSI is running */
134862306a36Sopenharmony_ci		}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci		show_autophase(auto_stat);
135162306a36Sopenharmony_ci	}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	/* FIFO_SHLD_IRQ */
135462306a36Sopenharmony_ci	if (irq_stat & IRQSTATUS_FIFO_SHLD_IRQ) {
135562306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INTR, "FIFO IRQ");
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci		switch(busphase) {
135862306a36Sopenharmony_ci		case BUSPHASE_DATA_OUT:
135962306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/write");
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci			//nsp32_pio_write(SCpnt);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci			break;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci		case BUSPHASE_DATA_IN:
136662306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/read");
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci			//nsp32_pio_read(SCpnt);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci			break;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci		case BUSPHASE_STATUS:
137362306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/status");
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci			nsp32_priv(SCpnt)->status = nsp32_read1(base, SCSI_CSB_IN);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci			break;
137862306a36Sopenharmony_ci		default:
137962306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/other phase");
138062306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "irq_stat=0x%x trans_stat=0x%x",
138162306a36Sopenharmony_ci				  irq_stat, trans_stat);
138262306a36Sopenharmony_ci			show_busphase(busphase);
138362306a36Sopenharmony_ci			break;
138462306a36Sopenharmony_ci		}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci		goto out;
138762306a36Sopenharmony_ci	}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	/* Phase Change IRQ */
139062306a36Sopenharmony_ci	if (irq_stat & IRQSTATUS_PHASE_CHANGE_IRQ) {
139162306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INTR, "phase change IRQ");
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci		switch(busphase) {
139462306a36Sopenharmony_ci		case BUSPHASE_MESSAGE_IN:
139562306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "phase chg/msg in");
139662306a36Sopenharmony_ci			nsp32_msgin_occur(SCpnt, irq_stat, 0);
139762306a36Sopenharmony_ci			break;
139862306a36Sopenharmony_ci		default:
139962306a36Sopenharmony_ci			nsp32_msg(KERN_WARNING, "phase chg/other phase?");
140062306a36Sopenharmony_ci			nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x\n",
140162306a36Sopenharmony_ci				  irq_stat, trans_stat);
140262306a36Sopenharmony_ci			show_busphase(busphase);
140362306a36Sopenharmony_ci			break;
140462306a36Sopenharmony_ci		}
140562306a36Sopenharmony_ci		goto out;
140662306a36Sopenharmony_ci	}
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	/* PCI_IRQ */
140962306a36Sopenharmony_ci	if (irq_stat & IRQSTATUS_PCI_IRQ) {
141062306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INTR, "PCI IRQ occurred");
141162306a36Sopenharmony_ci		/* Do nothing */
141262306a36Sopenharmony_ci	}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	/* BMCNTERR_IRQ */
141562306a36Sopenharmony_ci	if (irq_stat & IRQSTATUS_BMCNTERR_IRQ) {
141662306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "Received unexpected BMCNTERR IRQ! ");
141762306a36Sopenharmony_ci		/*
141862306a36Sopenharmony_ci		 * TODO: To be implemented improving bus master
141962306a36Sopenharmony_ci		 * transfer reliability when BMCNTERR is occurred in
142062306a36Sopenharmony_ci		 * AutoSCSI phase described in specification.
142162306a36Sopenharmony_ci		 */
142262306a36Sopenharmony_ci	}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci#if 0
142562306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_INTR,
142662306a36Sopenharmony_ci		  "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat);
142762306a36Sopenharmony_ci	show_busphase(busphase);
142862306a36Sopenharmony_ci#endif
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci out:
143162306a36Sopenharmony_ci	/* disable IRQ mask */
143262306a36Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, 0);
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci out2:
143562306a36Sopenharmony_ci	spin_unlock_irqrestore(host->host_lock, flags);
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_INTR, "exit");
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	return IRQ_RETVAL(handled);
144062306a36Sopenharmony_ci}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_cistatic int nsp32_show_info(struct seq_file *m, struct Scsi_Host *host)
144462306a36Sopenharmony_ci{
144562306a36Sopenharmony_ci	unsigned long     flags;
144662306a36Sopenharmony_ci	nsp32_hw_data    *data;
144762306a36Sopenharmony_ci	int		  hostno;
144862306a36Sopenharmony_ci	unsigned int      base;
144962306a36Sopenharmony_ci	unsigned char     mode_reg;
145062306a36Sopenharmony_ci	int		  id, speed;
145162306a36Sopenharmony_ci	long		  model;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	hostno = host->host_no;
145462306a36Sopenharmony_ci	data = (nsp32_hw_data *)host->hostdata;
145562306a36Sopenharmony_ci	base = host->io_port;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	seq_puts(m, "NinjaSCSI-32 status\n\n");
145862306a36Sopenharmony_ci	seq_printf(m, "Driver version:        %s, $Revision: 1.33 $\n",
145962306a36Sopenharmony_ci		   nsp32_release_version);
146062306a36Sopenharmony_ci	seq_printf(m, "SCSI host No.:         %d\n", hostno);
146162306a36Sopenharmony_ci	seq_printf(m, "IRQ:                   %d\n", host->irq);
146262306a36Sopenharmony_ci	seq_printf(m, "IO:                    0x%lx-0x%lx\n",
146362306a36Sopenharmony_ci		   host->io_port, host->io_port + host->n_io_port - 1);
146462306a36Sopenharmony_ci	seq_printf(m, "MMIO(virtual address): 0x%lx-0x%lx\n",
146562306a36Sopenharmony_ci		   host->base, host->base + data->MmioLength - 1);
146662306a36Sopenharmony_ci	seq_printf(m, "sg_tablesize:          %d\n",
146762306a36Sopenharmony_ci		   host->sg_tablesize);
146862306a36Sopenharmony_ci	seq_printf(m, "Chip revision:         0x%x\n",
146962306a36Sopenharmony_ci		   (nsp32_read2(base, INDEX_REG) >> 8) & 0xff);
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	mode_reg = nsp32_index_read1(base, CHIP_MODE);
147262306a36Sopenharmony_ci	model    = data->pci_devid->driver_data;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci#ifdef CONFIG_PM
147562306a36Sopenharmony_ci	seq_printf(m, "Power Management:      %s\n",
147662306a36Sopenharmony_ci		   (mode_reg & OPTF) ? "yes" : "no");
147762306a36Sopenharmony_ci#endif
147862306a36Sopenharmony_ci	seq_printf(m, "OEM:                   %ld, %s\n",
147962306a36Sopenharmony_ci		   (mode_reg & (OEM0|OEM1)), nsp32_model[model]);
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	spin_lock_irqsave(&(data->Lock), flags);
148262306a36Sopenharmony_ci	seq_printf(m, "CurrentSC:             0x%p\n\n",      data->CurrentSC);
148362306a36Sopenharmony_ci	spin_unlock_irqrestore(&(data->Lock), flags);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	seq_puts(m, "SDTR status\n");
148762306a36Sopenharmony_ci	for (id = 0; id < ARRAY_SIZE(data->target); id++) {
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci		seq_printf(m, "id %d: ", id);
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci		if (id == host->this_id) {
149262306a36Sopenharmony_ci			seq_puts(m, "----- NinjaSCSI-32 host adapter\n");
149362306a36Sopenharmony_ci			continue;
149462306a36Sopenharmony_ci		}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci		if (data->target[id].sync_flag == SDTR_DONE) {
149762306a36Sopenharmony_ci			if (data->target[id].period == 0 &&
149862306a36Sopenharmony_ci			    data->target[id].offset == ASYNC_OFFSET ) {
149962306a36Sopenharmony_ci				seq_puts(m, "async");
150062306a36Sopenharmony_ci			} else {
150162306a36Sopenharmony_ci				seq_puts(m, " sync");
150262306a36Sopenharmony_ci			}
150362306a36Sopenharmony_ci		} else {
150462306a36Sopenharmony_ci			seq_puts(m, " none");
150562306a36Sopenharmony_ci		}
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci		if (data->target[id].period != 0) {
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci			speed = 1000000 / (data->target[id].period * 4);
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci			seq_printf(m, " transfer %d.%dMB/s, offset %d",
151262306a36Sopenharmony_ci				speed / 1000,
151362306a36Sopenharmony_ci				speed % 1000,
151462306a36Sopenharmony_ci				data->target[id].offset
151562306a36Sopenharmony_ci				);
151662306a36Sopenharmony_ci		}
151762306a36Sopenharmony_ci		seq_putc(m, '\n');
151862306a36Sopenharmony_ci	}
151962306a36Sopenharmony_ci	return 0;
152062306a36Sopenharmony_ci}
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci/*
152562306a36Sopenharmony_ci * Reset parameters and call scsi_done for data->cur_lunt.
152662306a36Sopenharmony_ci * Be careful setting SCpnt->result = DID_* before calling this function.
152762306a36Sopenharmony_ci */
152862306a36Sopenharmony_cistatic void nsp32_scsi_done(struct scsi_cmnd *SCpnt)
152962306a36Sopenharmony_ci{
153062306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
153162306a36Sopenharmony_ci	unsigned int   base = SCpnt->device->host->io_port;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	scsi_dma_unmap(SCpnt);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	/*
153662306a36Sopenharmony_ci	 * clear TRANSFERCONTROL_BM_START
153762306a36Sopenharmony_ci	 */
153862306a36Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL, 0);
153962306a36Sopenharmony_ci	nsp32_write4(base, BM_CNT, 0);
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	/*
154262306a36Sopenharmony_ci	 * call scsi_done
154362306a36Sopenharmony_ci	 */
154462306a36Sopenharmony_ci	scsi_done(SCpnt);
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	/*
154762306a36Sopenharmony_ci	 * reset parameters
154862306a36Sopenharmony_ci	 */
154962306a36Sopenharmony_ci	data->cur_lunt->SCpnt	= NULL;
155062306a36Sopenharmony_ci	data->cur_lunt		= NULL;
155162306a36Sopenharmony_ci	data->cur_target	= NULL;
155262306a36Sopenharmony_ci	data->CurrentSC		= NULL;
155362306a36Sopenharmony_ci}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci/*
155762306a36Sopenharmony_ci * Bus Free Occur
155862306a36Sopenharmony_ci *
155962306a36Sopenharmony_ci * Current Phase is BUSFREE. AutoSCSI is automatically execute BUSFREE phase
156062306a36Sopenharmony_ci * with ACK reply when below condition is matched:
156162306a36Sopenharmony_ci *	MsgIn 00: Command Complete.
156262306a36Sopenharmony_ci *	MsgIn 02: Save Data Pointer.
156362306a36Sopenharmony_ci *	MsgIn 04: Disconnect.
156462306a36Sopenharmony_ci * In other case, unexpected BUSFREE is detected.
156562306a36Sopenharmony_ci */
156662306a36Sopenharmony_cistatic int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph)
156762306a36Sopenharmony_ci{
156862306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
156962306a36Sopenharmony_ci	unsigned int base   = SCpnt->device->host->io_port;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_BUSFREE, "enter execph=0x%x", execph);
157262306a36Sopenharmony_ci	show_autophase(execph);
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	nsp32_write4(base, BM_CNT, 0);
157562306a36Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL, 0);
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	/*
157862306a36Sopenharmony_ci	 * MsgIn 02: Save Data Pointer
157962306a36Sopenharmony_ci	 *
158062306a36Sopenharmony_ci	 * VALID:
158162306a36Sopenharmony_ci	 *   Save Data Pointer is received. Adjust pointer.
158262306a36Sopenharmony_ci	 *
158362306a36Sopenharmony_ci	 * NO-VALID:
158462306a36Sopenharmony_ci	 *   SCSI-3 says if Save Data Pointer is not received, then we restart
158562306a36Sopenharmony_ci	 *   processing and we can't adjust any SCSI data pointer in next data
158662306a36Sopenharmony_ci	 *   phase.
158762306a36Sopenharmony_ci	 */
158862306a36Sopenharmony_ci	if (execph & MSGIN_02_VALID) {
158962306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_BUSFREE, "MsgIn02_Valid");
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci		/*
159262306a36Sopenharmony_ci		 * Check sack_cnt/saved_sack_cnt, then adjust sg table if
159362306a36Sopenharmony_ci		 * needed.
159462306a36Sopenharmony_ci		 */
159562306a36Sopenharmony_ci		if (!(execph & MSGIN_00_VALID) &&
159662306a36Sopenharmony_ci		    ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE))) {
159762306a36Sopenharmony_ci			unsigned int sacklen, s_sacklen;
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci			/*
160062306a36Sopenharmony_ci			 * Read SACK count and SAVEDSACK count, then compare.
160162306a36Sopenharmony_ci			 */
160262306a36Sopenharmony_ci			sacklen   = nsp32_read4(base, SACK_CNT      );
160362306a36Sopenharmony_ci			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci			/*
160662306a36Sopenharmony_ci			 * If SAVEDSACKCNT == 0, it means SavedDataPointer is
160762306a36Sopenharmony_ci			 * come after data transferring.
160862306a36Sopenharmony_ci			 */
160962306a36Sopenharmony_ci			if (s_sacklen > 0) {
161062306a36Sopenharmony_ci				/*
161162306a36Sopenharmony_ci				 * Comparing between sack and savedsack to
161262306a36Sopenharmony_ci				 * check the condition of AutoMsgIn03.
161362306a36Sopenharmony_ci				 *
161462306a36Sopenharmony_ci				 * If they are same, set msgin03 == TRUE,
161562306a36Sopenharmony_ci				 * COMMANDCONTROL_AUTO_MSGIN_03 is enabled at
161662306a36Sopenharmony_ci				 * reselection.  On the other hand, if they
161762306a36Sopenharmony_ci				 * aren't same, set msgin03 == FALSE, and
161862306a36Sopenharmony_ci				 * COMMANDCONTROL_AUTO_MSGIN_03 is disabled at
161962306a36Sopenharmony_ci				 * reselection.
162062306a36Sopenharmony_ci				 */
162162306a36Sopenharmony_ci				if (sacklen != s_sacklen) {
162262306a36Sopenharmony_ci					data->cur_lunt->msgin03 = FALSE;
162362306a36Sopenharmony_ci				} else {
162462306a36Sopenharmony_ci					data->cur_lunt->msgin03 = TRUE;
162562306a36Sopenharmony_ci				}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci				nsp32_adjust_busfree(SCpnt, s_sacklen);
162862306a36Sopenharmony_ci			}
162962306a36Sopenharmony_ci		}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci		/* This value has not substitude with valid value yet... */
163262306a36Sopenharmony_ci		//data->cur_lunt->save_datp = data->cur_datp;
163362306a36Sopenharmony_ci	} else {
163462306a36Sopenharmony_ci		/*
163562306a36Sopenharmony_ci		 * no processing.
163662306a36Sopenharmony_ci		 */
163762306a36Sopenharmony_ci	}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	if (execph & MSGIN_03_VALID) {
164062306a36Sopenharmony_ci		/* MsgIn03 was valid to be processed. No need processing. */
164162306a36Sopenharmony_ci	}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	/*
164462306a36Sopenharmony_ci	 * target SDTR check
164562306a36Sopenharmony_ci	 */
164662306a36Sopenharmony_ci	if (data->cur_target->sync_flag & SDTR_INITIATOR) {
164762306a36Sopenharmony_ci		/*
164862306a36Sopenharmony_ci		 * SDTR negotiation pulled by the initiator has not
164962306a36Sopenharmony_ci		 * finished yet. Fall back to ASYNC mode.
165062306a36Sopenharmony_ci		 */
165162306a36Sopenharmony_ci		nsp32_set_async(data, data->cur_target);
165262306a36Sopenharmony_ci		data->cur_target->sync_flag &= ~SDTR_INITIATOR;
165362306a36Sopenharmony_ci		data->cur_target->sync_flag |= SDTR_DONE;
165462306a36Sopenharmony_ci	} else if (data->cur_target->sync_flag & SDTR_TARGET) {
165562306a36Sopenharmony_ci		/*
165662306a36Sopenharmony_ci		 * SDTR negotiation pulled by the target has been
165762306a36Sopenharmony_ci		 * negotiating.
165862306a36Sopenharmony_ci		 */
165962306a36Sopenharmony_ci		if (execph & (MSGIN_00_VALID | MSGIN_04_VALID)) {
166062306a36Sopenharmony_ci			/*
166162306a36Sopenharmony_ci			 * If valid message is received, then
166262306a36Sopenharmony_ci			 * negotiation is succeeded.
166362306a36Sopenharmony_ci			 */
166462306a36Sopenharmony_ci		} else {
166562306a36Sopenharmony_ci			/*
166662306a36Sopenharmony_ci			 * On the contrary, if unexpected bus free is
166762306a36Sopenharmony_ci			 * occurred, then negotiation is failed. Fall
166862306a36Sopenharmony_ci			 * back to ASYNC mode.
166962306a36Sopenharmony_ci			 */
167062306a36Sopenharmony_ci			nsp32_set_async(data, data->cur_target);
167162306a36Sopenharmony_ci		}
167262306a36Sopenharmony_ci		data->cur_target->sync_flag &= ~SDTR_TARGET;
167362306a36Sopenharmony_ci		data->cur_target->sync_flag |= SDTR_DONE;
167462306a36Sopenharmony_ci	}
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	/*
167762306a36Sopenharmony_ci	 * It is always ensured by SCSI standard that initiator
167862306a36Sopenharmony_ci	 * switches into Bus Free Phase after
167962306a36Sopenharmony_ci	 * receiving message 00 (Command Complete), 04 (Disconnect).
168062306a36Sopenharmony_ci	 * It's the reason that processing here is valid.
168162306a36Sopenharmony_ci	 */
168262306a36Sopenharmony_ci	if (execph & MSGIN_00_VALID) {
168362306a36Sopenharmony_ci		/* MsgIn 00: Command Complete */
168462306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_BUSFREE, "command complete");
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci		nsp32_priv(SCpnt)->status  = nsp32_read1(base, SCSI_CSB_IN);
168762306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_BUSFREE,
168862306a36Sopenharmony_ci			  "normal end stat=0x%x resid=0x%x\n",
168962306a36Sopenharmony_ci			  nsp32_priv(SCpnt)->status, scsi_get_resid(SCpnt));
169062306a36Sopenharmony_ci		SCpnt->result = (DID_OK << 16) |
169162306a36Sopenharmony_ci			(nsp32_priv(SCpnt)->status << 0);
169262306a36Sopenharmony_ci		nsp32_scsi_done(SCpnt);
169362306a36Sopenharmony_ci		/* All operation is done */
169462306a36Sopenharmony_ci		return TRUE;
169562306a36Sopenharmony_ci	} else if (execph & MSGIN_04_VALID) {
169662306a36Sopenharmony_ci		/* MsgIn 04: Disconnect */
169762306a36Sopenharmony_ci		nsp32_priv(SCpnt)->status = nsp32_read1(base, SCSI_CSB_IN);
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_BUSFREE, "disconnect");
170062306a36Sopenharmony_ci		return TRUE;
170162306a36Sopenharmony_ci	} else {
170262306a36Sopenharmony_ci		/* Unexpected bus free */
170362306a36Sopenharmony_ci		nsp32_msg(KERN_WARNING, "unexpected bus free occurred");
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci		SCpnt->result = DID_ERROR << 16;
170662306a36Sopenharmony_ci		nsp32_scsi_done(SCpnt);
170762306a36Sopenharmony_ci		return TRUE;
170862306a36Sopenharmony_ci	}
170962306a36Sopenharmony_ci	return FALSE;
171062306a36Sopenharmony_ci}
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci/*
171462306a36Sopenharmony_ci * nsp32_adjust_busfree - adjusting SG table
171562306a36Sopenharmony_ci *
171662306a36Sopenharmony_ci * Note: This driver adjust the SG table using SCSI ACK
171762306a36Sopenharmony_ci *       counter instead of BMCNT counter!
171862306a36Sopenharmony_ci */
171962306a36Sopenharmony_cistatic void nsp32_adjust_busfree(struct scsi_cmnd *SCpnt, unsigned int s_sacklen)
172062306a36Sopenharmony_ci{
172162306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
172262306a36Sopenharmony_ci	int old_entry = data->cur_entry;
172362306a36Sopenharmony_ci	int new_entry;
172462306a36Sopenharmony_ci	int sg_num = data->cur_lunt->sg_num;
172562306a36Sopenharmony_ci	nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt;
172662306a36Sopenharmony_ci	unsigned int restlen, sentlen;
172762306a36Sopenharmony_ci	u32_le len, addr;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_SGLIST, "old resid=0x%x", scsi_get_resid(SCpnt));
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	/* adjust saved SACK count with 4 byte start address boundary */
173262306a36Sopenharmony_ci	s_sacklen -= le32_to_cpu(sgt[old_entry].addr) & 3;
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	/*
173562306a36Sopenharmony_ci	 * calculate new_entry from sack count and each sgt[].len
173662306a36Sopenharmony_ci	 * calculate the byte which is intent to send
173762306a36Sopenharmony_ci	 */
173862306a36Sopenharmony_ci	sentlen = 0;
173962306a36Sopenharmony_ci	for (new_entry = old_entry; new_entry < sg_num; new_entry++) {
174062306a36Sopenharmony_ci		sentlen += (le32_to_cpu(sgt[new_entry].len) & ~SGTEND);
174162306a36Sopenharmony_ci		if (sentlen > s_sacklen) {
174262306a36Sopenharmony_ci			break;
174362306a36Sopenharmony_ci		}
174462306a36Sopenharmony_ci	}
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	/* all sgt is processed */
174762306a36Sopenharmony_ci	if (new_entry == sg_num) {
174862306a36Sopenharmony_ci		goto last;
174962306a36Sopenharmony_ci	}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	if (sentlen == s_sacklen) {
175262306a36Sopenharmony_ci		/* XXX: confirm it's ok or not */
175362306a36Sopenharmony_ci		/* In this case, it's ok because we are at
175462306a36Sopenharmony_ci		 * the head element of the sg. restlen is correctly
175562306a36Sopenharmony_ci		 * calculated.
175662306a36Sopenharmony_ci		 */
175762306a36Sopenharmony_ci	}
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	/* calculate the rest length for transferring */
176062306a36Sopenharmony_ci	restlen = sentlen - s_sacklen;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	/* update adjusting current SG table entry */
176362306a36Sopenharmony_ci	len  = le32_to_cpu(sgt[new_entry].len);
176462306a36Sopenharmony_ci	addr = le32_to_cpu(sgt[new_entry].addr);
176562306a36Sopenharmony_ci	addr += (len - restlen);
176662306a36Sopenharmony_ci	sgt[new_entry].addr = cpu_to_le32(addr);
176762306a36Sopenharmony_ci	sgt[new_entry].len  = cpu_to_le32(restlen);
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	/* set cur_entry with new_entry */
177062306a36Sopenharmony_ci	data->cur_entry = new_entry;
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	return;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci last:
177562306a36Sopenharmony_ci	if (scsi_get_resid(SCpnt) < sentlen) {
177662306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "resid underflow");
177762306a36Sopenharmony_ci	}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) - sentlen);
178062306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_SGLIST, "new resid=0x%x", scsi_get_resid(SCpnt));
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	/* update hostdata and lun */
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	return;
178562306a36Sopenharmony_ci}
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci/*
178962306a36Sopenharmony_ci * It's called MsgOut phase occur.
179062306a36Sopenharmony_ci * NinjaSCSI-32Bi/UDE automatically processes up to 3 messages in
179162306a36Sopenharmony_ci * message out phase. It, however, has more than 3 messages,
179262306a36Sopenharmony_ci * HBA creates the interrupt and we have to process by hand.
179362306a36Sopenharmony_ci */
179462306a36Sopenharmony_cistatic void nsp32_msgout_occur(struct scsi_cmnd *SCpnt)
179562306a36Sopenharmony_ci{
179662306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
179762306a36Sopenharmony_ci	unsigned int base   = SCpnt->device->host->io_port;
179862306a36Sopenharmony_ci	int i;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,
180162306a36Sopenharmony_ci		  "enter: msgout_len: 0x%x", data->msgout_len);
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	/*
180462306a36Sopenharmony_ci	 * If MsgOut phase is occurred without having any
180562306a36Sopenharmony_ci	 * message, then No_Operation is sent (SCSI-2).
180662306a36Sopenharmony_ci	 */
180762306a36Sopenharmony_ci	if (data->msgout_len == 0) {
180862306a36Sopenharmony_ci		nsp32_build_nop(SCpnt);
180962306a36Sopenharmony_ci	}
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	/*
181262306a36Sopenharmony_ci	 * send messages
181362306a36Sopenharmony_ci	 */
181462306a36Sopenharmony_ci	for (i = 0; i < data->msgout_len; i++) {
181562306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,
181662306a36Sopenharmony_ci			  "%d : 0x%x", i, data->msgoutbuf[i]);
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci		/*
181962306a36Sopenharmony_ci		 * Check REQ is asserted.
182062306a36Sopenharmony_ci		 */
182162306a36Sopenharmony_ci		nsp32_wait_req(data, ASSERT);
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci		if (i == (data->msgout_len - 1)) {
182462306a36Sopenharmony_ci			/*
182562306a36Sopenharmony_ci			 * If the last message, set the AutoSCSI restart
182662306a36Sopenharmony_ci			 * before send back the ack message. AutoSCSI
182762306a36Sopenharmony_ci			 * restart automatically negate ATN signal.
182862306a36Sopenharmony_ci			 */
182962306a36Sopenharmony_ci			//command = (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);
183062306a36Sopenharmony_ci			//nsp32_restart_autoscsi(SCpnt, command);
183162306a36Sopenharmony_ci			nsp32_write2(base, COMMAND_CONTROL,
183262306a36Sopenharmony_ci					 (CLEAR_CDB_FIFO_POINTER |
183362306a36Sopenharmony_ci					  AUTO_COMMAND_PHASE |
183462306a36Sopenharmony_ci					  AUTOSCSI_RESTART |
183562306a36Sopenharmony_ci					  AUTO_MSGIN_00_OR_04 |
183662306a36Sopenharmony_ci					  AUTO_MSGIN_02 ));
183762306a36Sopenharmony_ci		}
183862306a36Sopenharmony_ci		/*
183962306a36Sopenharmony_ci		 * Write data with SACK, then wait sack is
184062306a36Sopenharmony_ci		 * automatically negated.
184162306a36Sopenharmony_ci		 */
184262306a36Sopenharmony_ci		nsp32_write1(base, SCSI_DATA_WITH_ACK, data->msgoutbuf[i]);
184362306a36Sopenharmony_ci		nsp32_wait_sack(data, NEGATE);
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "bus: 0x%x\n",
184662306a36Sopenharmony_ci			  nsp32_read1(base, SCSI_BUS_MONITOR));
184762306a36Sopenharmony_ci	}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	data->msgout_len = 0;
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "exit");
185262306a36Sopenharmony_ci}
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci/*
185562306a36Sopenharmony_ci * Restart AutoSCSI
185662306a36Sopenharmony_ci *
185762306a36Sopenharmony_ci * Note: Restarting AutoSCSI needs set:
185862306a36Sopenharmony_ci *		SYNC_REG, ACK_WIDTH, SGT_ADR, TRANSFER_CONTROL
185962306a36Sopenharmony_ci */
186062306a36Sopenharmony_cistatic void nsp32_restart_autoscsi(struct scsi_cmnd *SCpnt, unsigned short command)
186162306a36Sopenharmony_ci{
186262306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
186362306a36Sopenharmony_ci	unsigned int   base = data->BaseAddress;
186462306a36Sopenharmony_ci	unsigned short transfer = 0;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_RESTART, "enter");
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	if (data->cur_target == NULL || data->cur_lunt == NULL) {
186962306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "Target or Lun is invalid");
187062306a36Sopenharmony_ci	}
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	/*
187362306a36Sopenharmony_ci	 * set SYNC_REG
187462306a36Sopenharmony_ci	 * Don't set BM_START_ADR before setting this register.
187562306a36Sopenharmony_ci	 */
187662306a36Sopenharmony_ci	nsp32_write1(base, SYNC_REG, data->cur_target->syncreg);
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	/*
187962306a36Sopenharmony_ci	 * set ACKWIDTH
188062306a36Sopenharmony_ci	 */
188162306a36Sopenharmony_ci	nsp32_write1(base, ACK_WIDTH, data->cur_target->ackwidth);
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	/*
188462306a36Sopenharmony_ci	 * set SREQ hazard killer sampling rate
188562306a36Sopenharmony_ci	 */
188662306a36Sopenharmony_ci	nsp32_write1(base, SREQ_SMPL_RATE, data->cur_target->sample_reg);
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	/*
188962306a36Sopenharmony_ci	 * set SGT ADDR (physical address)
189062306a36Sopenharmony_ci	 */
189162306a36Sopenharmony_ci	nsp32_write4(base, SGT_ADR, data->cur_lunt->sglun_paddr);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	/*
189462306a36Sopenharmony_ci	 * set TRANSFER CONTROL REG
189562306a36Sopenharmony_ci	 */
189662306a36Sopenharmony_ci	transfer = 0;
189762306a36Sopenharmony_ci	transfer |= (TRANSFER_GO | ALL_COUNTER_CLR);
189862306a36Sopenharmony_ci	if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
189962306a36Sopenharmony_ci		if (scsi_bufflen(SCpnt) > 0) {
190062306a36Sopenharmony_ci			transfer |= BM_START;
190162306a36Sopenharmony_ci		}
190262306a36Sopenharmony_ci	} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
190362306a36Sopenharmony_ci		transfer |= CB_MMIO_MODE;
190462306a36Sopenharmony_ci	} else if (data->trans_method & NSP32_TRANSFER_PIO) {
190562306a36Sopenharmony_ci		transfer |= CB_IO_MODE;
190662306a36Sopenharmony_ci	}
190762306a36Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL, transfer);
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	/*
191062306a36Sopenharmony_ci	 * restart AutoSCSI
191162306a36Sopenharmony_ci	 *
191262306a36Sopenharmony_ci	 * TODO: COMMANDCONTROL_AUTO_COMMAND_PHASE is needed ?
191362306a36Sopenharmony_ci	 */
191462306a36Sopenharmony_ci	command |= (CLEAR_CDB_FIFO_POINTER |
191562306a36Sopenharmony_ci		    AUTO_COMMAND_PHASE     |
191662306a36Sopenharmony_ci		    AUTOSCSI_RESTART       );
191762306a36Sopenharmony_ci	nsp32_write2(base, COMMAND_CONTROL, command);
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_RESTART, "exit");
192062306a36Sopenharmony_ci}
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci/*
192462306a36Sopenharmony_ci * cannot run automatically message in occur
192562306a36Sopenharmony_ci */
192662306a36Sopenharmony_cistatic void nsp32_msgin_occur(struct scsi_cmnd     *SCpnt,
192762306a36Sopenharmony_ci			      unsigned long  irq_status,
192862306a36Sopenharmony_ci			      unsigned short execph)
192962306a36Sopenharmony_ci{
193062306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
193162306a36Sopenharmony_ci	unsigned int   base = SCpnt->device->host->io_port;
193262306a36Sopenharmony_ci	unsigned char  msg;
193362306a36Sopenharmony_ci	unsigned char  msgtype;
193462306a36Sopenharmony_ci	unsigned char  newlun;
193562306a36Sopenharmony_ci	unsigned short command  = 0;
193662306a36Sopenharmony_ci	int	       msgclear = TRUE;
193762306a36Sopenharmony_ci	long	       new_sgtp;
193862306a36Sopenharmony_ci	int	       ret;
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci	/*
194162306a36Sopenharmony_ci	 * read first message
194262306a36Sopenharmony_ci	 *    Use SCSIDATA_W_ACK instead of SCSIDATAIN, because the procedure
194362306a36Sopenharmony_ci	 *    of Message-In have to be processed before sending back SCSI ACK.
194462306a36Sopenharmony_ci	 */
194562306a36Sopenharmony_ci	msg = nsp32_read1(base, SCSI_DATA_IN);
194662306a36Sopenharmony_ci	data->msginbuf[(unsigned char)data->msgin_len] = msg;
194762306a36Sopenharmony_ci	msgtype = data->msginbuf[0];
194862306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR,
194962306a36Sopenharmony_ci		  "enter: msglen: 0x%x msgin: 0x%x msgtype: 0x%x",
195062306a36Sopenharmony_ci		  data->msgin_len, msg, msgtype);
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	/*
195362306a36Sopenharmony_ci	 * TODO: We need checking whether bus phase is message in?
195462306a36Sopenharmony_ci	 */
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	/*
195762306a36Sopenharmony_ci	 * assert SCSI ACK
195862306a36Sopenharmony_ci	 */
195962306a36Sopenharmony_ci	nsp32_sack_assert(data);
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	/*
196262306a36Sopenharmony_ci	 * processing IDENTIFY
196362306a36Sopenharmony_ci	 */
196462306a36Sopenharmony_ci	if (msgtype & 0x80) {
196562306a36Sopenharmony_ci		if (!(irq_status & IRQSTATUS_RESELECT_OCCUER)) {
196662306a36Sopenharmony_ci			/* Invalid (non reselect) phase */
196762306a36Sopenharmony_ci			goto reject;
196862306a36Sopenharmony_ci		}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci		newlun = msgtype & 0x1f; /* TODO: SPI-3 compliant? */
197162306a36Sopenharmony_ci		ret = nsp32_reselection(SCpnt, newlun);
197262306a36Sopenharmony_ci		if (ret == TRUE) {
197362306a36Sopenharmony_ci			goto restart;
197462306a36Sopenharmony_ci		} else {
197562306a36Sopenharmony_ci			goto reject;
197662306a36Sopenharmony_ci		}
197762306a36Sopenharmony_ci	}
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	/*
198062306a36Sopenharmony_ci	 * processing messages except for IDENTIFY
198162306a36Sopenharmony_ci	 *
198262306a36Sopenharmony_ci	 * TODO: Messages are all SCSI-2 terminology. SCSI-3 compliance is TODO.
198362306a36Sopenharmony_ci	 */
198462306a36Sopenharmony_ci	switch (msgtype) {
198562306a36Sopenharmony_ci	/*
198662306a36Sopenharmony_ci	 * 1-byte message
198762306a36Sopenharmony_ci	 */
198862306a36Sopenharmony_ci	case COMMAND_COMPLETE:
198962306a36Sopenharmony_ci	case DISCONNECT:
199062306a36Sopenharmony_ci		/*
199162306a36Sopenharmony_ci		 * These messages should not be occurred.
199262306a36Sopenharmony_ci		 * They should be processed on AutoSCSI sequencer.
199362306a36Sopenharmony_ci		 */
199462306a36Sopenharmony_ci		nsp32_msg(KERN_WARNING,
199562306a36Sopenharmony_ci			   "unexpected message of AutoSCSI MsgIn: 0x%x", msg);
199662306a36Sopenharmony_ci		break;
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	case RESTORE_POINTERS:
199962306a36Sopenharmony_ci		/*
200062306a36Sopenharmony_ci		 * AutoMsgIn03 is disabled, and HBA gets this message.
200162306a36Sopenharmony_ci		 */
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci		if ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE)) {
200462306a36Sopenharmony_ci			unsigned int s_sacklen;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);
200762306a36Sopenharmony_ci			if ((execph & MSGIN_02_VALID) && (s_sacklen > 0)) {
200862306a36Sopenharmony_ci				nsp32_adjust_busfree(SCpnt, s_sacklen);
200962306a36Sopenharmony_ci			} else {
201062306a36Sopenharmony_ci				/* No need to rewrite SGT */
201162306a36Sopenharmony_ci			}
201262306a36Sopenharmony_ci		}
201362306a36Sopenharmony_ci		data->cur_lunt->msgin03 = FALSE;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci		/* Update with the new value */
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci		/* reset SACK/SavedACK counter (or ALL clear?) */
201862306a36Sopenharmony_ci		nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci		/*
202162306a36Sopenharmony_ci		 * set new sg pointer
202262306a36Sopenharmony_ci		 */
202362306a36Sopenharmony_ci		new_sgtp = data->cur_lunt->sglun_paddr +
202462306a36Sopenharmony_ci			(data->cur_lunt->cur_entry * sizeof(nsp32_sgtable));
202562306a36Sopenharmony_ci		nsp32_write4(base, SGT_ADR, new_sgtp);
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci		break;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	case SAVE_POINTERS:
203062306a36Sopenharmony_ci		/*
203162306a36Sopenharmony_ci		 * These messages should not be occurred.
203262306a36Sopenharmony_ci		 * They should be processed on AutoSCSI sequencer.
203362306a36Sopenharmony_ci		 */
203462306a36Sopenharmony_ci		nsp32_msg (KERN_WARNING,
203562306a36Sopenharmony_ci			   "unexpected message of AutoSCSI MsgIn: SAVE_POINTERS");
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci		break;
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	case MESSAGE_REJECT:
204062306a36Sopenharmony_ci		/* If previous message_out is sending SDTR, and get
204162306a36Sopenharmony_ci		   message_reject from target, SDTR negotiation is failed */
204262306a36Sopenharmony_ci		if (data->cur_target->sync_flag &
204362306a36Sopenharmony_ci				(SDTR_INITIATOR | SDTR_TARGET)) {
204462306a36Sopenharmony_ci			/*
204562306a36Sopenharmony_ci			 * Current target is negotiating SDTR, but it's
204662306a36Sopenharmony_ci			 * failed.  Fall back to async transfer mode, and set
204762306a36Sopenharmony_ci			 * SDTR_DONE.
204862306a36Sopenharmony_ci			 */
204962306a36Sopenharmony_ci			nsp32_set_async(data, data->cur_target);
205062306a36Sopenharmony_ci			data->cur_target->sync_flag &= ~SDTR_INITIATOR;
205162306a36Sopenharmony_ci			data->cur_target->sync_flag |= SDTR_DONE;
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci		}
205462306a36Sopenharmony_ci		break;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	case LINKED_CMD_COMPLETE:
205762306a36Sopenharmony_ci	case LINKED_FLG_CMD_COMPLETE:
205862306a36Sopenharmony_ci		/* queue tag is not supported currently */
205962306a36Sopenharmony_ci		nsp32_msg (KERN_WARNING,
206062306a36Sopenharmony_ci			   "unsupported message: 0x%x", msgtype);
206162306a36Sopenharmony_ci		break;
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	case INITIATE_RECOVERY:
206462306a36Sopenharmony_ci		/* staring ECA (Extended Contingent Allegiance) state. */
206562306a36Sopenharmony_ci		/* This message is declined in SPI2 or later. */
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci		goto reject;
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	/*
207062306a36Sopenharmony_ci	 * 2-byte message
207162306a36Sopenharmony_ci	 */
207262306a36Sopenharmony_ci	case SIMPLE_QUEUE_TAG:
207362306a36Sopenharmony_ci	case 0x23:
207462306a36Sopenharmony_ci		/*
207562306a36Sopenharmony_ci		 * 0x23: Ignore_Wide_Residue is not declared in scsi.h.
207662306a36Sopenharmony_ci		 * No support is needed.
207762306a36Sopenharmony_ci		 */
207862306a36Sopenharmony_ci		if (data->msgin_len >= 1) {
207962306a36Sopenharmony_ci			goto reject;
208062306a36Sopenharmony_ci		}
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci		/* current position is 1-byte of 2 byte */
208362306a36Sopenharmony_ci		msgclear = FALSE;
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci		break;
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	/*
208862306a36Sopenharmony_ci	 * extended message
208962306a36Sopenharmony_ci	 */
209062306a36Sopenharmony_ci	case EXTENDED_MESSAGE:
209162306a36Sopenharmony_ci		if (data->msgin_len < 1) {
209262306a36Sopenharmony_ci			/*
209362306a36Sopenharmony_ci			 * Current position does not reach 2-byte
209462306a36Sopenharmony_ci			 * (2-byte is extended message length).
209562306a36Sopenharmony_ci			 */
209662306a36Sopenharmony_ci			msgclear = FALSE;
209762306a36Sopenharmony_ci			break;
209862306a36Sopenharmony_ci		}
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci		if ((data->msginbuf[1] + 1) > data->msgin_len) {
210162306a36Sopenharmony_ci			/*
210262306a36Sopenharmony_ci			 * Current extended message has msginbuf[1] + 2
210362306a36Sopenharmony_ci			 * (msgin_len starts counting from 0, so buf[1] + 1).
210462306a36Sopenharmony_ci			 * If current message position is not finished,
210562306a36Sopenharmony_ci			 * continue receiving message.
210662306a36Sopenharmony_ci			 */
210762306a36Sopenharmony_ci			msgclear = FALSE;
210862306a36Sopenharmony_ci			break;
210962306a36Sopenharmony_ci		}
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci		/*
211262306a36Sopenharmony_ci		 * Reach here means regular length of each type of
211362306a36Sopenharmony_ci		 * extended messages.
211462306a36Sopenharmony_ci		 */
211562306a36Sopenharmony_ci		switch (data->msginbuf[2]) {
211662306a36Sopenharmony_ci		case EXTENDED_MODIFY_DATA_POINTER:
211762306a36Sopenharmony_ci			/* TODO */
211862306a36Sopenharmony_ci			goto reject; /* not implemented yet */
211962306a36Sopenharmony_ci			break;
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci		case EXTENDED_SDTR:
212262306a36Sopenharmony_ci			/*
212362306a36Sopenharmony_ci			 * Exchange this message between initiator and target.
212462306a36Sopenharmony_ci			 */
212562306a36Sopenharmony_ci			if (data->msgin_len != EXTENDED_SDTR_LEN + 1) {
212662306a36Sopenharmony_ci				/*
212762306a36Sopenharmony_ci				 * received inappropriate message.
212862306a36Sopenharmony_ci				 */
212962306a36Sopenharmony_ci				goto reject;
213062306a36Sopenharmony_ci				break;
213162306a36Sopenharmony_ci			}
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci			nsp32_analyze_sdtr(SCpnt);
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci			break;
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci		case EXTENDED_EXTENDED_IDENTIFY:
213862306a36Sopenharmony_ci			/* SCSI-I only, not supported. */
213962306a36Sopenharmony_ci			goto reject; /* not implemented yet */
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci			break;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci		case EXTENDED_WDTR:
214462306a36Sopenharmony_ci			goto reject; /* not implemented yet */
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci			break;
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci		default:
214962306a36Sopenharmony_ci			goto reject;
215062306a36Sopenharmony_ci		}
215162306a36Sopenharmony_ci		break;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	default:
215462306a36Sopenharmony_ci		goto reject;
215562306a36Sopenharmony_ci	}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci restart:
215862306a36Sopenharmony_ci	if (msgclear == TRUE) {
215962306a36Sopenharmony_ci		data->msgin_len = 0;
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci		/*
216262306a36Sopenharmony_ci		 * If restarting AutoSCSI, but there are some message to out
216362306a36Sopenharmony_ci		 * (msgout_len > 0), set AutoATN, and set SCSIMSGOUT as 0
216462306a36Sopenharmony_ci		 * (MV_VALID = 0). When commandcontrol is written with
216562306a36Sopenharmony_ci		 * AutoSCSI restart, at the same time MsgOutOccur should be
216662306a36Sopenharmony_ci		 * happened (however, such situation is really possible...?).
216762306a36Sopenharmony_ci		 */
216862306a36Sopenharmony_ci		if (data->msgout_len > 0) {
216962306a36Sopenharmony_ci			nsp32_write4(base, SCSI_MSG_OUT, 0);
217062306a36Sopenharmony_ci			command |= AUTO_ATN;
217162306a36Sopenharmony_ci		}
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci		/*
217462306a36Sopenharmony_ci		 * restart AutoSCSI
217562306a36Sopenharmony_ci		 * If it's failed, COMMANDCONTROL_AUTO_COMMAND_PHASE is needed.
217662306a36Sopenharmony_ci		 */
217762306a36Sopenharmony_ci		command |= (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci		/*
218062306a36Sopenharmony_ci		 * If current msgin03 is TRUE, then flag on.
218162306a36Sopenharmony_ci		 */
218262306a36Sopenharmony_ci		if (data->cur_lunt->msgin03 == TRUE) {
218362306a36Sopenharmony_ci			command |= AUTO_MSGIN_03;
218462306a36Sopenharmony_ci		}
218562306a36Sopenharmony_ci		data->cur_lunt->msgin03 = FALSE;
218662306a36Sopenharmony_ci	} else {
218762306a36Sopenharmony_ci		data->msgin_len++;
218862306a36Sopenharmony_ci	}
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	/*
219162306a36Sopenharmony_ci	 * restart AutoSCSI
219262306a36Sopenharmony_ci	 */
219362306a36Sopenharmony_ci	nsp32_restart_autoscsi(SCpnt, command);
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci	/*
219662306a36Sopenharmony_ci	 * wait SCSI REQ negate for REQ-ACK handshake
219762306a36Sopenharmony_ci	 */
219862306a36Sopenharmony_ci	nsp32_wait_req(data, NEGATE);
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	/*
220162306a36Sopenharmony_ci	 * negate SCSI ACK
220262306a36Sopenharmony_ci	 */
220362306a36Sopenharmony_ci	nsp32_sack_negate(data);
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit");
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	return;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci reject:
221062306a36Sopenharmony_ci	nsp32_msg(KERN_WARNING,
221162306a36Sopenharmony_ci		  "invalid or unsupported MessageIn, rejected. "
221262306a36Sopenharmony_ci		  "current msg: 0x%x (len: 0x%x), processing msg: 0x%x",
221362306a36Sopenharmony_ci		  msg, data->msgin_len, msgtype);
221462306a36Sopenharmony_ci	nsp32_build_reject(SCpnt);
221562306a36Sopenharmony_ci	data->msgin_len = 0;
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci	goto restart;
221862306a36Sopenharmony_ci}
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci/*
222162306a36Sopenharmony_ci *
222262306a36Sopenharmony_ci */
222362306a36Sopenharmony_cistatic void nsp32_analyze_sdtr(struct scsi_cmnd *SCpnt)
222462306a36Sopenharmony_ci{
222562306a36Sopenharmony_ci	nsp32_hw_data   *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
222662306a36Sopenharmony_ci	nsp32_target    *target     = data->cur_target;
222762306a36Sopenharmony_ci	unsigned char    get_period = data->msginbuf[3];
222862306a36Sopenharmony_ci	unsigned char    get_offset = data->msginbuf[4];
222962306a36Sopenharmony_ci	int		 entry;
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "enter");
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci	/*
223462306a36Sopenharmony_ci	 * If this inititor sent the SDTR message, then target responds SDTR,
223562306a36Sopenharmony_ci	 * initiator SYNCREG, ACKWIDTH from SDTR parameter.
223662306a36Sopenharmony_ci	 * Messages are not appropriate, then send back reject message.
223762306a36Sopenharmony_ci	 * If initiator did not send the SDTR, but target sends SDTR,
223862306a36Sopenharmony_ci	 * initiator calculator the appropriate parameter and send back SDTR.
223962306a36Sopenharmony_ci	 */
224062306a36Sopenharmony_ci	if (target->sync_flag & SDTR_INITIATOR) {
224162306a36Sopenharmony_ci		/*
224262306a36Sopenharmony_ci		 * Initiator sent SDTR, the target responds and
224362306a36Sopenharmony_ci		 * send back negotiation SDTR.
224462306a36Sopenharmony_ci		 */
224562306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target responds SDTR");
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci		target->sync_flag &= ~SDTR_INITIATOR;
224862306a36Sopenharmony_ci		target->sync_flag |= SDTR_DONE;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci		/*
225162306a36Sopenharmony_ci		 * offset:
225262306a36Sopenharmony_ci		 */
225362306a36Sopenharmony_ci		if (get_offset > SYNC_OFFSET) {
225462306a36Sopenharmony_ci			/*
225562306a36Sopenharmony_ci			 * Negotiation is failed, the target send back
225662306a36Sopenharmony_ci			 * unexpected offset value.
225762306a36Sopenharmony_ci			 */
225862306a36Sopenharmony_ci			goto reject;
225962306a36Sopenharmony_ci		}
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci		if (get_offset == ASYNC_OFFSET) {
226262306a36Sopenharmony_ci			/*
226362306a36Sopenharmony_ci			 * Negotiation is succeeded, the target want
226462306a36Sopenharmony_ci			 * to fall back into asynchronous transfer mode.
226562306a36Sopenharmony_ci			 */
226662306a36Sopenharmony_ci			goto async;
226762306a36Sopenharmony_ci		}
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci		/*
227062306a36Sopenharmony_ci		 * period:
227162306a36Sopenharmony_ci		 *    Check whether sync period is too short. If too short,
227262306a36Sopenharmony_ci		 *    fall back to async mode. If it's ok, then investigate
227362306a36Sopenharmony_ci		 *    the received sync period. If sync period is acceptable
227462306a36Sopenharmony_ci		 *    between sync table start_period and end_period, then
227562306a36Sopenharmony_ci		 *    set this I_T nexus as sent offset and period.
227662306a36Sopenharmony_ci		 *    If it's not acceptable, send back reject and fall back
227762306a36Sopenharmony_ci		 *    to async mode.
227862306a36Sopenharmony_ci		 */
227962306a36Sopenharmony_ci		if (get_period < data->synct[0].period_num) {
228062306a36Sopenharmony_ci			/*
228162306a36Sopenharmony_ci			 * Negotiation is failed, the target send back
228262306a36Sopenharmony_ci			 * unexpected period value.
228362306a36Sopenharmony_ci			 */
228462306a36Sopenharmony_ci			goto reject;
228562306a36Sopenharmony_ci		}
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci		entry = nsp32_search_period_entry(data, target, get_period);
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci		if (entry < 0) {
229062306a36Sopenharmony_ci			/*
229162306a36Sopenharmony_ci			 * Target want to use long period which is not
229262306a36Sopenharmony_ci			 * acceptable NinjaSCSI-32Bi/UDE.
229362306a36Sopenharmony_ci			 */
229462306a36Sopenharmony_ci			goto reject;
229562306a36Sopenharmony_ci		}
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ci		/*
229862306a36Sopenharmony_ci		 * Set new sync table and offset in this I_T nexus.
229962306a36Sopenharmony_ci		 */
230062306a36Sopenharmony_ci		nsp32_set_sync_entry(data, target, entry, get_offset);
230162306a36Sopenharmony_ci	} else {
230262306a36Sopenharmony_ci		/* Target send SDTR to initiator. */
230362306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target send SDTR");
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci		target->sync_flag |= SDTR_INITIATOR;
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci		/* offset: */
230862306a36Sopenharmony_ci		if (get_offset > SYNC_OFFSET) {
230962306a36Sopenharmony_ci			/* send back as SYNC_OFFSET */
231062306a36Sopenharmony_ci			get_offset = SYNC_OFFSET;
231162306a36Sopenharmony_ci		}
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci		/* period: */
231462306a36Sopenharmony_ci		if (get_period < data->synct[0].period_num) {
231562306a36Sopenharmony_ci			get_period = data->synct[0].period_num;
231662306a36Sopenharmony_ci		}
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci		entry = nsp32_search_period_entry(data, target, get_period);
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ci		if (get_offset == ASYNC_OFFSET || entry < 0) {
232162306a36Sopenharmony_ci			nsp32_set_async(data, target);
232262306a36Sopenharmony_ci			nsp32_build_sdtr(SCpnt, 0, ASYNC_OFFSET);
232362306a36Sopenharmony_ci		} else {
232462306a36Sopenharmony_ci			nsp32_set_sync_entry(data, target, entry, get_offset);
232562306a36Sopenharmony_ci			nsp32_build_sdtr(SCpnt, get_period, get_offset);
232662306a36Sopenharmony_ci		}
232762306a36Sopenharmony_ci	}
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	target->period = get_period;
233062306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit");
233162306a36Sopenharmony_ci	return;
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci reject:
233462306a36Sopenharmony_ci	/*
233562306a36Sopenharmony_ci	 * If the current message is unacceptable, send back to the target
233662306a36Sopenharmony_ci	 * with reject message.
233762306a36Sopenharmony_ci	 */
233862306a36Sopenharmony_ci	nsp32_build_reject(SCpnt);
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci async:
234162306a36Sopenharmony_ci	nsp32_set_async(data, target);	/* set as ASYNC transfer mode */
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	target->period = 0;
234462306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit: set async");
234562306a36Sopenharmony_ci	return;
234662306a36Sopenharmony_ci}
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci/*
235062306a36Sopenharmony_ci * Search config entry number matched in sync_table from given
235162306a36Sopenharmony_ci * target and speed period value. If failed to search, return negative value.
235262306a36Sopenharmony_ci */
235362306a36Sopenharmony_cistatic int nsp32_search_period_entry(nsp32_hw_data *data,
235462306a36Sopenharmony_ci				     nsp32_target  *target,
235562306a36Sopenharmony_ci				     unsigned char  period)
235662306a36Sopenharmony_ci{
235762306a36Sopenharmony_ci	int i;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	if (target->limit_entry >= data->syncnum) {
236062306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "limit_entry exceeds syncnum!");
236162306a36Sopenharmony_ci		target->limit_entry = 0;
236262306a36Sopenharmony_ci	}
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	for (i = target->limit_entry; i < data->syncnum; i++) {
236562306a36Sopenharmony_ci		if (period >= data->synct[i].start_period &&
236662306a36Sopenharmony_ci		    period <= data->synct[i].end_period) {
236762306a36Sopenharmony_ci				break;
236862306a36Sopenharmony_ci		}
236962306a36Sopenharmony_ci	}
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	/*
237262306a36Sopenharmony_ci	 * Check given period value is over the sync_table value.
237362306a36Sopenharmony_ci	 * If so, return max value.
237462306a36Sopenharmony_ci	 */
237562306a36Sopenharmony_ci	if (i == data->syncnum) {
237662306a36Sopenharmony_ci		i = -1;
237762306a36Sopenharmony_ci	}
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	return i;
238062306a36Sopenharmony_ci}
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci/*
238462306a36Sopenharmony_ci * target <-> initiator use ASYNC transfer
238562306a36Sopenharmony_ci */
238662306a36Sopenharmony_cistatic void nsp32_set_async(nsp32_hw_data *data, nsp32_target *target)
238762306a36Sopenharmony_ci{
238862306a36Sopenharmony_ci	unsigned char period = data->synct[target->limit_entry].period_num;
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci	target->offset     = ASYNC_OFFSET;
239162306a36Sopenharmony_ci	target->period     = 0;
239262306a36Sopenharmony_ci	target->syncreg    = TO_SYNCREG(period, ASYNC_OFFSET);
239362306a36Sopenharmony_ci	target->ackwidth   = 0;
239462306a36Sopenharmony_ci	target->sample_reg = 0;
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_SYNC, "set async");
239762306a36Sopenharmony_ci}
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci/*
240162306a36Sopenharmony_ci * target <-> initiator use maximum SYNC transfer
240262306a36Sopenharmony_ci */
240362306a36Sopenharmony_cistatic void nsp32_set_max_sync(nsp32_hw_data *data,
240462306a36Sopenharmony_ci			       nsp32_target  *target,
240562306a36Sopenharmony_ci			       unsigned char *period,
240662306a36Sopenharmony_ci			       unsigned char *offset)
240762306a36Sopenharmony_ci{
240862306a36Sopenharmony_ci	unsigned char period_num, ackwidth;
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	period_num = data->synct[target->limit_entry].period_num;
241162306a36Sopenharmony_ci	*period    = data->synct[target->limit_entry].start_period;
241262306a36Sopenharmony_ci	ackwidth   = data->synct[target->limit_entry].ackwidth;
241362306a36Sopenharmony_ci	*offset    = SYNC_OFFSET;
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	target->syncreg    = TO_SYNCREG(period_num, *offset);
241662306a36Sopenharmony_ci	target->ackwidth   = ackwidth;
241762306a36Sopenharmony_ci	target->offset     = *offset;
241862306a36Sopenharmony_ci	target->sample_reg = 0;       /* disable SREQ sampling */
241962306a36Sopenharmony_ci}
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci/*
242362306a36Sopenharmony_ci * target <-> initiator use entry number speed
242462306a36Sopenharmony_ci */
242562306a36Sopenharmony_cistatic void nsp32_set_sync_entry(nsp32_hw_data *data,
242662306a36Sopenharmony_ci				 nsp32_target  *target,
242762306a36Sopenharmony_ci				 int		entry,
242862306a36Sopenharmony_ci				 unsigned char  offset)
242962306a36Sopenharmony_ci{
243062306a36Sopenharmony_ci	unsigned char period, ackwidth, sample_rate;
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci	period      = data->synct[entry].period_num;
243362306a36Sopenharmony_ci	ackwidth    = data->synct[entry].ackwidth;
243462306a36Sopenharmony_ci	sample_rate = data->synct[entry].sample_rate;
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci	target->syncreg    = TO_SYNCREG(period, offset);
243762306a36Sopenharmony_ci	target->ackwidth   = ackwidth;
243862306a36Sopenharmony_ci	target->offset     = offset;
243962306a36Sopenharmony_ci	target->sample_reg = sample_rate | SAMPLING_ENABLE;
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_SYNC, "set sync");
244262306a36Sopenharmony_ci}
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci/*
244662306a36Sopenharmony_ci * It waits until SCSI REQ becomes assertion or negation state.
244762306a36Sopenharmony_ci *
244862306a36Sopenharmony_ci * Note: If nsp32_msgin_occur is called, we asserts SCSI ACK. Then
244962306a36Sopenharmony_ci *     connected target responds SCSI REQ negation.  We have to wait
245062306a36Sopenharmony_ci *     SCSI REQ becomes negation in order to negate SCSI ACK signal for
245162306a36Sopenharmony_ci *     REQ-ACK handshake.
245262306a36Sopenharmony_ci */
245362306a36Sopenharmony_cistatic void nsp32_wait_req(nsp32_hw_data *data, int state)
245462306a36Sopenharmony_ci{
245562306a36Sopenharmony_ci	unsigned int  base      = data->BaseAddress;
245662306a36Sopenharmony_ci	int	      wait_time = 0;
245762306a36Sopenharmony_ci	unsigned char bus, req_bit;
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	if (!((state == ASSERT) || (state == NEGATE))) {
246062306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "unknown state designation");
246162306a36Sopenharmony_ci	}
246262306a36Sopenharmony_ci	/* REQ is BIT(5) */
246362306a36Sopenharmony_ci	req_bit = (state == ASSERT ? BUSMON_REQ : 0);
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	do {
246662306a36Sopenharmony_ci		bus = nsp32_read1(base, SCSI_BUS_MONITOR);
246762306a36Sopenharmony_ci		if ((bus & BUSMON_REQ) == req_bit) {
246862306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_WAIT,
246962306a36Sopenharmony_ci				  "wait_time: %d", wait_time);
247062306a36Sopenharmony_ci			return;
247162306a36Sopenharmony_ci		}
247262306a36Sopenharmony_ci		udelay(1);
247362306a36Sopenharmony_ci		wait_time++;
247462306a36Sopenharmony_ci	} while (wait_time < REQSACK_TIMEOUT_TIME);
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci	nsp32_msg(KERN_WARNING, "wait REQ timeout, req_bit: 0x%x", req_bit);
247762306a36Sopenharmony_ci}
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci/*
248062306a36Sopenharmony_ci * It waits until SCSI SACK becomes assertion or negation state.
248162306a36Sopenharmony_ci */
248262306a36Sopenharmony_cistatic void nsp32_wait_sack(nsp32_hw_data *data, int state)
248362306a36Sopenharmony_ci{
248462306a36Sopenharmony_ci	unsigned int  base      = data->BaseAddress;
248562306a36Sopenharmony_ci	int	      wait_time = 0;
248662306a36Sopenharmony_ci	unsigned char bus, ack_bit;
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	if (!((state == ASSERT) || (state == NEGATE))) {
248962306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "unknown state designation");
249062306a36Sopenharmony_ci	}
249162306a36Sopenharmony_ci	/* ACK is BIT(4) */
249262306a36Sopenharmony_ci	ack_bit = (state == ASSERT ? BUSMON_ACK : 0);
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci	do {
249562306a36Sopenharmony_ci		bus = nsp32_read1(base, SCSI_BUS_MONITOR);
249662306a36Sopenharmony_ci		if ((bus & BUSMON_ACK) == ack_bit) {
249762306a36Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_WAIT,
249862306a36Sopenharmony_ci				  "wait_time: %d", wait_time);
249962306a36Sopenharmony_ci			return;
250062306a36Sopenharmony_ci		}
250162306a36Sopenharmony_ci		udelay(1);
250262306a36Sopenharmony_ci		wait_time++;
250362306a36Sopenharmony_ci	} while (wait_time < REQSACK_TIMEOUT_TIME);
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	nsp32_msg(KERN_WARNING, "wait SACK timeout, ack_bit: 0x%x", ack_bit);
250662306a36Sopenharmony_ci}
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci/*
250962306a36Sopenharmony_ci * assert SCSI ACK
251062306a36Sopenharmony_ci *
251162306a36Sopenharmony_ci * Note: SCSI ACK assertion needs with ACKENB=1, AUTODIRECTION=1.
251262306a36Sopenharmony_ci */
251362306a36Sopenharmony_cistatic void nsp32_sack_assert(nsp32_hw_data *data)
251462306a36Sopenharmony_ci{
251562306a36Sopenharmony_ci	unsigned int  base = data->BaseAddress;
251662306a36Sopenharmony_ci	unsigned char busctrl;
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci	busctrl  = nsp32_read1(base, SCSI_BUS_CONTROL);
251962306a36Sopenharmony_ci	busctrl	|= (BUSCTL_ACK | AUTODIRECTION | ACKENB);
252062306a36Sopenharmony_ci	nsp32_write1(base, SCSI_BUS_CONTROL, busctrl);
252162306a36Sopenharmony_ci}
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci/*
252462306a36Sopenharmony_ci * negate SCSI ACK
252562306a36Sopenharmony_ci */
252662306a36Sopenharmony_cistatic void nsp32_sack_negate(nsp32_hw_data *data)
252762306a36Sopenharmony_ci{
252862306a36Sopenharmony_ci	unsigned int  base = data->BaseAddress;
252962306a36Sopenharmony_ci	unsigned char busctrl;
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci	busctrl  = nsp32_read1(base, SCSI_BUS_CONTROL);
253262306a36Sopenharmony_ci	busctrl	&= ~BUSCTL_ACK;
253362306a36Sopenharmony_ci	nsp32_write1(base, SCSI_BUS_CONTROL, busctrl);
253462306a36Sopenharmony_ci}
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci/*
253962306a36Sopenharmony_ci * Note: n_io_port is defined as 0x7f because I/O register port is
254062306a36Sopenharmony_ci *	 assigned as:
254162306a36Sopenharmony_ci *	0x800-0x8ff: memory mapped I/O port
254262306a36Sopenharmony_ci *	0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly)
254362306a36Sopenharmony_ci *	0xc00-0xfff: CardBus status registers
254462306a36Sopenharmony_ci */
254562306a36Sopenharmony_cistatic int nsp32_detect(struct pci_dev *pdev)
254662306a36Sopenharmony_ci{
254762306a36Sopenharmony_ci	struct Scsi_Host *host;	/* registered host structure */
254862306a36Sopenharmony_ci	struct resource  *res;
254962306a36Sopenharmony_ci	nsp32_hw_data    *data;
255062306a36Sopenharmony_ci	int		  ret;
255162306a36Sopenharmony_ci	int		  i, j;
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	/*
255662306a36Sopenharmony_ci	 * register this HBA as SCSI device
255762306a36Sopenharmony_ci	 */
255862306a36Sopenharmony_ci	host = scsi_host_alloc(&nsp32_template, sizeof(nsp32_hw_data));
255962306a36Sopenharmony_ci	if (host == NULL) {
256062306a36Sopenharmony_ci		nsp32_msg (KERN_ERR, "failed to scsi register");
256162306a36Sopenharmony_ci		goto err;
256262306a36Sopenharmony_ci	}
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_ci	/*
256562306a36Sopenharmony_ci	 * set nsp32_hw_data
256662306a36Sopenharmony_ci	 */
256762306a36Sopenharmony_ci	data = (nsp32_hw_data *)host->hostdata;
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	memcpy(data, &nsp32_data_base, sizeof(nsp32_hw_data));
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	host->irq       = data->IrqNumber;
257262306a36Sopenharmony_ci	host->io_port   = data->BaseAddress;
257362306a36Sopenharmony_ci	host->unique_id = data->BaseAddress;
257462306a36Sopenharmony_ci	host->n_io_port	= data->NumAddress;
257562306a36Sopenharmony_ci	host->base      = (unsigned long)data->MmioAddress;
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci	data->Host      = host;
257862306a36Sopenharmony_ci	spin_lock_init(&(data->Lock));
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	data->cur_lunt   = NULL;
258162306a36Sopenharmony_ci	data->cur_target = NULL;
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	/*
258462306a36Sopenharmony_ci	 * Bus master transfer mode is supported currently.
258562306a36Sopenharmony_ci	 */
258662306a36Sopenharmony_ci	data->trans_method = NSP32_TRANSFER_BUSMASTER;
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	/*
258962306a36Sopenharmony_ci	 * Set clock div, CLOCK_4 (HBA has own external clock, and
259062306a36Sopenharmony_ci	 * dividing * 100ns/4).
259162306a36Sopenharmony_ci	 * Currently CLOCK_4 has only tested, not for CLOCK_2/PCICLK yet.
259262306a36Sopenharmony_ci	 */
259362306a36Sopenharmony_ci	data->clock = CLOCK_4;
259462306a36Sopenharmony_ci
259562306a36Sopenharmony_ci	/*
259662306a36Sopenharmony_ci	 * Select appropriate nsp32_sync_table and set I_CLOCKDIV.
259762306a36Sopenharmony_ci	 */
259862306a36Sopenharmony_ci	switch (data->clock) {
259962306a36Sopenharmony_ci	case CLOCK_4:
260062306a36Sopenharmony_ci		/* If data->clock is CLOCK_4, then select 40M sync table. */
260162306a36Sopenharmony_ci		data->synct   = nsp32_sync_table_40M;
260262306a36Sopenharmony_ci		data->syncnum = ARRAY_SIZE(nsp32_sync_table_40M);
260362306a36Sopenharmony_ci		break;
260462306a36Sopenharmony_ci	case CLOCK_2:
260562306a36Sopenharmony_ci		/* If data->clock is CLOCK_2, then select 20M sync table. */
260662306a36Sopenharmony_ci		data->synct   = nsp32_sync_table_20M;
260762306a36Sopenharmony_ci		data->syncnum = ARRAY_SIZE(nsp32_sync_table_20M);
260862306a36Sopenharmony_ci		break;
260962306a36Sopenharmony_ci	case PCICLK:
261062306a36Sopenharmony_ci		/* If data->clock is PCICLK, then select pci sync table. */
261162306a36Sopenharmony_ci		data->synct   = nsp32_sync_table_pci;
261262306a36Sopenharmony_ci		data->syncnum = ARRAY_SIZE(nsp32_sync_table_pci);
261362306a36Sopenharmony_ci		break;
261462306a36Sopenharmony_ci	default:
261562306a36Sopenharmony_ci		nsp32_msg(KERN_WARNING,
261662306a36Sopenharmony_ci			  "Invalid clock div is selected, set CLOCK_4.");
261762306a36Sopenharmony_ci		/* Use default value CLOCK_4 */
261862306a36Sopenharmony_ci		data->clock   = CLOCK_4;
261962306a36Sopenharmony_ci		data->synct   = nsp32_sync_table_40M;
262062306a36Sopenharmony_ci		data->syncnum = ARRAY_SIZE(nsp32_sync_table_40M);
262162306a36Sopenharmony_ci	}
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci	/*
262462306a36Sopenharmony_ci	 * setup nsp32_lunt
262562306a36Sopenharmony_ci	 */
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	/*
262862306a36Sopenharmony_ci	 * setup DMA
262962306a36Sopenharmony_ci	 */
263062306a36Sopenharmony_ci	if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
263162306a36Sopenharmony_ci		nsp32_msg (KERN_ERR, "failed to set PCI DMA mask");
263262306a36Sopenharmony_ci		goto scsi_unregister;
263362306a36Sopenharmony_ci	}
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ci	/*
263662306a36Sopenharmony_ci	 * allocate autoparam DMA resource.
263762306a36Sopenharmony_ci	 */
263862306a36Sopenharmony_ci	data->autoparam = dma_alloc_coherent(&pdev->dev,
263962306a36Sopenharmony_ci			sizeof(nsp32_autoparam), &(data->auto_paddr),
264062306a36Sopenharmony_ci			GFP_KERNEL);
264162306a36Sopenharmony_ci	if (data->autoparam == NULL) {
264262306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
264362306a36Sopenharmony_ci		goto scsi_unregister;
264462306a36Sopenharmony_ci	}
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci	/*
264762306a36Sopenharmony_ci	 * allocate scatter-gather DMA resource.
264862306a36Sopenharmony_ci	 */
264962306a36Sopenharmony_ci	data->sg_list = dma_alloc_coherent(&pdev->dev, NSP32_SG_TABLE_SIZE,
265062306a36Sopenharmony_ci			&data->sg_paddr, GFP_KERNEL);
265162306a36Sopenharmony_ci	if (data->sg_list == NULL) {
265262306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
265362306a36Sopenharmony_ci		goto free_autoparam;
265462306a36Sopenharmony_ci	}
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->lunt); i++) {
265762306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(data->lunt[0]); j++) {
265862306a36Sopenharmony_ci			int offset = i * ARRAY_SIZE(data->lunt[0]) + j;
265962306a36Sopenharmony_ci			nsp32_lunt tmp = {
266062306a36Sopenharmony_ci				.SCpnt       = NULL,
266162306a36Sopenharmony_ci				.save_datp   = 0,
266262306a36Sopenharmony_ci				.msgin03     = FALSE,
266362306a36Sopenharmony_ci				.sg_num      = 0,
266462306a36Sopenharmony_ci				.cur_entry   = 0,
266562306a36Sopenharmony_ci				.sglun       = &(data->sg_list[offset]),
266662306a36Sopenharmony_ci				.sglun_paddr = data->sg_paddr + (offset * sizeof(nsp32_sglun)),
266762306a36Sopenharmony_ci			};
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci			data->lunt[i][j] = tmp;
267062306a36Sopenharmony_ci		}
267162306a36Sopenharmony_ci	}
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci	/*
267462306a36Sopenharmony_ci	 * setup target
267562306a36Sopenharmony_ci	 */
267662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->target); i++) {
267762306a36Sopenharmony_ci		nsp32_target *target = &(data->target[i]);
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci		target->limit_entry  = 0;
268062306a36Sopenharmony_ci		target->sync_flag    = 0;
268162306a36Sopenharmony_ci		nsp32_set_async(data, target);
268262306a36Sopenharmony_ci	}
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci	/*
268562306a36Sopenharmony_ci	 * EEPROM check
268662306a36Sopenharmony_ci	 */
268762306a36Sopenharmony_ci	ret = nsp32_getprom_param(data);
268862306a36Sopenharmony_ci	if (ret == FALSE) {
268962306a36Sopenharmony_ci		data->resettime = 3;	/* default 3 */
269062306a36Sopenharmony_ci	}
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	/*
269362306a36Sopenharmony_ci	 * setup HBA
269462306a36Sopenharmony_ci	 */
269562306a36Sopenharmony_ci	nsp32hw_init(data);
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	snprintf(data->info_str, sizeof(data->info_str),
269862306a36Sopenharmony_ci		 "NinjaSCSI-32Bi/UDE: irq %d, io 0x%lx+0x%x",
269962306a36Sopenharmony_ci		 host->irq, host->io_port, host->n_io_port);
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	/*
270262306a36Sopenharmony_ci	 * SCSI bus reset
270362306a36Sopenharmony_ci	 *
270462306a36Sopenharmony_ci	 * Note: It's important to reset SCSI bus in initialization phase.
270562306a36Sopenharmony_ci	 *     NinjaSCSI-32Bi/UDE HBA EEPROM seems to exchange SDTR when
270662306a36Sopenharmony_ci	 *     system is coming up, so SCSI devices connected to HBA is set as
270762306a36Sopenharmony_ci	 *     un-asynchronous mode.  It brings the merit that this HBA is
270862306a36Sopenharmony_ci	 *     ready to start synchronous transfer without any preparation,
270962306a36Sopenharmony_ci	 *     but we are difficult to control transfer speed.  In addition,
271062306a36Sopenharmony_ci	 *     it prevents device transfer speed from effecting EEPROM start-up
271162306a36Sopenharmony_ci	 *     SDTR.  NinjaSCSI-32Bi/UDE has the feature if EEPROM is set as
271262306a36Sopenharmony_ci	 *     Auto Mode, then FAST-10M is selected when SCSI devices are
271362306a36Sopenharmony_ci	 *     connected same or more than 4 devices.  It should be avoided
271462306a36Sopenharmony_ci	 *     depending on this specification. Thus, resetting the SCSI bus
271562306a36Sopenharmony_ci	 *     restores all connected SCSI devices to asynchronous mode, then
271662306a36Sopenharmony_ci	 *     this driver set SDTR safely later, and we can control all SCSI
271762306a36Sopenharmony_ci	 *     device transfer mode.
271862306a36Sopenharmony_ci	 */
271962306a36Sopenharmony_ci	nsp32_do_bus_reset(data);
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci	ret = request_irq(host->irq, do_nsp32_isr, IRQF_SHARED, "nsp32", data);
272262306a36Sopenharmony_ci	if (ret < 0) {
272362306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NinjaSCSI32 "
272462306a36Sopenharmony_ci			  "SCSI PCI controller. Interrupt: %d", host->irq);
272562306a36Sopenharmony_ci		goto free_sg_list;
272662306a36Sopenharmony_ci	}
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_ci	/*
272962306a36Sopenharmony_ci         * PCI IO register
273062306a36Sopenharmony_ci         */
273162306a36Sopenharmony_ci	res = request_region(host->io_port, host->n_io_port, "nsp32");
273262306a36Sopenharmony_ci	if (res == NULL) {
273362306a36Sopenharmony_ci		nsp32_msg(KERN_ERR,
273462306a36Sopenharmony_ci			  "I/O region 0x%x+0x%x is already used",
273562306a36Sopenharmony_ci			  data->BaseAddress, data->NumAddress);
273662306a36Sopenharmony_ci		goto free_irq;
273762306a36Sopenharmony_ci	}
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci	ret = scsi_add_host(host, &pdev->dev);
274062306a36Sopenharmony_ci	if (ret) {
274162306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "failed to add scsi host");
274262306a36Sopenharmony_ci		goto free_region;
274362306a36Sopenharmony_ci	}
274462306a36Sopenharmony_ci	scsi_scan_host(host);
274562306a36Sopenharmony_ci	pci_set_drvdata(pdev, host);
274662306a36Sopenharmony_ci	return 0;
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci free_region:
274962306a36Sopenharmony_ci	release_region(host->io_port, host->n_io_port);
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci free_irq:
275262306a36Sopenharmony_ci	free_irq(host->irq, data);
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_ci free_sg_list:
275562306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, NSP32_SG_TABLE_SIZE,
275662306a36Sopenharmony_ci			    data->sg_list, data->sg_paddr);
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci free_autoparam:
275962306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, sizeof(nsp32_autoparam),
276062306a36Sopenharmony_ci			    data->autoparam, data->auto_paddr);
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci scsi_unregister:
276362306a36Sopenharmony_ci	scsi_host_put(host);
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci err:
276662306a36Sopenharmony_ci	return 1;
276762306a36Sopenharmony_ci}
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_cistatic int nsp32_release(struct Scsi_Host *host)
277062306a36Sopenharmony_ci{
277162306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata;
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci	if (data->autoparam) {
277462306a36Sopenharmony_ci		dma_free_coherent(&data->Pci->dev, sizeof(nsp32_autoparam),
277562306a36Sopenharmony_ci				    data->autoparam, data->auto_paddr);
277662306a36Sopenharmony_ci	}
277762306a36Sopenharmony_ci
277862306a36Sopenharmony_ci	if (data->sg_list) {
277962306a36Sopenharmony_ci		dma_free_coherent(&data->Pci->dev, NSP32_SG_TABLE_SIZE,
278062306a36Sopenharmony_ci				    data->sg_list, data->sg_paddr);
278162306a36Sopenharmony_ci	}
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	if (host->irq) {
278462306a36Sopenharmony_ci		free_irq(host->irq, data);
278562306a36Sopenharmony_ci	}
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	if (host->io_port && host->n_io_port) {
278862306a36Sopenharmony_ci		release_region(host->io_port, host->n_io_port);
278962306a36Sopenharmony_ci	}
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ci	if (data->MmioAddress) {
279262306a36Sopenharmony_ci		iounmap(data->MmioAddress);
279362306a36Sopenharmony_ci	}
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_ci	return 0;
279662306a36Sopenharmony_ci}
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_cistatic const char *nsp32_info(struct Scsi_Host *shpnt)
279962306a36Sopenharmony_ci{
280062306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata;
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	return data->info_str;
280362306a36Sopenharmony_ci}
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci/****************************************************************************
280762306a36Sopenharmony_ci * error handler
280862306a36Sopenharmony_ci */
280962306a36Sopenharmony_cistatic int nsp32_eh_abort(struct scsi_cmnd *SCpnt)
281062306a36Sopenharmony_ci{
281162306a36Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
281262306a36Sopenharmony_ci	unsigned int   base = SCpnt->device->host->io_port;
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci	nsp32_msg(KERN_WARNING, "abort");
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_ci	if (data->cur_lunt->SCpnt == NULL) {
281762306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_BUSRESET, "abort failed");
281862306a36Sopenharmony_ci		return FAILED;
281962306a36Sopenharmony_ci	}
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci	if (data->cur_target->sync_flag & (SDTR_INITIATOR | SDTR_TARGET)) {
282262306a36Sopenharmony_ci		/* reset SDTR negotiation */
282362306a36Sopenharmony_ci		data->cur_target->sync_flag = 0;
282462306a36Sopenharmony_ci		nsp32_set_async(data, data->cur_target);
282562306a36Sopenharmony_ci	}
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL, 0);
282862306a36Sopenharmony_ci	nsp32_write2(base, BM_CNT, 0);
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci	SCpnt->result = DID_ABORT << 16;
283162306a36Sopenharmony_ci	nsp32_scsi_done(SCpnt);
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_BUSRESET, "abort success");
283462306a36Sopenharmony_ci	return SUCCESS;
283562306a36Sopenharmony_ci}
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_cistatic void nsp32_do_bus_reset(nsp32_hw_data *data)
283862306a36Sopenharmony_ci{
283962306a36Sopenharmony_ci	unsigned int   base = data->BaseAddress;
284062306a36Sopenharmony_ci	int i;
284162306a36Sopenharmony_ci	unsigned short __maybe_unused intrdat;
284262306a36Sopenharmony_ci
284362306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_BUSRESET, "in");
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	/*
284662306a36Sopenharmony_ci	 * stop all transfer
284762306a36Sopenharmony_ci	 * clear TRANSFERCONTROL_BM_START
284862306a36Sopenharmony_ci	 * clear counter
284962306a36Sopenharmony_ci	 */
285062306a36Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL, 0);
285162306a36Sopenharmony_ci	nsp32_write4(base, BM_CNT, 0);
285262306a36Sopenharmony_ci	nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci	/*
285562306a36Sopenharmony_ci	 * fall back to asynchronous transfer mode
285662306a36Sopenharmony_ci	 * initialize SDTR negotiation flag
285762306a36Sopenharmony_ci	 */
285862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->target); i++) {
285962306a36Sopenharmony_ci		nsp32_target *target = &data->target[i];
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci		target->sync_flag = 0;
286262306a36Sopenharmony_ci		nsp32_set_async(data, target);
286362306a36Sopenharmony_ci	}
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	/*
286662306a36Sopenharmony_ci	 * reset SCSI bus
286762306a36Sopenharmony_ci	 */
286862306a36Sopenharmony_ci	nsp32_write1(base, SCSI_BUS_CONTROL, BUSCTL_RST);
286962306a36Sopenharmony_ci	mdelay(RESET_HOLD_TIME / 1000);
287062306a36Sopenharmony_ci	nsp32_write1(base, SCSI_BUS_CONTROL, 0);
287162306a36Sopenharmony_ci	for(i = 0; i < 5; i++) {
287262306a36Sopenharmony_ci		intrdat = nsp32_read2(base, IRQ_STATUS); /* dummy read */
287362306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_BUSRESET, "irq:1: 0x%x", intrdat);
287462306a36Sopenharmony_ci	}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci	data->CurrentSC = NULL;
287762306a36Sopenharmony_ci}
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_cistatic int nsp32_eh_host_reset(struct scsi_cmnd *SCpnt)
288062306a36Sopenharmony_ci{
288162306a36Sopenharmony_ci	struct Scsi_Host *host = SCpnt->device->host;
288262306a36Sopenharmony_ci	unsigned int      base = SCpnt->device->host->io_port;
288362306a36Sopenharmony_ci	nsp32_hw_data    *data = (nsp32_hw_data *)host->hostdata;
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci	nsp32_msg(KERN_INFO, "Host Reset");
288662306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt);
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_ci	spin_lock_irq(SCpnt->device->host->host_lock);
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	nsp32hw_init(data);
289162306a36Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
289262306a36Sopenharmony_ci	nsp32_do_bus_reset(data);
289362306a36Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, 0);
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_ci	spin_unlock_irq(SCpnt->device->host->host_lock);
289662306a36Sopenharmony_ci	return SUCCESS;	/* Host reset is succeeded at any time. */
289762306a36Sopenharmony_ci}
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci/**************************************************************************
290162306a36Sopenharmony_ci * EEPROM handler
290262306a36Sopenharmony_ci */
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci/*
290562306a36Sopenharmony_ci * getting EEPROM parameter
290662306a36Sopenharmony_ci */
290762306a36Sopenharmony_cistatic int nsp32_getprom_param(nsp32_hw_data *data)
290862306a36Sopenharmony_ci{
290962306a36Sopenharmony_ci	int vendor = data->pci_devid->vendor;
291062306a36Sopenharmony_ci	int device = data->pci_devid->device;
291162306a36Sopenharmony_ci	int ret, i;
291262306a36Sopenharmony_ci	int __maybe_unused val;
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	/*
291562306a36Sopenharmony_ci	 * EEPROM checking.
291662306a36Sopenharmony_ci	 */
291762306a36Sopenharmony_ci	ret = nsp32_prom_read(data, 0x7e);
291862306a36Sopenharmony_ci	if (ret != 0x55) {
291962306a36Sopenharmony_ci		nsp32_msg(KERN_INFO, "No EEPROM detected: 0x%x", ret);
292062306a36Sopenharmony_ci		return FALSE;
292162306a36Sopenharmony_ci	}
292262306a36Sopenharmony_ci	ret = nsp32_prom_read(data, 0x7f);
292362306a36Sopenharmony_ci	if (ret != 0xaa) {
292462306a36Sopenharmony_ci		nsp32_msg(KERN_INFO, "Invalid number: 0x%x", ret);
292562306a36Sopenharmony_ci		return FALSE;
292662306a36Sopenharmony_ci	}
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci	/*
292962306a36Sopenharmony_ci	 * check EEPROM type
293062306a36Sopenharmony_ci	 */
293162306a36Sopenharmony_ci	if (vendor == PCI_VENDOR_ID_WORKBIT &&
293262306a36Sopenharmony_ci	    device == PCI_DEVICE_ID_WORKBIT_STANDARD) {
293362306a36Sopenharmony_ci		ret = nsp32_getprom_c16(data);
293462306a36Sopenharmony_ci	} else if (vendor == PCI_VENDOR_ID_WORKBIT &&
293562306a36Sopenharmony_ci		   device == PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC) {
293662306a36Sopenharmony_ci		ret = nsp32_getprom_at24(data);
293762306a36Sopenharmony_ci	} else if (vendor == PCI_VENDOR_ID_WORKBIT &&
293862306a36Sopenharmony_ci		   device == PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO ) {
293962306a36Sopenharmony_ci		ret = nsp32_getprom_at24(data);
294062306a36Sopenharmony_ci	} else {
294162306a36Sopenharmony_ci		nsp32_msg(KERN_WARNING, "Unknown EEPROM");
294262306a36Sopenharmony_ci		ret = FALSE;
294362306a36Sopenharmony_ci	}
294462306a36Sopenharmony_ci
294562306a36Sopenharmony_ci	/* for debug : SPROM data full checking */
294662306a36Sopenharmony_ci	for (i = 0; i <= 0x1f; i++) {
294762306a36Sopenharmony_ci		val = nsp32_prom_read(data, i);
294862306a36Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_EEPROM,
294962306a36Sopenharmony_ci			  "rom address 0x%x : 0x%x", i, val);
295062306a36Sopenharmony_ci	}
295162306a36Sopenharmony_ci
295262306a36Sopenharmony_ci	return ret;
295362306a36Sopenharmony_ci}
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_ci
295662306a36Sopenharmony_ci/*
295762306a36Sopenharmony_ci * AT24C01A (Logitec: LHA-600S), AT24C02 (Melco Buffalo: IFC-USLP) data map:
295862306a36Sopenharmony_ci *
295962306a36Sopenharmony_ci *   ROMADDR
296062306a36Sopenharmony_ci *   0x00 - 0x06 :  Device Synchronous Transfer Period (SCSI ID 0 - 6)
296162306a36Sopenharmony_ci *			Value 0x0: ASYNC, 0x0c: Ultra-20M, 0x19: Fast-10M
296262306a36Sopenharmony_ci *   0x07        :  HBA Synchronous Transfer Period
296362306a36Sopenharmony_ci *			Value 0: AutoSync, 1: Manual Setting
296462306a36Sopenharmony_ci *   0x08 - 0x0f :  Not Used? (0x0)
296562306a36Sopenharmony_ci *   0x10        :  Bus Termination
296662306a36Sopenharmony_ci *			Value 0: Auto[ON], 1: ON, 2: OFF
296762306a36Sopenharmony_ci *   0x11        :  Not Used? (0)
296862306a36Sopenharmony_ci *   0x12        :  Bus Reset Delay Time (0x03)
296962306a36Sopenharmony_ci *   0x13        :  Bootable CD Support
297062306a36Sopenharmony_ci *			Value 0: Disable, 1: Enable
297162306a36Sopenharmony_ci *   0x14        :  Device Scan
297262306a36Sopenharmony_ci *			Bit   7  6  5  4  3  2  1  0
297362306a36Sopenharmony_ci *			      |  <----------------->
297462306a36Sopenharmony_ci *			      |    SCSI ID: Value 0: Skip, 1: YES
297562306a36Sopenharmony_ci *			      |->  Value 0: ALL scan,  Value 1: Manual
297662306a36Sopenharmony_ci *   0x15 - 0x1b :  Not Used? (0)
297762306a36Sopenharmony_ci *   0x1c        :  Constant? (0x01) (clock div?)
297862306a36Sopenharmony_ci *   0x1d - 0x7c :  Not Used (0xff)
297962306a36Sopenharmony_ci *   0x7d	 :  Not Used? (0xff)
298062306a36Sopenharmony_ci *   0x7e        :  Constant (0x55), Validity signature
298162306a36Sopenharmony_ci *   0x7f        :  Constant (0xaa), Validity signature
298262306a36Sopenharmony_ci */
298362306a36Sopenharmony_cistatic int nsp32_getprom_at24(nsp32_hw_data *data)
298462306a36Sopenharmony_ci{
298562306a36Sopenharmony_ci	int	      ret, i;
298662306a36Sopenharmony_ci	int	      auto_sync;
298762306a36Sopenharmony_ci	nsp32_target *target;
298862306a36Sopenharmony_ci	int	      entry;
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci	/*
299162306a36Sopenharmony_ci	 * Reset time which is designated by EEPROM.
299262306a36Sopenharmony_ci	 *
299362306a36Sopenharmony_ci	 * TODO: Not used yet.
299462306a36Sopenharmony_ci	 */
299562306a36Sopenharmony_ci	data->resettime = nsp32_prom_read(data, 0x12);
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci	/*
299862306a36Sopenharmony_ci	 * HBA Synchronous Transfer Period
299962306a36Sopenharmony_ci	 *
300062306a36Sopenharmony_ci	 * Note: auto_sync = 0: auto, 1: manual.  Ninja SCSI HBA spec says
300162306a36Sopenharmony_ci	 *	that if auto_sync is 0 (auto), and connected SCSI devices are
300262306a36Sopenharmony_ci	 *	same or lower than 3, then transfer speed is set as ULTRA-20M.
300362306a36Sopenharmony_ci	 *	On the contrary if connected SCSI devices are same or higher
300462306a36Sopenharmony_ci	 *	than 4, then transfer speed is set as FAST-10M.
300562306a36Sopenharmony_ci	 *
300662306a36Sopenharmony_ci	 *	I break this rule. The number of connected SCSI devices are
300762306a36Sopenharmony_ci	 *	only ignored. If auto_sync is 0 (auto), then transfer speed is
300862306a36Sopenharmony_ci	 *	forced as ULTRA-20M.
300962306a36Sopenharmony_ci	 */
301062306a36Sopenharmony_ci	ret = nsp32_prom_read(data, 0x07);
301162306a36Sopenharmony_ci	switch (ret) {
301262306a36Sopenharmony_ci	case 0:
301362306a36Sopenharmony_ci		auto_sync = TRUE;
301462306a36Sopenharmony_ci		break;
301562306a36Sopenharmony_ci	case 1:
301662306a36Sopenharmony_ci		auto_sync = FALSE;
301762306a36Sopenharmony_ci		break;
301862306a36Sopenharmony_ci	default:
301962306a36Sopenharmony_ci		nsp32_msg(KERN_WARNING,
302062306a36Sopenharmony_ci			  "Unsupported Auto Sync mode. Fall back to manual mode.");
302162306a36Sopenharmony_ci		auto_sync = TRUE;
302262306a36Sopenharmony_ci	}
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_ci	if (trans_mode == ULTRA20M_MODE) {
302562306a36Sopenharmony_ci		auto_sync = TRUE;
302662306a36Sopenharmony_ci	}
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci	/*
302962306a36Sopenharmony_ci	 * each device Synchronous Transfer Period
303062306a36Sopenharmony_ci	 */
303162306a36Sopenharmony_ci	for (i = 0; i < NSP32_HOST_SCSIID; i++) {
303262306a36Sopenharmony_ci		target = &data->target[i];
303362306a36Sopenharmony_ci		if (auto_sync == TRUE) {
303462306a36Sopenharmony_ci			target->limit_entry = 0;   /* set as ULTRA20M */
303562306a36Sopenharmony_ci		} else {
303662306a36Sopenharmony_ci			ret   = nsp32_prom_read(data, i);
303762306a36Sopenharmony_ci			entry = nsp32_search_period_entry(data, target, ret);
303862306a36Sopenharmony_ci			if (entry < 0) {
303962306a36Sopenharmony_ci				/* search failed... set maximum speed */
304062306a36Sopenharmony_ci				entry = 0;
304162306a36Sopenharmony_ci			}
304262306a36Sopenharmony_ci			target->limit_entry = entry;
304362306a36Sopenharmony_ci		}
304462306a36Sopenharmony_ci	}
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci	return TRUE;
304762306a36Sopenharmony_ci}
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_ci/*
305162306a36Sopenharmony_ci * C16 110 (I-O Data: SC-NBD) data map:
305262306a36Sopenharmony_ci *
305362306a36Sopenharmony_ci *   ROMADDR
305462306a36Sopenharmony_ci *   0x00 - 0x06 :  Device Synchronous Transfer Period (SCSI ID 0 - 6)
305562306a36Sopenharmony_ci *			Value 0x0: 20MB/S, 0x1: 10MB/S, 0x2: 5MB/S, 0x3: ASYNC
305662306a36Sopenharmony_ci *   0x07        :  0 (HBA Synchronous Transfer Period: Auto Sync)
305762306a36Sopenharmony_ci *   0x08 - 0x0f :  Not Used? (0x0)
305862306a36Sopenharmony_ci *   0x10        :  Transfer Mode
305962306a36Sopenharmony_ci *			Value 0: PIO, 1: Busmater
306062306a36Sopenharmony_ci *   0x11        :  Bus Reset Delay Time (0x00-0x20)
306162306a36Sopenharmony_ci *   0x12        :  Bus Termination
306262306a36Sopenharmony_ci *			Value 0: Disable, 1: Enable
306362306a36Sopenharmony_ci *   0x13 - 0x19 :  Disconnection
306462306a36Sopenharmony_ci *			Value 0: Disable, 1: Enable
306562306a36Sopenharmony_ci *   0x1a - 0x7c :  Not Used? (0)
306662306a36Sopenharmony_ci *   0x7d	 :  Not Used? (0xf8)
306762306a36Sopenharmony_ci *   0x7e        :  Constant (0x55), Validity signature
306862306a36Sopenharmony_ci *   0x7f        :  Constant (0xaa), Validity signature
306962306a36Sopenharmony_ci */
307062306a36Sopenharmony_cistatic int nsp32_getprom_c16(nsp32_hw_data *data)
307162306a36Sopenharmony_ci{
307262306a36Sopenharmony_ci	int	      ret, i;
307362306a36Sopenharmony_ci	nsp32_target *target;
307462306a36Sopenharmony_ci	int	      entry, val;
307562306a36Sopenharmony_ci
307662306a36Sopenharmony_ci	/*
307762306a36Sopenharmony_ci	 * Reset time which is designated by EEPROM.
307862306a36Sopenharmony_ci	 *
307962306a36Sopenharmony_ci	 * TODO: Not used yet.
308062306a36Sopenharmony_ci	 */
308162306a36Sopenharmony_ci	data->resettime = nsp32_prom_read(data, 0x11);
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_ci	/*
308462306a36Sopenharmony_ci	 * each device Synchronous Transfer Period
308562306a36Sopenharmony_ci	 */
308662306a36Sopenharmony_ci	for (i = 0; i < NSP32_HOST_SCSIID; i++) {
308762306a36Sopenharmony_ci		target = &data->target[i];
308862306a36Sopenharmony_ci		ret = nsp32_prom_read(data, i);
308962306a36Sopenharmony_ci		switch (ret) {
309062306a36Sopenharmony_ci		case 0:		/* 20MB/s */
309162306a36Sopenharmony_ci			val = 0x0c;
309262306a36Sopenharmony_ci			break;
309362306a36Sopenharmony_ci		case 1:		/* 10MB/s */
309462306a36Sopenharmony_ci			val = 0x19;
309562306a36Sopenharmony_ci			break;
309662306a36Sopenharmony_ci		case 2:		/* 5MB/s */
309762306a36Sopenharmony_ci			val = 0x32;
309862306a36Sopenharmony_ci			break;
309962306a36Sopenharmony_ci		case 3:		/* ASYNC */
310062306a36Sopenharmony_ci			val = 0x00;
310162306a36Sopenharmony_ci			break;
310262306a36Sopenharmony_ci		default:	/* default 20MB/s */
310362306a36Sopenharmony_ci			val = 0x0c;
310462306a36Sopenharmony_ci			break;
310562306a36Sopenharmony_ci		}
310662306a36Sopenharmony_ci		entry = nsp32_search_period_entry(data, target, val);
310762306a36Sopenharmony_ci		if (entry < 0 || trans_mode == ULTRA20M_MODE) {
310862306a36Sopenharmony_ci			/* search failed... set maximum speed */
310962306a36Sopenharmony_ci			entry = 0;
311062306a36Sopenharmony_ci		}
311162306a36Sopenharmony_ci		target->limit_entry = entry;
311262306a36Sopenharmony_ci	}
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci	return TRUE;
311562306a36Sopenharmony_ci}
311662306a36Sopenharmony_ci
311762306a36Sopenharmony_ci
311862306a36Sopenharmony_ci/*
311962306a36Sopenharmony_ci * Atmel AT24C01A (drived in 5V) serial EEPROM routines
312062306a36Sopenharmony_ci */
312162306a36Sopenharmony_cistatic int nsp32_prom_read(nsp32_hw_data *data, int romaddr)
312262306a36Sopenharmony_ci{
312362306a36Sopenharmony_ci	int i, val;
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci	/* start condition */
312662306a36Sopenharmony_ci	nsp32_prom_start(data);
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci	/* device address */
312962306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 1);	/* 1 */
313062306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* 0 */
313162306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 1);	/* 1 */
313262306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* 0 */
313362306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* A2: 0 (GND) */
313462306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* A1: 0 (GND) */
313562306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* A0: 0 (GND) */
313662306a36Sopenharmony_ci
313762306a36Sopenharmony_ci	/* R/W: W for dummy write */
313862306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ci	/* ack */
314162306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);
314262306a36Sopenharmony_ci
314362306a36Sopenharmony_ci	/* word address */
314462306a36Sopenharmony_ci	for (i = 7; i >= 0; i--) {
314562306a36Sopenharmony_ci		nsp32_prom_write_bit(data, ((romaddr >> i) & 1));
314662306a36Sopenharmony_ci	}
314762306a36Sopenharmony_ci
314862306a36Sopenharmony_ci	/* ack */
314962306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);
315062306a36Sopenharmony_ci
315162306a36Sopenharmony_ci	/* start condition */
315262306a36Sopenharmony_ci	nsp32_prom_start(data);
315362306a36Sopenharmony_ci
315462306a36Sopenharmony_ci	/* device address */
315562306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 1);	/* 1 */
315662306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* 0 */
315762306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 1);	/* 1 */
315862306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* 0 */
315962306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* A2: 0 (GND) */
316062306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* A1: 0 (GND) */
316162306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* A0: 0 (GND) */
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ci	/* R/W: R */
316462306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 1);
316562306a36Sopenharmony_ci
316662306a36Sopenharmony_ci	/* ack */
316762306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 0);
316862306a36Sopenharmony_ci
316962306a36Sopenharmony_ci	/* data... */
317062306a36Sopenharmony_ci	val = 0;
317162306a36Sopenharmony_ci	for (i = 7; i >= 0; i--) {
317262306a36Sopenharmony_ci		val += (nsp32_prom_read_bit(data) << i);
317362306a36Sopenharmony_ci	}
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci	/* no ack */
317662306a36Sopenharmony_ci	nsp32_prom_write_bit(data, 1);
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci	/* stop condition */
317962306a36Sopenharmony_ci	nsp32_prom_stop(data);
318062306a36Sopenharmony_ci
318162306a36Sopenharmony_ci	return val;
318262306a36Sopenharmony_ci}
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_cistatic void nsp32_prom_set(nsp32_hw_data *data, int bit, int val)
318562306a36Sopenharmony_ci{
318662306a36Sopenharmony_ci	int base = data->BaseAddress;
318762306a36Sopenharmony_ci	int tmp;
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci	tmp = nsp32_index_read1(base, SERIAL_ROM_CTL);
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_ci	if (val == 0) {
319262306a36Sopenharmony_ci		tmp &= ~bit;
319362306a36Sopenharmony_ci	} else {
319462306a36Sopenharmony_ci		tmp |=  bit;
319562306a36Sopenharmony_ci	}
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci	nsp32_index_write1(base, SERIAL_ROM_CTL, tmp);
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci	udelay(10);
320062306a36Sopenharmony_ci}
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_cistatic int nsp32_prom_get(nsp32_hw_data *data, int bit)
320362306a36Sopenharmony_ci{
320462306a36Sopenharmony_ci	int base = data->BaseAddress;
320562306a36Sopenharmony_ci	int tmp, ret;
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci	if (bit != SDA) {
320862306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "return value is not appropriate");
320962306a36Sopenharmony_ci		return 0;
321062306a36Sopenharmony_ci	}
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci
321362306a36Sopenharmony_ci	tmp = nsp32_index_read1(base, SERIAL_ROM_CTL) & bit;
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	if (tmp == 0) {
321662306a36Sopenharmony_ci		ret = 0;
321762306a36Sopenharmony_ci	} else {
321862306a36Sopenharmony_ci		ret = 1;
321962306a36Sopenharmony_ci	}
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	udelay(10);
322262306a36Sopenharmony_ci
322362306a36Sopenharmony_ci	return ret;
322462306a36Sopenharmony_ci}
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_cistatic void nsp32_prom_start (nsp32_hw_data *data)
322762306a36Sopenharmony_ci{
322862306a36Sopenharmony_ci	/* start condition */
322962306a36Sopenharmony_ci	nsp32_prom_set(data, SCL, 1);
323062306a36Sopenharmony_ci	nsp32_prom_set(data, SDA, 1);
323162306a36Sopenharmony_ci	nsp32_prom_set(data, ENA, 1);	/* output mode */
323262306a36Sopenharmony_ci	nsp32_prom_set(data, SDA, 0);	/* keeping SCL=1 and transiting
323362306a36Sopenharmony_ci					 * SDA 1->0 is start condition */
323462306a36Sopenharmony_ci	nsp32_prom_set(data, SCL, 0);
323562306a36Sopenharmony_ci}
323662306a36Sopenharmony_ci
323762306a36Sopenharmony_cistatic void nsp32_prom_stop (nsp32_hw_data *data)
323862306a36Sopenharmony_ci{
323962306a36Sopenharmony_ci	/* stop condition */
324062306a36Sopenharmony_ci	nsp32_prom_set(data, SCL, 1);
324162306a36Sopenharmony_ci	nsp32_prom_set(data, SDA, 0);
324262306a36Sopenharmony_ci	nsp32_prom_set(data, ENA, 1);	/* output mode */
324362306a36Sopenharmony_ci	nsp32_prom_set(data, SDA, 1);
324462306a36Sopenharmony_ci	nsp32_prom_set(data, SCL, 0);
324562306a36Sopenharmony_ci}
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_cistatic void nsp32_prom_write_bit(nsp32_hw_data *data, int val)
324862306a36Sopenharmony_ci{
324962306a36Sopenharmony_ci	/* write */
325062306a36Sopenharmony_ci	nsp32_prom_set(data, SDA, val);
325162306a36Sopenharmony_ci	nsp32_prom_set(data, SCL, 1  );
325262306a36Sopenharmony_ci	nsp32_prom_set(data, SCL, 0  );
325362306a36Sopenharmony_ci}
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_cistatic int nsp32_prom_read_bit(nsp32_hw_data *data)
325662306a36Sopenharmony_ci{
325762306a36Sopenharmony_ci	int val;
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci	/* read */
326062306a36Sopenharmony_ci	nsp32_prom_set(data, ENA, 0);	/* input mode */
326162306a36Sopenharmony_ci	nsp32_prom_set(data, SCL, 1);
326262306a36Sopenharmony_ci
326362306a36Sopenharmony_ci	val = nsp32_prom_get(data, SDA);
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	nsp32_prom_set(data, SCL, 0);
326662306a36Sopenharmony_ci	nsp32_prom_set(data, ENA, 1);	/* output mode */
326762306a36Sopenharmony_ci
326862306a36Sopenharmony_ci	return val;
326962306a36Sopenharmony_ci}
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci/**************************************************************************
327362306a36Sopenharmony_ci * Power Management
327462306a36Sopenharmony_ci */
327562306a36Sopenharmony_ci#ifdef CONFIG_PM
327662306a36Sopenharmony_ci
327762306a36Sopenharmony_ci/* Device suspended */
327862306a36Sopenharmony_cistatic int nsp32_suspend(struct pci_dev *pdev, pm_message_t state)
327962306a36Sopenharmony_ci{
328062306a36Sopenharmony_ci	struct Scsi_Host *host = pci_get_drvdata(pdev);
328162306a36Sopenharmony_ci
328262306a36Sopenharmony_ci	nsp32_msg(KERN_INFO, "pci-suspend: pdev=0x%p, state.event=%x, slot=%s, host=0x%p",
328362306a36Sopenharmony_ci		  pdev, state.event, pci_name(pdev), host);
328462306a36Sopenharmony_ci
328562306a36Sopenharmony_ci	pci_save_state     (pdev);
328662306a36Sopenharmony_ci	pci_disable_device (pdev);
328762306a36Sopenharmony_ci	pci_set_power_state(pdev, pci_choose_state(pdev, state));
328862306a36Sopenharmony_ci
328962306a36Sopenharmony_ci	return 0;
329062306a36Sopenharmony_ci}
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_ci/* Device woken up */
329362306a36Sopenharmony_cistatic int nsp32_resume(struct pci_dev *pdev)
329462306a36Sopenharmony_ci{
329562306a36Sopenharmony_ci	struct Scsi_Host *host = pci_get_drvdata(pdev);
329662306a36Sopenharmony_ci	nsp32_hw_data    *data = (nsp32_hw_data *)host->hostdata;
329762306a36Sopenharmony_ci	unsigned short    reg;
329862306a36Sopenharmony_ci
329962306a36Sopenharmony_ci	nsp32_msg(KERN_INFO, "pci-resume: pdev=0x%p, slot=%s, host=0x%p",
330062306a36Sopenharmony_ci		  pdev, pci_name(pdev), host);
330162306a36Sopenharmony_ci
330262306a36Sopenharmony_ci	pci_set_power_state(pdev, PCI_D0);
330362306a36Sopenharmony_ci	pci_enable_wake    (pdev, PCI_D0, 0);
330462306a36Sopenharmony_ci	pci_restore_state  (pdev);
330562306a36Sopenharmony_ci
330662306a36Sopenharmony_ci	reg = nsp32_read2(data->BaseAddress, INDEX_REG);
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci	nsp32_msg(KERN_INFO, "io=0x%x reg=0x%x", data->BaseAddress, reg);
330962306a36Sopenharmony_ci
331062306a36Sopenharmony_ci	if (reg == 0xffff) {
331162306a36Sopenharmony_ci		nsp32_msg(KERN_INFO, "missing device. abort resume.");
331262306a36Sopenharmony_ci		return 0;
331362306a36Sopenharmony_ci	}
331462306a36Sopenharmony_ci
331562306a36Sopenharmony_ci	nsp32hw_init      (data);
331662306a36Sopenharmony_ci	nsp32_do_bus_reset(data);
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci	nsp32_msg(KERN_INFO, "resume success");
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci	return 0;
332162306a36Sopenharmony_ci}
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci#endif
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci/************************************************************************
332662306a36Sopenharmony_ci * PCI/Cardbus probe/remove routine
332762306a36Sopenharmony_ci */
332862306a36Sopenharmony_cistatic int nsp32_probe(struct pci_dev *pdev, const struct pci_device_id *id)
332962306a36Sopenharmony_ci{
333062306a36Sopenharmony_ci	int ret;
333162306a36Sopenharmony_ci	nsp32_hw_data *data = &nsp32_data_base;
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
333462306a36Sopenharmony_ci
333562306a36Sopenharmony_ci	ret = pci_enable_device(pdev);
333662306a36Sopenharmony_ci	if (ret) {
333762306a36Sopenharmony_ci		nsp32_msg(KERN_ERR, "failed to enable pci device");
333862306a36Sopenharmony_ci		return ret;
333962306a36Sopenharmony_ci	}
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	data->Pci	  = pdev;
334262306a36Sopenharmony_ci	data->pci_devid   = id;
334362306a36Sopenharmony_ci	data->IrqNumber   = pdev->irq;
334462306a36Sopenharmony_ci	data->BaseAddress = pci_resource_start(pdev, 0);
334562306a36Sopenharmony_ci	data->NumAddress  = pci_resource_len  (pdev, 0);
334662306a36Sopenharmony_ci	data->MmioAddress = pci_ioremap_bar(pdev, 1);
334762306a36Sopenharmony_ci	data->MmioLength  = pci_resource_len  (pdev, 1);
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci	pci_set_master(pdev);
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci	ret = nsp32_detect(pdev);
335262306a36Sopenharmony_ci
335362306a36Sopenharmony_ci	nsp32_msg(KERN_INFO, "irq: %i mmio: %p+0x%lx slot: %s model: %s",
335462306a36Sopenharmony_ci		  pdev->irq,
335562306a36Sopenharmony_ci		  data->MmioAddress, data->MmioLength,
335662306a36Sopenharmony_ci		  pci_name(pdev),
335762306a36Sopenharmony_ci		  nsp32_model[id->driver_data]);
335862306a36Sopenharmony_ci
335962306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_REGISTER, "exit %d", ret);
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci	return ret;
336262306a36Sopenharmony_ci}
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_cistatic void nsp32_remove(struct pci_dev *pdev)
336562306a36Sopenharmony_ci{
336662306a36Sopenharmony_ci	struct Scsi_Host *host = pci_get_drvdata(pdev);
336762306a36Sopenharmony_ci
336862306a36Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci	scsi_remove_host(host);
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ci	nsp32_release(host);
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_ci	scsi_host_put(host);
337562306a36Sopenharmony_ci}
337662306a36Sopenharmony_ci
337762306a36Sopenharmony_cistatic struct pci_driver nsp32_driver = {
337862306a36Sopenharmony_ci	.name		= "nsp32",
337962306a36Sopenharmony_ci	.id_table	= nsp32_pci_table,
338062306a36Sopenharmony_ci	.probe		= nsp32_probe,
338162306a36Sopenharmony_ci	.remove		= nsp32_remove,
338262306a36Sopenharmony_ci#ifdef CONFIG_PM
338362306a36Sopenharmony_ci	.suspend	= nsp32_suspend,
338462306a36Sopenharmony_ci	.resume		= nsp32_resume,
338562306a36Sopenharmony_ci#endif
338662306a36Sopenharmony_ci};
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci/*********************************************************************
338962306a36Sopenharmony_ci * Moule entry point
339062306a36Sopenharmony_ci */
339162306a36Sopenharmony_cistatic int __init init_nsp32(void) {
339262306a36Sopenharmony_ci	nsp32_msg(KERN_INFO, "loading...");
339362306a36Sopenharmony_ci	return pci_register_driver(&nsp32_driver);
339462306a36Sopenharmony_ci}
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_cistatic void __exit exit_nsp32(void) {
339762306a36Sopenharmony_ci	nsp32_msg(KERN_INFO, "unloading...");
339862306a36Sopenharmony_ci	pci_unregister_driver(&nsp32_driver);
339962306a36Sopenharmony_ci}
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_cimodule_init(init_nsp32);
340262306a36Sopenharmony_cimodule_exit(exit_nsp32);
340362306a36Sopenharmony_ci
340462306a36Sopenharmony_ci/* end */
3405