18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * NinjaSCSI-32Bi Cardbus, NinjaSCSI-32UDE PCI/CardBus SCSI driver
48c2ecf20Sopenharmony_ci * Copyright (C) 2001, 2002, 2003
58c2ecf20Sopenharmony_ci *      YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
68c2ecf20Sopenharmony_ci *      GOTO Masanori <gotom@debian.or.jp>, <gotom@debian.org>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Revision History:
98c2ecf20Sopenharmony_ci *   1.0: Initial Release.
108c2ecf20Sopenharmony_ci *   1.1: Add /proc SDTR status.
118c2ecf20Sopenharmony_ci *        Remove obsolete error handler nsp32_reset.
128c2ecf20Sopenharmony_ci *        Some clean up.
138c2ecf20Sopenharmony_ci *   1.2: PowerPC (big endian) support.
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/string.h>
208c2ecf20Sopenharmony_ci#include <linux/timer.h>
218c2ecf20Sopenharmony_ci#include <linux/ioport.h>
228c2ecf20Sopenharmony_ci#include <linux/major.h>
238c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
248c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
258c2ecf20Sopenharmony_ci#include <linux/pci.h>
268c2ecf20Sopenharmony_ci#include <linux/delay.h>
278c2ecf20Sopenharmony_ci#include <linux/ctype.h>
288c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include <asm/dma.h>
318c2ecf20Sopenharmony_ci#include <asm/io.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
348c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
358c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
368c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
378c2ecf20Sopenharmony_ci#include <scsi/scsi_ioctl.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#include "nsp32.h"
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/***********************************************************************
438c2ecf20Sopenharmony_ci * Module parameters
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_cistatic int       trans_mode = 0;	/* default: BIOS */
468c2ecf20Sopenharmony_cimodule_param     (trans_mode, int, 0);
478c2ecf20Sopenharmony_ciMODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS(default) 1: Async 2: Ultra20M");
488c2ecf20Sopenharmony_ci#define ASYNC_MODE    1
498c2ecf20Sopenharmony_ci#define ULTRA20M_MODE 2
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic bool      auto_param = 0;	/* default: ON */
528c2ecf20Sopenharmony_cimodule_param     (auto_param, bool, 0);
538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON(default) 1: OFF)");
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic bool      disc_priv  = 1;	/* default: OFF */
568c2ecf20Sopenharmony_cimodule_param     (disc_priv, bool, 0);
578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disc_priv,  "disconnection privilege mode (0: ON 1: OFF(default))");
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ciMODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>, GOTO Masanori <gotom@debian.or.jp>");
608c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Workbit NinjaSCSI-32Bi/UDE CardBus/PCI SCSI host bus adapter module");
618c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic const char *nsp32_release_version = "1.2";
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/****************************************************************************
678c2ecf20Sopenharmony_ci * Supported hardware
688c2ecf20Sopenharmony_ci */
698c2ecf20Sopenharmony_cistatic struct pci_device_id nsp32_pci_table[] = {
708c2ecf20Sopenharmony_ci	{
718c2ecf20Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_IODATA,
728c2ecf20Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II,
738c2ecf20Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
748c2ecf20Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
758c2ecf20Sopenharmony_ci		.driver_data = MODEL_IODATA,
768c2ecf20Sopenharmony_ci	},
778c2ecf20Sopenharmony_ci	{
788c2ecf20Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
798c2ecf20Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_KME,
808c2ecf20Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
818c2ecf20Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
828c2ecf20Sopenharmony_ci		.driver_data = MODEL_KME,
838c2ecf20Sopenharmony_ci	},
848c2ecf20Sopenharmony_ci	{
858c2ecf20Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
868c2ecf20Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_WBT,
878c2ecf20Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
888c2ecf20Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
898c2ecf20Sopenharmony_ci		.driver_data = MODEL_WORKBIT,
908c2ecf20Sopenharmony_ci	},
918c2ecf20Sopenharmony_ci	{
928c2ecf20Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
938c2ecf20Sopenharmony_ci		.device      = PCI_DEVICE_ID_WORKBIT_STANDARD,
948c2ecf20Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
958c2ecf20Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
968c2ecf20Sopenharmony_ci		.driver_data = MODEL_PCI_WORKBIT,
978c2ecf20Sopenharmony_ci	},
988c2ecf20Sopenharmony_ci	{
998c2ecf20Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
1008c2ecf20Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC,
1018c2ecf20Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
1028c2ecf20Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
1038c2ecf20Sopenharmony_ci		.driver_data = MODEL_LOGITEC,
1048c2ecf20Sopenharmony_ci	},
1058c2ecf20Sopenharmony_ci	{
1068c2ecf20Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
1078c2ecf20Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC,
1088c2ecf20Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
1098c2ecf20Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
1108c2ecf20Sopenharmony_ci		.driver_data = MODEL_PCI_LOGITEC,
1118c2ecf20Sopenharmony_ci	},
1128c2ecf20Sopenharmony_ci	{
1138c2ecf20Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
1148c2ecf20Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO,
1158c2ecf20Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
1168c2ecf20Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
1178c2ecf20Sopenharmony_ci		.driver_data = MODEL_PCI_MELCO,
1188c2ecf20Sopenharmony_ci	},
1198c2ecf20Sopenharmony_ci	{
1208c2ecf20Sopenharmony_ci		.vendor      = PCI_VENDOR_ID_WORKBIT,
1218c2ecf20Sopenharmony_ci		.device      = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO_II,
1228c2ecf20Sopenharmony_ci		.subvendor   = PCI_ANY_ID,
1238c2ecf20Sopenharmony_ci		.subdevice   = PCI_ANY_ID,
1248c2ecf20Sopenharmony_ci		.driver_data = MODEL_PCI_MELCO,
1258c2ecf20Sopenharmony_ci	},
1268c2ecf20Sopenharmony_ci	{0,0,},
1278c2ecf20Sopenharmony_ci};
1288c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, nsp32_pci_table);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic nsp32_hw_data nsp32_data_base;  /* probe <-> detect glue */
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/*
1348c2ecf20Sopenharmony_ci * Period/AckWidth speed conversion table
1358c2ecf20Sopenharmony_ci *
1368c2ecf20Sopenharmony_ci * Note: This period/ackwidth speed table must be in descending order.
1378c2ecf20Sopenharmony_ci */
1388c2ecf20Sopenharmony_cistatic nsp32_sync_table nsp32_sync_table_40M[] = {
1398c2ecf20Sopenharmony_ci     /* {PNo, AW,   SP,   EP, SREQ smpl}  Speed(MB/s) Period AckWidth */
1408c2ecf20Sopenharmony_ci	{0x1,  0, 0x0c, 0x0c, SMPL_40M},  /*  20.0 :  50ns,  25ns */
1418c2ecf20Sopenharmony_ci	{0x2,  0, 0x0d, 0x18, SMPL_40M},  /*  13.3 :  75ns,  25ns */
1428c2ecf20Sopenharmony_ci	{0x3,  1, 0x19, 0x19, SMPL_40M},  /*  10.0 : 100ns,  50ns */
1438c2ecf20Sopenharmony_ci	{0x4,  1, 0x1a, 0x1f, SMPL_20M},  /*   8.0 : 125ns,  50ns */
1448c2ecf20Sopenharmony_ci	{0x5,  2, 0x20, 0x25, SMPL_20M},  /*   6.7 : 150ns,  75ns */
1458c2ecf20Sopenharmony_ci	{0x6,  2, 0x26, 0x31, SMPL_20M},  /*   5.7 : 175ns,  75ns */
1468c2ecf20Sopenharmony_ci	{0x7,  3, 0x32, 0x32, SMPL_20M},  /*   5.0 : 200ns, 100ns */
1478c2ecf20Sopenharmony_ci	{0x8,  3, 0x33, 0x38, SMPL_10M},  /*   4.4 : 225ns, 100ns */
1488c2ecf20Sopenharmony_ci	{0x9,  3, 0x39, 0x3e, SMPL_10M},  /*   4.0 : 250ns, 100ns */
1498c2ecf20Sopenharmony_ci};
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic nsp32_sync_table nsp32_sync_table_20M[] = {
1528c2ecf20Sopenharmony_ci	{0x1,  0, 0x19, 0x19, SMPL_40M},  /* 10.0 : 100ns,  50ns */
1538c2ecf20Sopenharmony_ci	{0x2,  0, 0x1a, 0x25, SMPL_20M},  /*  6.7 : 150ns,  50ns */
1548c2ecf20Sopenharmony_ci	{0x3,  1, 0x26, 0x32, SMPL_20M},  /*  5.0 : 200ns, 100ns */
1558c2ecf20Sopenharmony_ci	{0x4,  1, 0x33, 0x3e, SMPL_10M},  /*  4.0 : 250ns, 100ns */
1568c2ecf20Sopenharmony_ci	{0x5,  2, 0x3f, 0x4b, SMPL_10M},  /*  3.3 : 300ns, 150ns */
1578c2ecf20Sopenharmony_ci	{0x6,  2, 0x4c, 0x57, SMPL_10M},  /*  2.8 : 350ns, 150ns */
1588c2ecf20Sopenharmony_ci	{0x7,  3, 0x58, 0x64, SMPL_10M},  /*  2.5 : 400ns, 200ns */
1598c2ecf20Sopenharmony_ci	{0x8,  3, 0x65, 0x70, SMPL_10M},  /*  2.2 : 450ns, 200ns */
1608c2ecf20Sopenharmony_ci	{0x9,  3, 0x71, 0x7d, SMPL_10M},  /*  2.0 : 500ns, 200ns */
1618c2ecf20Sopenharmony_ci};
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic nsp32_sync_table nsp32_sync_table_pci[] = {
1648c2ecf20Sopenharmony_ci	{0x1,  0, 0x0c, 0x0f, SMPL_40M},  /* 16.6 :  60ns,  30ns */
1658c2ecf20Sopenharmony_ci	{0x2,  0, 0x10, 0x16, SMPL_40M},  /* 11.1 :  90ns,  30ns */
1668c2ecf20Sopenharmony_ci	{0x3,  1, 0x17, 0x1e, SMPL_20M},  /*  8.3 : 120ns,  60ns */
1678c2ecf20Sopenharmony_ci	{0x4,  1, 0x1f, 0x25, SMPL_20M},  /*  6.7 : 150ns,  60ns */
1688c2ecf20Sopenharmony_ci	{0x5,  2, 0x26, 0x2d, SMPL_20M},  /*  5.6 : 180ns,  90ns */
1698c2ecf20Sopenharmony_ci	{0x6,  2, 0x2e, 0x34, SMPL_10M},  /*  4.8 : 210ns,  90ns */
1708c2ecf20Sopenharmony_ci	{0x7,  3, 0x35, 0x3c, SMPL_10M},  /*  4.2 : 240ns, 120ns */
1718c2ecf20Sopenharmony_ci	{0x8,  3, 0x3d, 0x43, SMPL_10M},  /*  3.7 : 270ns, 120ns */
1728c2ecf20Sopenharmony_ci	{0x9,  3, 0x44, 0x4b, SMPL_10M},  /*  3.3 : 300ns, 120ns */
1738c2ecf20Sopenharmony_ci};
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci/*
1768c2ecf20Sopenharmony_ci * function declaration
1778c2ecf20Sopenharmony_ci */
1788c2ecf20Sopenharmony_ci/* module entry point */
1798c2ecf20Sopenharmony_cistatic int         nsp32_probe (struct pci_dev *, const struct pci_device_id *);
1808c2ecf20Sopenharmony_cistatic void        nsp32_remove(struct pci_dev *);
1818c2ecf20Sopenharmony_cistatic int  __init init_nsp32  (void);
1828c2ecf20Sopenharmony_cistatic void __exit exit_nsp32  (void);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci/* struct struct scsi_host_template */
1858c2ecf20Sopenharmony_cistatic int         nsp32_show_info   (struct seq_file *, struct Scsi_Host *);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic int         nsp32_detect      (struct pci_dev *pdev);
1888c2ecf20Sopenharmony_cistatic int         nsp32_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
1898c2ecf20Sopenharmony_cistatic const char *nsp32_info        (struct Scsi_Host *);
1908c2ecf20Sopenharmony_cistatic int         nsp32_release     (struct Scsi_Host *);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci/* SCSI error handler */
1938c2ecf20Sopenharmony_cistatic int         nsp32_eh_abort     (struct scsi_cmnd *);
1948c2ecf20Sopenharmony_cistatic int         nsp32_eh_host_reset(struct scsi_cmnd *);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci/* generate SCSI message */
1978c2ecf20Sopenharmony_cistatic void nsp32_build_identify(struct scsi_cmnd *);
1988c2ecf20Sopenharmony_cistatic void nsp32_build_nop     (struct scsi_cmnd *);
1998c2ecf20Sopenharmony_cistatic void nsp32_build_reject  (struct scsi_cmnd *);
2008c2ecf20Sopenharmony_cistatic void nsp32_build_sdtr    (struct scsi_cmnd *, unsigned char, unsigned char);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci/* SCSI message handler */
2038c2ecf20Sopenharmony_cistatic int  nsp32_busfree_occur(struct scsi_cmnd *, unsigned short);
2048c2ecf20Sopenharmony_cistatic void nsp32_msgout_occur (struct scsi_cmnd *);
2058c2ecf20Sopenharmony_cistatic void nsp32_msgin_occur  (struct scsi_cmnd *, unsigned long, unsigned short);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic int  nsp32_setup_sg_table    (struct scsi_cmnd *);
2088c2ecf20Sopenharmony_cistatic int  nsp32_selection_autopara(struct scsi_cmnd *);
2098c2ecf20Sopenharmony_cistatic int  nsp32_selection_autoscsi(struct scsi_cmnd *);
2108c2ecf20Sopenharmony_cistatic void nsp32_scsi_done         (struct scsi_cmnd *);
2118c2ecf20Sopenharmony_cistatic int  nsp32_arbitration       (struct scsi_cmnd *, unsigned int);
2128c2ecf20Sopenharmony_cistatic int  nsp32_reselection       (struct scsi_cmnd *, unsigned char);
2138c2ecf20Sopenharmony_cistatic void nsp32_adjust_busfree    (struct scsi_cmnd *, unsigned int);
2148c2ecf20Sopenharmony_cistatic void nsp32_restart_autoscsi  (struct scsi_cmnd *, unsigned short);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci/* SCSI SDTR */
2178c2ecf20Sopenharmony_cistatic void nsp32_analyze_sdtr       (struct scsi_cmnd *);
2188c2ecf20Sopenharmony_cistatic int  nsp32_search_period_entry(nsp32_hw_data *, nsp32_target *, unsigned char);
2198c2ecf20Sopenharmony_cistatic void nsp32_set_async          (nsp32_hw_data *, nsp32_target *);
2208c2ecf20Sopenharmony_cistatic void nsp32_set_max_sync       (nsp32_hw_data *, nsp32_target *, unsigned char *, unsigned char *);
2218c2ecf20Sopenharmony_cistatic void nsp32_set_sync_entry     (nsp32_hw_data *, nsp32_target *, int, unsigned char);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci/* SCSI bus status handler */
2248c2ecf20Sopenharmony_cistatic void nsp32_wait_req    (nsp32_hw_data *, int);
2258c2ecf20Sopenharmony_cistatic void nsp32_wait_sack   (nsp32_hw_data *, int);
2268c2ecf20Sopenharmony_cistatic void nsp32_sack_assert (nsp32_hw_data *);
2278c2ecf20Sopenharmony_cistatic void nsp32_sack_negate (nsp32_hw_data *);
2288c2ecf20Sopenharmony_cistatic void nsp32_do_bus_reset(nsp32_hw_data *);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci/* hardware interrupt handler */
2318c2ecf20Sopenharmony_cistatic irqreturn_t do_nsp32_isr(int, void *);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/* initialize hardware */
2348c2ecf20Sopenharmony_cistatic int  nsp32hw_init(nsp32_hw_data *);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci/* EEPROM handler */
2378c2ecf20Sopenharmony_cistatic        int  nsp32_getprom_param (nsp32_hw_data *);
2388c2ecf20Sopenharmony_cistatic        int  nsp32_getprom_at24  (nsp32_hw_data *);
2398c2ecf20Sopenharmony_cistatic        int  nsp32_getprom_c16   (nsp32_hw_data *);
2408c2ecf20Sopenharmony_cistatic        void nsp32_prom_start    (nsp32_hw_data *);
2418c2ecf20Sopenharmony_cistatic        void nsp32_prom_stop     (nsp32_hw_data *);
2428c2ecf20Sopenharmony_cistatic        int  nsp32_prom_read     (nsp32_hw_data *, int);
2438c2ecf20Sopenharmony_cistatic        int  nsp32_prom_read_bit (nsp32_hw_data *);
2448c2ecf20Sopenharmony_cistatic        void nsp32_prom_write_bit(nsp32_hw_data *, int);
2458c2ecf20Sopenharmony_cistatic        void nsp32_prom_set      (nsp32_hw_data *, int, int);
2468c2ecf20Sopenharmony_cistatic        int  nsp32_prom_get      (nsp32_hw_data *, int);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci/* debug/warning/info message */
2498c2ecf20Sopenharmony_cistatic void nsp32_message (const char *, int, char *, char *, ...);
2508c2ecf20Sopenharmony_ci#ifdef NSP32_DEBUG
2518c2ecf20Sopenharmony_cistatic void nsp32_dmessage(const char *, int, int,    char *, ...);
2528c2ecf20Sopenharmony_ci#endif
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci/*
2558c2ecf20Sopenharmony_ci * max_sectors is currently limited up to 128.
2568c2ecf20Sopenharmony_ci */
2578c2ecf20Sopenharmony_cistatic struct scsi_host_template nsp32_template = {
2588c2ecf20Sopenharmony_ci	.proc_name			= "nsp32",
2598c2ecf20Sopenharmony_ci	.name				= "Workbit NinjaSCSI-32Bi/UDE",
2608c2ecf20Sopenharmony_ci	.show_info			= nsp32_show_info,
2618c2ecf20Sopenharmony_ci	.info				= nsp32_info,
2628c2ecf20Sopenharmony_ci	.queuecommand			= nsp32_queuecommand,
2638c2ecf20Sopenharmony_ci	.can_queue			= 1,
2648c2ecf20Sopenharmony_ci	.sg_tablesize			= NSP32_SG_SIZE,
2658c2ecf20Sopenharmony_ci	.max_sectors			= 128,
2668c2ecf20Sopenharmony_ci	.this_id			= NSP32_HOST_SCSIID,
2678c2ecf20Sopenharmony_ci	.dma_boundary			= PAGE_SIZE - 1,
2688c2ecf20Sopenharmony_ci	.eh_abort_handler		= nsp32_eh_abort,
2698c2ecf20Sopenharmony_ci	.eh_host_reset_handler		= nsp32_eh_host_reset,
2708c2ecf20Sopenharmony_ci/*	.highmem_io			= 1, */
2718c2ecf20Sopenharmony_ci};
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci#include "nsp32_io.h"
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci/***********************************************************************
2768c2ecf20Sopenharmony_ci * debug, error print
2778c2ecf20Sopenharmony_ci */
2788c2ecf20Sopenharmony_ci#ifndef NSP32_DEBUG
2798c2ecf20Sopenharmony_ci# define NSP32_DEBUG_MASK	      0x000000
2808c2ecf20Sopenharmony_ci# define nsp32_msg(type, args...)     nsp32_message ("", 0, (type), args)
2818c2ecf20Sopenharmony_ci# define nsp32_dbg(mask, args...)     /* */
2828c2ecf20Sopenharmony_ci#else
2838c2ecf20Sopenharmony_ci# define NSP32_DEBUG_MASK	      0xffffff
2848c2ecf20Sopenharmony_ci# define nsp32_msg(type, args...) \
2858c2ecf20Sopenharmony_ci	nsp32_message (__func__, __LINE__, (type), args)
2868c2ecf20Sopenharmony_ci# define nsp32_dbg(mask, args...) \
2878c2ecf20Sopenharmony_ci	nsp32_dmessage(__func__, __LINE__, (mask), args)
2888c2ecf20Sopenharmony_ci#endif
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci#define NSP32_DEBUG_QUEUECOMMAND	BIT(0)
2918c2ecf20Sopenharmony_ci#define NSP32_DEBUG_REGISTER		BIT(1)
2928c2ecf20Sopenharmony_ci#define NSP32_DEBUG_AUTOSCSI		BIT(2)
2938c2ecf20Sopenharmony_ci#define NSP32_DEBUG_INTR		BIT(3)
2948c2ecf20Sopenharmony_ci#define NSP32_DEBUG_SGLIST		BIT(4)
2958c2ecf20Sopenharmony_ci#define NSP32_DEBUG_BUSFREE		BIT(5)
2968c2ecf20Sopenharmony_ci#define NSP32_DEBUG_CDB_CONTENTS	BIT(6)
2978c2ecf20Sopenharmony_ci#define NSP32_DEBUG_RESELECTION		BIT(7)
2988c2ecf20Sopenharmony_ci#define NSP32_DEBUG_MSGINOCCUR		BIT(8)
2998c2ecf20Sopenharmony_ci#define NSP32_DEBUG_EEPROM		BIT(9)
3008c2ecf20Sopenharmony_ci#define NSP32_DEBUG_MSGOUTOCCUR		BIT(10)
3018c2ecf20Sopenharmony_ci#define NSP32_DEBUG_BUSRESET		BIT(11)
3028c2ecf20Sopenharmony_ci#define NSP32_DEBUG_RESTART		BIT(12)
3038c2ecf20Sopenharmony_ci#define NSP32_DEBUG_SYNC		BIT(13)
3048c2ecf20Sopenharmony_ci#define NSP32_DEBUG_WAIT		BIT(14)
3058c2ecf20Sopenharmony_ci#define NSP32_DEBUG_TARGETFLAG		BIT(15)
3068c2ecf20Sopenharmony_ci#define NSP32_DEBUG_PROC		BIT(16)
3078c2ecf20Sopenharmony_ci#define NSP32_DEBUG_INIT		BIT(17)
3088c2ecf20Sopenharmony_ci#define NSP32_SPECIAL_PRINT_REGISTER	BIT(20)
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci#define NSP32_DEBUG_BUF_LEN		100
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistatic void nsp32_message(const char *func, int line, char *type, char *fmt, ...)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	va_list args;
3158c2ecf20Sopenharmony_ci	char buf[NSP32_DEBUG_BUF_LEN];
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	va_start(args, fmt);
3188c2ecf20Sopenharmony_ci	vsnprintf(buf, sizeof(buf), fmt, args);
3198c2ecf20Sopenharmony_ci	va_end(args);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci#ifndef NSP32_DEBUG
3228c2ecf20Sopenharmony_ci	printk("%snsp32: %s\n", type, buf);
3238c2ecf20Sopenharmony_ci#else
3248c2ecf20Sopenharmony_ci	printk("%snsp32: %s (%d): %s\n", type, func, line, buf);
3258c2ecf20Sopenharmony_ci#endif
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci#ifdef NSP32_DEBUG
3298c2ecf20Sopenharmony_cistatic void nsp32_dmessage(const char *func, int line, int mask, char *fmt, ...)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	va_list args;
3328c2ecf20Sopenharmony_ci	char buf[NSP32_DEBUG_BUF_LEN];
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	va_start(args, fmt);
3358c2ecf20Sopenharmony_ci	vsnprintf(buf, sizeof(buf), fmt, args);
3368c2ecf20Sopenharmony_ci	va_end(args);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (mask & NSP32_DEBUG_MASK) {
3398c2ecf20Sopenharmony_ci		printk("nsp32-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci#endif
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci#ifdef NSP32_DEBUG
3458c2ecf20Sopenharmony_ci# include "nsp32_debug.c"
3468c2ecf20Sopenharmony_ci#else
3478c2ecf20Sopenharmony_ci# define show_command(arg)   /* */
3488c2ecf20Sopenharmony_ci# define show_busphase(arg)  /* */
3498c2ecf20Sopenharmony_ci# define show_autophase(arg) /* */
3508c2ecf20Sopenharmony_ci#endif
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci/*
3538c2ecf20Sopenharmony_ci * IDENTIFY Message
3548c2ecf20Sopenharmony_ci */
3558c2ecf20Sopenharmony_cistatic void nsp32_build_identify(struct scsi_cmnd *SCpnt)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
3588c2ecf20Sopenharmony_ci	int pos             = data->msgout_len;
3598c2ecf20Sopenharmony_ci	int mode            = FALSE;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	/* XXX: Auto DiscPriv detection is progressing... */
3628c2ecf20Sopenharmony_ci	if (disc_priv == 0) {
3638c2ecf20Sopenharmony_ci		/* mode = TRUE; */
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	data->msgoutbuf[pos] = IDENTIFY(mode, SCpnt->device->lun); pos++;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	data->msgout_len = pos;
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci/*
3728c2ecf20Sopenharmony_ci * SDTR Message Routine
3738c2ecf20Sopenharmony_ci */
3748c2ecf20Sopenharmony_cistatic void nsp32_build_sdtr(struct scsi_cmnd    *SCpnt,
3758c2ecf20Sopenharmony_ci			     unsigned char period,
3768c2ecf20Sopenharmony_ci			     unsigned char offset)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
3798c2ecf20Sopenharmony_ci	int pos             = data->msgout_len;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	data->msgoutbuf[pos] = EXTENDED_MESSAGE;  pos++;
3828c2ecf20Sopenharmony_ci	data->msgoutbuf[pos] = EXTENDED_SDTR_LEN; pos++;
3838c2ecf20Sopenharmony_ci	data->msgoutbuf[pos] = EXTENDED_SDTR;     pos++;
3848c2ecf20Sopenharmony_ci	data->msgoutbuf[pos] = period;            pos++;
3858c2ecf20Sopenharmony_ci	data->msgoutbuf[pos] = offset;            pos++;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	data->msgout_len = pos;
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci/*
3918c2ecf20Sopenharmony_ci * No Operation Message
3928c2ecf20Sopenharmony_ci */
3938c2ecf20Sopenharmony_cistatic void nsp32_build_nop(struct scsi_cmnd *SCpnt)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
3968c2ecf20Sopenharmony_ci	int            pos  = data->msgout_len;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	if (pos != 0) {
3998c2ecf20Sopenharmony_ci		nsp32_msg(KERN_WARNING,
4008c2ecf20Sopenharmony_ci			  "Some messages are already contained!");
4018c2ecf20Sopenharmony_ci		return;
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	data->msgoutbuf[pos] = NOP; pos++;
4058c2ecf20Sopenharmony_ci	data->msgout_len = pos;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci/*
4098c2ecf20Sopenharmony_ci * Reject Message
4108c2ecf20Sopenharmony_ci */
4118c2ecf20Sopenharmony_cistatic void nsp32_build_reject(struct scsi_cmnd *SCpnt)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
4148c2ecf20Sopenharmony_ci	int            pos  = data->msgout_len;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	data->msgoutbuf[pos] = MESSAGE_REJECT; pos++;
4178c2ecf20Sopenharmony_ci	data->msgout_len = pos;
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci/*
4218c2ecf20Sopenharmony_ci * timer
4228c2ecf20Sopenharmony_ci */
4238c2ecf20Sopenharmony_ci#if 0
4248c2ecf20Sopenharmony_cistatic void nsp32_start_timer(struct scsi_cmnd *SCpnt, int time)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	unsigned int base = SCpnt->host->io_port;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_INTR, "timer=%d", time);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if (time & (~TIMER_CNT_MASK)) {
4318c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INTR, "timer set overflow");
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	nsp32_write2(base, TIMER_SET, time & TIMER_CNT_MASK);
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci#endif
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci/*
4408c2ecf20Sopenharmony_ci * set SCSI command and other parameter to asic, and start selection phase
4418c2ecf20Sopenharmony_ci */
4428c2ecf20Sopenharmony_cistatic int nsp32_selection_autopara(struct scsi_cmnd *SCpnt)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	nsp32_hw_data  *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
4458c2ecf20Sopenharmony_ci	unsigned int	base    = SCpnt->device->host->io_port;
4468c2ecf20Sopenharmony_ci	unsigned int	host_id = SCpnt->device->host->this_id;
4478c2ecf20Sopenharmony_ci	unsigned char	target  = scmd_id(SCpnt);
4488c2ecf20Sopenharmony_ci	nsp32_autoparam *param  = data->autoparam;
4498c2ecf20Sopenharmony_ci	unsigned char	phase;
4508c2ecf20Sopenharmony_ci	int		i, ret;
4518c2ecf20Sopenharmony_ci	unsigned int	msgout;
4528c2ecf20Sopenharmony_ci	u16_le	        s;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in");
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/*
4578c2ecf20Sopenharmony_ci	 * check bus free
4588c2ecf20Sopenharmony_ci	 */
4598c2ecf20Sopenharmony_ci	phase = nsp32_read1(base, SCSI_BUS_MONITOR);
4608c2ecf20Sopenharmony_ci	if (phase != BUSMON_BUS_FREE) {
4618c2ecf20Sopenharmony_ci		nsp32_msg(KERN_WARNING, "bus busy");
4628c2ecf20Sopenharmony_ci		show_busphase(phase & BUSMON_PHASE_MASK);
4638c2ecf20Sopenharmony_ci		SCpnt->result = DID_BUS_BUSY << 16;
4648c2ecf20Sopenharmony_ci		return FALSE;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	/*
4688c2ecf20Sopenharmony_ci	 * message out
4698c2ecf20Sopenharmony_ci	 *
4708c2ecf20Sopenharmony_ci	 * Note: If the range of msgout_len is 1 - 3, fill scsi_msgout.
4718c2ecf20Sopenharmony_ci	 *       over 3 messages needs another routine.
4728c2ecf20Sopenharmony_ci	 */
4738c2ecf20Sopenharmony_ci	if (data->msgout_len == 0) {
4748c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!");
4758c2ecf20Sopenharmony_ci		SCpnt->result = DID_ERROR << 16;
4768c2ecf20Sopenharmony_ci		return FALSE;
4778c2ecf20Sopenharmony_ci	} else if (data->msgout_len > 0 && data->msgout_len <= 3) {
4788c2ecf20Sopenharmony_ci		msgout = 0;
4798c2ecf20Sopenharmony_ci		for (i = 0; i < data->msgout_len; i++) {
4808c2ecf20Sopenharmony_ci			/*
4818c2ecf20Sopenharmony_ci			 * the sending order of the message is:
4828c2ecf20Sopenharmony_ci			 *  MCNT 3: MSG#0 -> MSG#1 -> MSG#2
4838c2ecf20Sopenharmony_ci			 *  MCNT 2:          MSG#1 -> MSG#2
4848c2ecf20Sopenharmony_ci			 *  MCNT 1:                   MSG#2
4858c2ecf20Sopenharmony_ci			 */
4868c2ecf20Sopenharmony_ci			msgout >>= 8;
4878c2ecf20Sopenharmony_ci			msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24);
4888c2ecf20Sopenharmony_ci		}
4898c2ecf20Sopenharmony_ci		msgout |= MV_VALID;	/* MV valid */
4908c2ecf20Sopenharmony_ci		msgout |= (unsigned int)data->msgout_len; /* len */
4918c2ecf20Sopenharmony_ci	} else {
4928c2ecf20Sopenharmony_ci		/* data->msgout_len > 3 */
4938c2ecf20Sopenharmony_ci		msgout = 0;
4948c2ecf20Sopenharmony_ci	}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	// nsp_dbg(NSP32_DEBUG_AUTOSCSI, "sel time out=0x%x\n", nsp32_read2(base, SEL_TIME_OUT));
4978c2ecf20Sopenharmony_ci	// nsp32_write2(base, SEL_TIME_OUT,   SEL_TIMEOUT_TIME);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	/*
5008c2ecf20Sopenharmony_ci	 * setup asic parameter
5018c2ecf20Sopenharmony_ci	 */
5028c2ecf20Sopenharmony_ci	memset(param, 0, sizeof(nsp32_autoparam));
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	/* cdb */
5058c2ecf20Sopenharmony_ci	for (i = 0; i < SCpnt->cmd_len; i++) {
5068c2ecf20Sopenharmony_ci		param->cdb[4 * i] = SCpnt->cmnd[i];
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	/* outgoing messages */
5108c2ecf20Sopenharmony_ci	param->msgout = cpu_to_le32(msgout);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	/* syncreg, ackwidth, target id, SREQ sampling rate */
5138c2ecf20Sopenharmony_ci	param->syncreg    = data->cur_target->syncreg;
5148c2ecf20Sopenharmony_ci	param->ackwidth   = data->cur_target->ackwidth;
5158c2ecf20Sopenharmony_ci	param->target_id  = BIT(host_id) | BIT(target);
5168c2ecf20Sopenharmony_ci	param->sample_reg = data->cur_target->sample_reg;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	// nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "sample rate=0x%x\n", data->cur_target->sample_reg);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	/* command control */
5218c2ecf20Sopenharmony_ci	param->command_control = cpu_to_le16(CLEAR_CDB_FIFO_POINTER |
5228c2ecf20Sopenharmony_ci					     AUTOSCSI_START         |
5238c2ecf20Sopenharmony_ci					     AUTO_MSGIN_00_OR_04    |
5248c2ecf20Sopenharmony_ci					     AUTO_MSGIN_02          |
5258c2ecf20Sopenharmony_ci					     AUTO_ATN               );
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	/* transfer control */
5298c2ecf20Sopenharmony_ci	s = 0;
5308c2ecf20Sopenharmony_ci	switch (data->trans_method) {
5318c2ecf20Sopenharmony_ci	case NSP32_TRANSFER_BUSMASTER:
5328c2ecf20Sopenharmony_ci		s |= BM_START;
5338c2ecf20Sopenharmony_ci		break;
5348c2ecf20Sopenharmony_ci	case NSP32_TRANSFER_MMIO:
5358c2ecf20Sopenharmony_ci		s |= CB_MMIO_MODE;
5368c2ecf20Sopenharmony_ci		break;
5378c2ecf20Sopenharmony_ci	case NSP32_TRANSFER_PIO:
5388c2ecf20Sopenharmony_ci		s |= CB_IO_MODE;
5398c2ecf20Sopenharmony_ci		break;
5408c2ecf20Sopenharmony_ci	default:
5418c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "unknown trans_method");
5428c2ecf20Sopenharmony_ci		break;
5438c2ecf20Sopenharmony_ci	}
5448c2ecf20Sopenharmony_ci	/*
5458c2ecf20Sopenharmony_ci	 * OR-ed BLIEND_MODE, FIFO intr is decreased, instead of PCI bus waits.
5468c2ecf20Sopenharmony_ci	 * For bus master transfer, it's taken off.
5478c2ecf20Sopenharmony_ci	 */
5488c2ecf20Sopenharmony_ci	s |= (TRANSFER_GO | ALL_COUNTER_CLR);
5498c2ecf20Sopenharmony_ci	param->transfer_control = cpu_to_le16(s);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	/* sg table addr */
5528c2ecf20Sopenharmony_ci	param->sgt_pointer = cpu_to_le32(data->cur_lunt->sglun_paddr);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	/*
5558c2ecf20Sopenharmony_ci	 * transfer parameter to ASIC
5568c2ecf20Sopenharmony_ci	 */
5578c2ecf20Sopenharmony_ci	nsp32_write4(base, SGT_ADR,         data->auto_paddr);
5588c2ecf20Sopenharmony_ci	nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER |
5598c2ecf20Sopenharmony_ci		                            AUTO_PARAMETER         );
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	/*
5628c2ecf20Sopenharmony_ci	 * Check arbitration
5638c2ecf20Sopenharmony_ci	 */
5648c2ecf20Sopenharmony_ci	ret = nsp32_arbitration(SCpnt, base);
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	return ret;
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci/*
5718c2ecf20Sopenharmony_ci * Selection with AUTO SCSI (without AUTO PARAMETER)
5728c2ecf20Sopenharmony_ci */
5738c2ecf20Sopenharmony_cistatic int nsp32_selection_autoscsi(struct scsi_cmnd *SCpnt)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	nsp32_hw_data  *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
5768c2ecf20Sopenharmony_ci	unsigned int	base    = SCpnt->device->host->io_port;
5778c2ecf20Sopenharmony_ci	unsigned int	host_id = SCpnt->device->host->this_id;
5788c2ecf20Sopenharmony_ci	unsigned char	target  = scmd_id(SCpnt);
5798c2ecf20Sopenharmony_ci	unsigned char	phase;
5808c2ecf20Sopenharmony_ci	int		status;
5818c2ecf20Sopenharmony_ci	unsigned short	command	= 0;
5828c2ecf20Sopenharmony_ci	unsigned int	msgout  = 0;
5838c2ecf20Sopenharmony_ci	unsigned short	execph;
5848c2ecf20Sopenharmony_ci	int		i;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in");
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	/*
5898c2ecf20Sopenharmony_ci	 * IRQ disable
5908c2ecf20Sopenharmony_ci	 */
5918c2ecf20Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	/*
5948c2ecf20Sopenharmony_ci	 * check bus line
5958c2ecf20Sopenharmony_ci	 */
5968c2ecf20Sopenharmony_ci	phase = nsp32_read1(base, SCSI_BUS_MONITOR);
5978c2ecf20Sopenharmony_ci	if ((phase & BUSMON_BSY) || (phase & BUSMON_SEL)) {
5988c2ecf20Sopenharmony_ci		nsp32_msg(KERN_WARNING, "bus busy");
5998c2ecf20Sopenharmony_ci		SCpnt->result = DID_BUS_BUSY << 16;
6008c2ecf20Sopenharmony_ci		status = 1;
6018c2ecf20Sopenharmony_ci		goto out;
6028c2ecf20Sopenharmony_ci        }
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	/*
6058c2ecf20Sopenharmony_ci	 * clear execph
6068c2ecf20Sopenharmony_ci	 */
6078c2ecf20Sopenharmony_ci	execph = nsp32_read2(base, SCSI_EXECUTE_PHASE);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	/*
6108c2ecf20Sopenharmony_ci	 * clear FIFO counter to set CDBs
6118c2ecf20Sopenharmony_ci	 */
6128c2ecf20Sopenharmony_ci	nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	/*
6158c2ecf20Sopenharmony_ci	 * set CDB0 - CDB15
6168c2ecf20Sopenharmony_ci	 */
6178c2ecf20Sopenharmony_ci	for (i = 0; i < SCpnt->cmd_len; i++) {
6188c2ecf20Sopenharmony_ci		nsp32_write1(base, COMMAND_DATA, SCpnt->cmnd[i]);
6198c2ecf20Sopenharmony_ci        }
6208c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_CDB_CONTENTS, "CDB[0]=[0x%x]", SCpnt->cmnd[0]);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	/*
6238c2ecf20Sopenharmony_ci	 * set SCSIOUT LATCH(initiator)/TARGET(target) (OR-ed) ID
6248c2ecf20Sopenharmony_ci	 */
6258c2ecf20Sopenharmony_ci	nsp32_write1(base, SCSI_OUT_LATCH_TARGET_ID, BIT(host_id) | BIT(target));
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	/*
6288c2ecf20Sopenharmony_ci	 * set SCSI MSGOUT REG
6298c2ecf20Sopenharmony_ci	 *
6308c2ecf20Sopenharmony_ci	 * Note: If the range of msgout_len is 1 - 3, fill scsi_msgout.
6318c2ecf20Sopenharmony_ci	 *       over 3 messages needs another routine.
6328c2ecf20Sopenharmony_ci	 */
6338c2ecf20Sopenharmony_ci	if (data->msgout_len == 0) {
6348c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!");
6358c2ecf20Sopenharmony_ci		SCpnt->result = DID_ERROR << 16;
6368c2ecf20Sopenharmony_ci		status = 1;
6378c2ecf20Sopenharmony_ci		goto out;
6388c2ecf20Sopenharmony_ci	} else if (data->msgout_len > 0 && data->msgout_len <= 3) {
6398c2ecf20Sopenharmony_ci		msgout = 0;
6408c2ecf20Sopenharmony_ci		for (i = 0; i < data->msgout_len; i++) {
6418c2ecf20Sopenharmony_ci			/*
6428c2ecf20Sopenharmony_ci			 * the sending order of the message is:
6438c2ecf20Sopenharmony_ci			 *  MCNT 3: MSG#0 -> MSG#1 -> MSG#2
6448c2ecf20Sopenharmony_ci			 *  MCNT 2:          MSG#1 -> MSG#2
6458c2ecf20Sopenharmony_ci			 *  MCNT 1:                   MSG#2
6468c2ecf20Sopenharmony_ci			 */
6478c2ecf20Sopenharmony_ci			msgout >>= 8;
6488c2ecf20Sopenharmony_ci			msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24);
6498c2ecf20Sopenharmony_ci		}
6508c2ecf20Sopenharmony_ci		msgout |= MV_VALID;	/* MV valid */
6518c2ecf20Sopenharmony_ci		msgout |= (unsigned int)data->msgout_len; /* len */
6528c2ecf20Sopenharmony_ci		nsp32_write4(base, SCSI_MSG_OUT, msgout);
6538c2ecf20Sopenharmony_ci	} else {
6548c2ecf20Sopenharmony_ci		/* data->msgout_len > 3 */
6558c2ecf20Sopenharmony_ci		nsp32_write4(base, SCSI_MSG_OUT, 0);
6568c2ecf20Sopenharmony_ci	}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	/*
6598c2ecf20Sopenharmony_ci	 * set selection timeout(= 250ms)
6608c2ecf20Sopenharmony_ci	 */
6618c2ecf20Sopenharmony_ci	nsp32_write2(base, SEL_TIME_OUT,   SEL_TIMEOUT_TIME);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	/*
6648c2ecf20Sopenharmony_ci	 * set SREQ hazard killer sampling rate
6658c2ecf20Sopenharmony_ci	 *
6668c2ecf20Sopenharmony_ci	 * TODO: sample_rate (BASE+0F) is 0 when internal clock = 40MHz.
6678c2ecf20Sopenharmony_ci	 *      check other internal clock!
6688c2ecf20Sopenharmony_ci	 */
6698c2ecf20Sopenharmony_ci	nsp32_write1(base, SREQ_SMPL_RATE, data->cur_target->sample_reg);
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	/*
6728c2ecf20Sopenharmony_ci	 * clear Arbit
6738c2ecf20Sopenharmony_ci	 */
6748c2ecf20Sopenharmony_ci	nsp32_write1(base, SET_ARBIT,      ARBIT_CLEAR);
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	/*
6778c2ecf20Sopenharmony_ci	 * set SYNCREG
6788c2ecf20Sopenharmony_ci	 * Don't set BM_START_ADR before setting this register.
6798c2ecf20Sopenharmony_ci	 */
6808c2ecf20Sopenharmony_ci	nsp32_write1(base, SYNC_REG,  data->cur_target->syncreg);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	/*
6838c2ecf20Sopenharmony_ci	 * set ACKWIDTH
6848c2ecf20Sopenharmony_ci	 */
6858c2ecf20Sopenharmony_ci	nsp32_write1(base, ACK_WIDTH, data->cur_target->ackwidth);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_AUTOSCSI,
6888c2ecf20Sopenharmony_ci		  "syncreg=0x%x, ackwidth=0x%x, sgtpaddr=0x%x, id=0x%x",
6898c2ecf20Sopenharmony_ci		  nsp32_read1(base, SYNC_REG), nsp32_read1(base, ACK_WIDTH),
6908c2ecf20Sopenharmony_ci		  nsp32_read4(base, SGT_ADR), nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID));
6918c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "msgout_len=%d, msgout=0x%x",
6928c2ecf20Sopenharmony_ci		  data->msgout_len, msgout);
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	/*
6958c2ecf20Sopenharmony_ci	 * set SGT ADDR (physical address)
6968c2ecf20Sopenharmony_ci	 */
6978c2ecf20Sopenharmony_ci	nsp32_write4(base, SGT_ADR, data->cur_lunt->sglun_paddr);
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	/*
7008c2ecf20Sopenharmony_ci	 * set TRANSFER CONTROL REG
7018c2ecf20Sopenharmony_ci	 */
7028c2ecf20Sopenharmony_ci	command = 0;
7038c2ecf20Sopenharmony_ci	command |= (TRANSFER_GO | ALL_COUNTER_CLR);
7048c2ecf20Sopenharmony_ci	if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
7058c2ecf20Sopenharmony_ci		if (scsi_bufflen(SCpnt) > 0) {
7068c2ecf20Sopenharmony_ci			command |= BM_START;
7078c2ecf20Sopenharmony_ci		}
7088c2ecf20Sopenharmony_ci	} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
7098c2ecf20Sopenharmony_ci		command |= CB_MMIO_MODE;
7108c2ecf20Sopenharmony_ci	} else if (data->trans_method & NSP32_TRANSFER_PIO) {
7118c2ecf20Sopenharmony_ci		command |= CB_IO_MODE;
7128c2ecf20Sopenharmony_ci	}
7138c2ecf20Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL, command);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	/*
7168c2ecf20Sopenharmony_ci	 * start AUTO SCSI, kick off arbitration
7178c2ecf20Sopenharmony_ci	 */
7188c2ecf20Sopenharmony_ci	command = (CLEAR_CDB_FIFO_POINTER |
7198c2ecf20Sopenharmony_ci		   AUTOSCSI_START         |
7208c2ecf20Sopenharmony_ci		   AUTO_MSGIN_00_OR_04    |
7218c2ecf20Sopenharmony_ci		   AUTO_MSGIN_02          |
7228c2ecf20Sopenharmony_ci		   AUTO_ATN                );
7238c2ecf20Sopenharmony_ci	nsp32_write2(base, COMMAND_CONTROL, command);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	/*
7268c2ecf20Sopenharmony_ci	 * Check arbitration
7278c2ecf20Sopenharmony_ci	 */
7288c2ecf20Sopenharmony_ci	status = nsp32_arbitration(SCpnt, base);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci out:
7318c2ecf20Sopenharmony_ci	/*
7328c2ecf20Sopenharmony_ci	 * IRQ enable
7338c2ecf20Sopenharmony_ci	 */
7348c2ecf20Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, 0);
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	return status;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci/*
7418c2ecf20Sopenharmony_ci * Arbitration Status Check
7428c2ecf20Sopenharmony_ci *
7438c2ecf20Sopenharmony_ci * Note: Arbitration counter is waited during ARBIT_GO is not lifting.
7448c2ecf20Sopenharmony_ci *	 Using udelay(1) consumes CPU time and system time, but
7458c2ecf20Sopenharmony_ci *	 arbitration delay time is defined minimal 2.4us in SCSI
7468c2ecf20Sopenharmony_ci *	 specification, thus udelay works as coarse grained wait timer.
7478c2ecf20Sopenharmony_ci */
7488c2ecf20Sopenharmony_cistatic int nsp32_arbitration(struct scsi_cmnd *SCpnt, unsigned int base)
7498c2ecf20Sopenharmony_ci{
7508c2ecf20Sopenharmony_ci	unsigned char arbit;
7518c2ecf20Sopenharmony_ci	int	      status = TRUE;
7528c2ecf20Sopenharmony_ci	int	      time   = 0;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	do {
7558c2ecf20Sopenharmony_ci		arbit = nsp32_read1(base, ARBIT_STATUS);
7568c2ecf20Sopenharmony_ci		time++;
7578c2ecf20Sopenharmony_ci	} while ((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
7588c2ecf20Sopenharmony_ci		 (time <= ARBIT_TIMEOUT_TIME));
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_AUTOSCSI,
7618c2ecf20Sopenharmony_ci		  "arbit: 0x%x, delay time: %d", arbit, time);
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	if (arbit & ARBIT_WIN) {
7648c2ecf20Sopenharmony_ci		/* Arbitration succeeded */
7658c2ecf20Sopenharmony_ci		SCpnt->result = DID_OK << 16;
7668c2ecf20Sopenharmony_ci		nsp32_index_write1(base, EXT_PORT, LED_ON); /* PCI LED on */
7678c2ecf20Sopenharmony_ci	} else if (arbit & ARBIT_FAIL) {
7688c2ecf20Sopenharmony_ci		/* Arbitration failed */
7698c2ecf20Sopenharmony_ci		SCpnt->result = DID_BUS_BUSY << 16;
7708c2ecf20Sopenharmony_ci		status = FALSE;
7718c2ecf20Sopenharmony_ci	} else {
7728c2ecf20Sopenharmony_ci		/*
7738c2ecf20Sopenharmony_ci		 * unknown error or ARBIT_GO timeout,
7748c2ecf20Sopenharmony_ci		 * something lock up! guess no connection.
7758c2ecf20Sopenharmony_ci		 */
7768c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit timeout");
7778c2ecf20Sopenharmony_ci		SCpnt->result = DID_NO_CONNECT << 16;
7788c2ecf20Sopenharmony_ci		status = FALSE;
7798c2ecf20Sopenharmony_ci        }
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	/*
7828c2ecf20Sopenharmony_ci	 * clear Arbit
7838c2ecf20Sopenharmony_ci	 */
7848c2ecf20Sopenharmony_ci	nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	return status;
7878c2ecf20Sopenharmony_ci}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci/*
7918c2ecf20Sopenharmony_ci * reselection
7928c2ecf20Sopenharmony_ci *
7938c2ecf20Sopenharmony_ci * Note: This reselection routine is called from msgin_occur,
7948c2ecf20Sopenharmony_ci *	 reselection target id&lun must be already set.
7958c2ecf20Sopenharmony_ci *	 SCSI-2 says IDENTIFY implies RESTORE_POINTER operation.
7968c2ecf20Sopenharmony_ci */
7978c2ecf20Sopenharmony_cistatic int nsp32_reselection(struct scsi_cmnd *SCpnt, unsigned char newlun)
7988c2ecf20Sopenharmony_ci{
7998c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
8008c2ecf20Sopenharmony_ci	unsigned int   host_id = SCpnt->device->host->this_id;
8018c2ecf20Sopenharmony_ci	unsigned int   base    = SCpnt->device->host->io_port;
8028c2ecf20Sopenharmony_ci	unsigned char  tmpid, newid;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_RESELECTION, "enter");
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	/*
8078c2ecf20Sopenharmony_ci	 * calculate reselected SCSI ID
8088c2ecf20Sopenharmony_ci	 */
8098c2ecf20Sopenharmony_ci	tmpid = nsp32_read1(base, RESELECT_ID);
8108c2ecf20Sopenharmony_ci	tmpid &= (~BIT(host_id));
8118c2ecf20Sopenharmony_ci	newid = 0;
8128c2ecf20Sopenharmony_ci	while (tmpid) {
8138c2ecf20Sopenharmony_ci		if (tmpid & 1) {
8148c2ecf20Sopenharmony_ci			break;
8158c2ecf20Sopenharmony_ci		}
8168c2ecf20Sopenharmony_ci		tmpid >>= 1;
8178c2ecf20Sopenharmony_ci		newid++;
8188c2ecf20Sopenharmony_ci	}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	/*
8218c2ecf20Sopenharmony_ci	 * If reselected New ID:LUN is not existed
8228c2ecf20Sopenharmony_ci	 * or current nexus is not existed, unexpected
8238c2ecf20Sopenharmony_ci	 * reselection is occurred. Send reject message.
8248c2ecf20Sopenharmony_ci	 */
8258c2ecf20Sopenharmony_ci	if (newid >= ARRAY_SIZE(data->lunt) || newlun >= ARRAY_SIZE(data->lunt[0])) {
8268c2ecf20Sopenharmony_ci		nsp32_msg(KERN_WARNING, "unknown id/lun");
8278c2ecf20Sopenharmony_ci		return FALSE;
8288c2ecf20Sopenharmony_ci	} else if(data->lunt[newid][newlun].SCpnt == NULL) {
8298c2ecf20Sopenharmony_ci		nsp32_msg(KERN_WARNING, "no SCSI command is processing");
8308c2ecf20Sopenharmony_ci		return FALSE;
8318c2ecf20Sopenharmony_ci	}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	data->cur_id    = newid;
8348c2ecf20Sopenharmony_ci	data->cur_lun   = newlun;
8358c2ecf20Sopenharmony_ci	data->cur_target = &(data->target[newid]);
8368c2ecf20Sopenharmony_ci	data->cur_lunt   = &(data->lunt[newid][newlun]);
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	/* reset SACK/SavedACK counter (or ALL clear?) */
8398c2ecf20Sopenharmony_ci	nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	return TRUE;
8428c2ecf20Sopenharmony_ci}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci/*
8468c2ecf20Sopenharmony_ci * nsp32_setup_sg_table - build scatter gather list for transfer data
8478c2ecf20Sopenharmony_ci *			    with bus master.
8488c2ecf20Sopenharmony_ci *
8498c2ecf20Sopenharmony_ci * Note: NinjaSCSI-32Bi/UDE bus master can not transfer over 64KB at a time.
8508c2ecf20Sopenharmony_ci */
8518c2ecf20Sopenharmony_cistatic int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
8548c2ecf20Sopenharmony_ci	struct scatterlist *sg;
8558c2ecf20Sopenharmony_ci	nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt;
8568c2ecf20Sopenharmony_ci	int num, i;
8578c2ecf20Sopenharmony_ci	u32_le l;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	if (sgt == NULL) {
8608c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_SGLIST, "SGT == null");
8618c2ecf20Sopenharmony_ci		return FALSE;
8628c2ecf20Sopenharmony_ci	}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	num = scsi_dma_map(SCpnt);
8658c2ecf20Sopenharmony_ci	if (!num)
8668c2ecf20Sopenharmony_ci		return TRUE;
8678c2ecf20Sopenharmony_ci	else if (num < 0)
8688c2ecf20Sopenharmony_ci		return FALSE;
8698c2ecf20Sopenharmony_ci	else {
8708c2ecf20Sopenharmony_ci		scsi_for_each_sg(SCpnt, sg, num, i) {
8718c2ecf20Sopenharmony_ci			/*
8728c2ecf20Sopenharmony_ci			 * Build nsp32_sglist, substitute sg dma addresses.
8738c2ecf20Sopenharmony_ci			 */
8748c2ecf20Sopenharmony_ci			sgt[i].addr = cpu_to_le32(sg_dma_address(sg));
8758c2ecf20Sopenharmony_ci			sgt[i].len  = cpu_to_le32(sg_dma_len(sg));
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci			if (le32_to_cpu(sgt[i].len) > 0x10000) {
8788c2ecf20Sopenharmony_ci				nsp32_msg(KERN_ERR,
8798c2ecf20Sopenharmony_ci					"can't transfer over 64KB at a time, size=0x%lx", le32_to_cpu(sgt[i].len));
8808c2ecf20Sopenharmony_ci				return FALSE;
8818c2ecf20Sopenharmony_ci			}
8828c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_SGLIST,
8838c2ecf20Sopenharmony_ci				  "num 0x%x : addr 0x%lx len 0x%lx",
8848c2ecf20Sopenharmony_ci				  i,
8858c2ecf20Sopenharmony_ci				  le32_to_cpu(sgt[i].addr),
8868c2ecf20Sopenharmony_ci				  le32_to_cpu(sgt[i].len ));
8878c2ecf20Sopenharmony_ci		}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci		/* set end mark */
8908c2ecf20Sopenharmony_ci		l = le32_to_cpu(sgt[num-1].len);
8918c2ecf20Sopenharmony_ci		sgt[num-1].len = cpu_to_le32(l | SGTEND);
8928c2ecf20Sopenharmony_ci	}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	return TRUE;
8958c2ecf20Sopenharmony_ci}
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_cistatic int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
8988c2ecf20Sopenharmony_ci{
8998c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
9008c2ecf20Sopenharmony_ci	nsp32_target *target;
9018c2ecf20Sopenharmony_ci	nsp32_lunt   *cur_lunt;
9028c2ecf20Sopenharmony_ci	int ret;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
9058c2ecf20Sopenharmony_ci		  "enter. target: 0x%x LUN: 0x%llx cmnd: 0x%x cmndlen: 0x%x "
9068c2ecf20Sopenharmony_ci		  "use_sg: 0x%x reqbuf: 0x%lx reqlen: 0x%x",
9078c2ecf20Sopenharmony_ci		  SCpnt->device->id, SCpnt->device->lun, SCpnt->cmnd[0], SCpnt->cmd_len,
9088c2ecf20Sopenharmony_ci		  scsi_sg_count(SCpnt), scsi_sglist(SCpnt), scsi_bufflen(SCpnt));
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	if (data->CurrentSC != NULL) {
9118c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "Currentsc != NULL. Cancel this command request");
9128c2ecf20Sopenharmony_ci		data->CurrentSC = NULL;
9138c2ecf20Sopenharmony_ci		SCpnt->result   = DID_NO_CONNECT << 16;
9148c2ecf20Sopenharmony_ci		done(SCpnt);
9158c2ecf20Sopenharmony_ci		return 0;
9168c2ecf20Sopenharmony_ci	}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	/* check target ID is not same as this initiator ID */
9198c2ecf20Sopenharmony_ci	if (scmd_id(SCpnt) == SCpnt->device->host->this_id) {
9208c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "target==host???");
9218c2ecf20Sopenharmony_ci		SCpnt->result = DID_BAD_TARGET << 16;
9228c2ecf20Sopenharmony_ci		done(SCpnt);
9238c2ecf20Sopenharmony_ci		return 0;
9248c2ecf20Sopenharmony_ci	}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	/* check target LUN is allowable value */
9278c2ecf20Sopenharmony_ci	if (SCpnt->device->lun >= MAX_LUN) {
9288c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "no more lun");
9298c2ecf20Sopenharmony_ci		SCpnt->result = DID_BAD_TARGET << 16;
9308c2ecf20Sopenharmony_ci		done(SCpnt);
9318c2ecf20Sopenharmony_ci		return 0;
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	show_command(SCpnt);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	SCpnt->scsi_done     = done;
9378c2ecf20Sopenharmony_ci	data->CurrentSC      = SCpnt;
9388c2ecf20Sopenharmony_ci	SCpnt->SCp.Status    = CHECK_CONDITION;
9398c2ecf20Sopenharmony_ci	SCpnt->SCp.Message   = 0;
9408c2ecf20Sopenharmony_ci	scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	SCpnt->SCp.ptr		    = (char *)scsi_sglist(SCpnt);
9438c2ecf20Sopenharmony_ci	SCpnt->SCp.this_residual    = scsi_bufflen(SCpnt);
9448c2ecf20Sopenharmony_ci	SCpnt->SCp.buffer	    = NULL;
9458c2ecf20Sopenharmony_ci	SCpnt->SCp.buffers_residual = 0;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	/* initialize data */
9488c2ecf20Sopenharmony_ci	data->msgout_len	= 0;
9498c2ecf20Sopenharmony_ci	data->msgin_len		= 0;
9508c2ecf20Sopenharmony_ci	cur_lunt		= &(data->lunt[SCpnt->device->id][SCpnt->device->lun]);
9518c2ecf20Sopenharmony_ci	cur_lunt->SCpnt		= SCpnt;
9528c2ecf20Sopenharmony_ci	cur_lunt->save_datp	= 0;
9538c2ecf20Sopenharmony_ci	cur_lunt->msgin03	= FALSE;
9548c2ecf20Sopenharmony_ci	data->cur_lunt		= cur_lunt;
9558c2ecf20Sopenharmony_ci	data->cur_id		= SCpnt->device->id;
9568c2ecf20Sopenharmony_ci	data->cur_lun		= SCpnt->device->lun;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	ret = nsp32_setup_sg_table(SCpnt);
9598c2ecf20Sopenharmony_ci	if (ret == FALSE) {
9608c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "SGT fail");
9618c2ecf20Sopenharmony_ci		SCpnt->result = DID_ERROR << 16;
9628c2ecf20Sopenharmony_ci		nsp32_scsi_done(SCpnt);
9638c2ecf20Sopenharmony_ci		return 0;
9648c2ecf20Sopenharmony_ci	}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	/* Build IDENTIFY */
9678c2ecf20Sopenharmony_ci	nsp32_build_identify(SCpnt);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	/*
9708c2ecf20Sopenharmony_ci	 * If target is the first time to transfer after the reset
9718c2ecf20Sopenharmony_ci	 * (target don't have SDTR_DONE and SDTR_INITIATOR), sync
9728c2ecf20Sopenharmony_ci	 * message SDTR is needed to do synchronous transfer.
9738c2ecf20Sopenharmony_ci	 */
9748c2ecf20Sopenharmony_ci	target = &data->target[scmd_id(SCpnt)];
9758c2ecf20Sopenharmony_ci	data->cur_target = target;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	if (!(target->sync_flag & (SDTR_DONE | SDTR_INITIATOR | SDTR_TARGET))) {
9788c2ecf20Sopenharmony_ci		unsigned char period, offset;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci		if (trans_mode != ASYNC_MODE) {
9818c2ecf20Sopenharmony_ci			nsp32_set_max_sync(data, target, &period, &offset);
9828c2ecf20Sopenharmony_ci			nsp32_build_sdtr(SCpnt, period, offset);
9838c2ecf20Sopenharmony_ci			target->sync_flag |= SDTR_INITIATOR;
9848c2ecf20Sopenharmony_ci		} else {
9858c2ecf20Sopenharmony_ci			nsp32_set_async(data, target);
9868c2ecf20Sopenharmony_ci			target->sync_flag |= SDTR_DONE;
9878c2ecf20Sopenharmony_ci		}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
9908c2ecf20Sopenharmony_ci			  "SDTR: entry: %d start_period: 0x%x offset: 0x%x\n",
9918c2ecf20Sopenharmony_ci			  target->limit_entry, period, offset);
9928c2ecf20Sopenharmony_ci	} else if (target->sync_flag & SDTR_INITIATOR) {
9938c2ecf20Sopenharmony_ci		/*
9948c2ecf20Sopenharmony_ci		 * It was negotiating SDTR with target, sending from the
9958c2ecf20Sopenharmony_ci		 * initiator, but there are no chance to remove this flag.
9968c2ecf20Sopenharmony_ci		 * Set async because we don't get proper negotiation.
9978c2ecf20Sopenharmony_ci		 */
9988c2ecf20Sopenharmony_ci		nsp32_set_async(data, target);
9998c2ecf20Sopenharmony_ci		target->sync_flag &= ~SDTR_INITIATOR;
10008c2ecf20Sopenharmony_ci		target->sync_flag |= SDTR_DONE;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
10038c2ecf20Sopenharmony_ci			  "SDTR_INITIATOR: fall back to async");
10048c2ecf20Sopenharmony_ci	} else if (target->sync_flag & SDTR_TARGET) {
10058c2ecf20Sopenharmony_ci		/*
10068c2ecf20Sopenharmony_ci		 * It was negotiating SDTR with target, sending from target,
10078c2ecf20Sopenharmony_ci		 * but there are no chance to remove this flag.  Set async
10088c2ecf20Sopenharmony_ci		 * because we don't get proper negotiation.
10098c2ecf20Sopenharmony_ci		 */
10108c2ecf20Sopenharmony_ci		nsp32_set_async(data, target);
10118c2ecf20Sopenharmony_ci		target->sync_flag &= ~SDTR_TARGET;
10128c2ecf20Sopenharmony_ci		target->sync_flag |= SDTR_DONE;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
10158c2ecf20Sopenharmony_ci			  "Unknown SDTR from target is reached, fall back to async.");
10168c2ecf20Sopenharmony_ci	}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_TARGETFLAG,
10198c2ecf20Sopenharmony_ci		  "target: %d sync_flag: 0x%x syncreg: 0x%x ackwidth: 0x%x",
10208c2ecf20Sopenharmony_ci		  SCpnt->device->id, target->sync_flag, target->syncreg,
10218c2ecf20Sopenharmony_ci		  target->ackwidth);
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	/* Selection */
10248c2ecf20Sopenharmony_ci	if (auto_param == 0) {
10258c2ecf20Sopenharmony_ci		ret = nsp32_selection_autopara(SCpnt);
10268c2ecf20Sopenharmony_ci	} else {
10278c2ecf20Sopenharmony_ci		ret = nsp32_selection_autoscsi(SCpnt);
10288c2ecf20Sopenharmony_ci	}
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	if (ret != TRUE) {
10318c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "selection fail");
10328c2ecf20Sopenharmony_ci		nsp32_scsi_done(SCpnt);
10338c2ecf20Sopenharmony_ci	}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	return 0;
10368c2ecf20Sopenharmony_ci}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(nsp32_queuecommand)
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci/* initialize asic */
10418c2ecf20Sopenharmony_cistatic int nsp32hw_init(nsp32_hw_data *data)
10428c2ecf20Sopenharmony_ci{
10438c2ecf20Sopenharmony_ci	unsigned int   base = data->BaseAddress;
10448c2ecf20Sopenharmony_ci	unsigned short irq_stat;
10458c2ecf20Sopenharmony_ci	unsigned long  lc_reg;
10468c2ecf20Sopenharmony_ci	unsigned char  power;
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	lc_reg = nsp32_index_read4(base, CFG_LATE_CACHE);
10498c2ecf20Sopenharmony_ci	if ((lc_reg & 0xff00) == 0) {
10508c2ecf20Sopenharmony_ci		lc_reg |= (0x20 << 8);
10518c2ecf20Sopenharmony_ci		nsp32_index_write2(base, CFG_LATE_CACHE, lc_reg & 0xffff);
10528c2ecf20Sopenharmony_ci	}
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL,        IRQ_CONTROL_ALL_IRQ_MASK);
10558c2ecf20Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL,   0);
10568c2ecf20Sopenharmony_ci	nsp32_write4(base, BM_CNT,             0);
10578c2ecf20Sopenharmony_ci	nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	do {
10608c2ecf20Sopenharmony_ci		irq_stat = nsp32_read2(base, IRQ_STATUS);
10618c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INIT, "irq_stat 0x%x", irq_stat);
10628c2ecf20Sopenharmony_ci	} while (irq_stat & IRQSTATUS_ANY_IRQ);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	/*
10658c2ecf20Sopenharmony_ci	 * Fill FIFO_FULL_SHLD, FIFO_EMPTY_SHLD. Below parameter is
10668c2ecf20Sopenharmony_ci	 *  designated by specification.
10678c2ecf20Sopenharmony_ci	 */
10688c2ecf20Sopenharmony_ci	if ((data->trans_method & NSP32_TRANSFER_PIO) ||
10698c2ecf20Sopenharmony_ci	    (data->trans_method & NSP32_TRANSFER_MMIO)) {
10708c2ecf20Sopenharmony_ci		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT,  0x40);
10718c2ecf20Sopenharmony_ci		nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x40);
10728c2ecf20Sopenharmony_ci	} else if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
10738c2ecf20Sopenharmony_ci		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT,  0x10);
10748c2ecf20Sopenharmony_ci		nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x60);
10758c2ecf20Sopenharmony_ci	} else {
10768c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INIT, "unknown transfer mode");
10778c2ecf20Sopenharmony_ci	}
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_INIT, "full 0x%x emp 0x%x",
10808c2ecf20Sopenharmony_ci		  nsp32_index_read1(base, FIFO_FULL_SHLD_COUNT),
10818c2ecf20Sopenharmony_ci		  nsp32_index_read1(base, FIFO_EMPTY_SHLD_COUNT));
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	nsp32_index_write1(base, CLOCK_DIV, data->clock);
10848c2ecf20Sopenharmony_ci	nsp32_index_write1(base, BM_CYCLE,  MEMRD_CMD1 | SGT_AUTO_PARA_MEMED_CMD);
10858c2ecf20Sopenharmony_ci	nsp32_write1(base, PARITY_CONTROL, 0);	/* parity check is disable */
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	/*
10888c2ecf20Sopenharmony_ci	 * initialize MISC_WRRD register
10898c2ecf20Sopenharmony_ci	 *
10908c2ecf20Sopenharmony_ci	 * Note: Designated parameters is obeyed as following:
10918c2ecf20Sopenharmony_ci	 *	MISC_SCSI_DIRECTION_DETECTOR_SELECT: It must be set.
10928c2ecf20Sopenharmony_ci	 *	MISC_MASTER_TERMINATION_SELECT:      It must be set.
10938c2ecf20Sopenharmony_ci	 *	MISC_BMREQ_NEGATE_TIMING_SEL:	     It should be set.
10948c2ecf20Sopenharmony_ci	 *	MISC_AUTOSEL_TIMING_SEL:	     It should be set.
10958c2ecf20Sopenharmony_ci	 *	MISC_BMSTOP_CHANGE2_NONDATA_PHASE:   It should be set.
10968c2ecf20Sopenharmony_ci	 *	MISC_DELAYED_BMSTART:		     It's selected for safety.
10978c2ecf20Sopenharmony_ci	 *
10988c2ecf20Sopenharmony_ci	 * Note: If MISC_BMSTOP_CHANGE2_NONDATA_PHASE is set, then
10998c2ecf20Sopenharmony_ci	 *	we have to set TRANSFERCONTROL_BM_START as 0 and set
11008c2ecf20Sopenharmony_ci	 *	appropriate value before restarting bus master transfer.
11018c2ecf20Sopenharmony_ci	 */
11028c2ecf20Sopenharmony_ci	nsp32_index_write2(base, MISC_WR,
11038c2ecf20Sopenharmony_ci			   (SCSI_DIRECTION_DETECTOR_SELECT |
11048c2ecf20Sopenharmony_ci			    DELAYED_BMSTART                |
11058c2ecf20Sopenharmony_ci			    MASTER_TERMINATION_SELECT      |
11068c2ecf20Sopenharmony_ci			    BMREQ_NEGATE_TIMING_SEL        |
11078c2ecf20Sopenharmony_ci			    AUTOSEL_TIMING_SEL             |
11088c2ecf20Sopenharmony_ci			    BMSTOP_CHANGE2_NONDATA_PHASE));
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	nsp32_index_write1(base, TERM_PWR_CONTROL, 0);
11118c2ecf20Sopenharmony_ci	power = nsp32_index_read1(base, TERM_PWR_CONTROL);
11128c2ecf20Sopenharmony_ci	if (!(power & SENSE)) {
11138c2ecf20Sopenharmony_ci		nsp32_msg(KERN_INFO, "term power on");
11148c2ecf20Sopenharmony_ci		nsp32_index_write1(base, TERM_PWR_CONTROL, BPWR);
11158c2ecf20Sopenharmony_ci	}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	nsp32_write2(base, TIMER_SET, TIMER_STOP);
11188c2ecf20Sopenharmony_ci	nsp32_write2(base, TIMER_SET, TIMER_STOP); /* Required 2 times */
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	nsp32_write1(base, SYNC_REG,     0);
11218c2ecf20Sopenharmony_ci	nsp32_write1(base, ACK_WIDTH,    0);
11228c2ecf20Sopenharmony_ci	nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME);
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	/*
11258c2ecf20Sopenharmony_ci	 * enable to select designated IRQ (except for
11268c2ecf20Sopenharmony_ci	 * IRQSELECT_SERR, IRQSELECT_PERR, IRQSELECT_BMCNTERR)
11278c2ecf20Sopenharmony_ci	 */
11288c2ecf20Sopenharmony_ci	nsp32_index_write2(base, IRQ_SELECT, IRQSELECT_TIMER_IRQ         |
11298c2ecf20Sopenharmony_ci			                     IRQSELECT_SCSIRESET_IRQ     |
11308c2ecf20Sopenharmony_ci			                     IRQSELECT_FIFO_SHLD_IRQ     |
11318c2ecf20Sopenharmony_ci			                     IRQSELECT_RESELECT_IRQ      |
11328c2ecf20Sopenharmony_ci			                     IRQSELECT_PHASE_CHANGE_IRQ  |
11338c2ecf20Sopenharmony_ci			                     IRQSELECT_AUTO_SCSI_SEQ_IRQ |
11348c2ecf20Sopenharmony_ci			                  //   IRQSELECT_BMCNTERR_IRQ      |
11358c2ecf20Sopenharmony_ci			                     IRQSELECT_TARGET_ABORT_IRQ  |
11368c2ecf20Sopenharmony_ci			                     IRQSELECT_MASTER_ABORT_IRQ );
11378c2ecf20Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, 0);
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	/* PCI LED off */
11408c2ecf20Sopenharmony_ci	nsp32_index_write1(base, EXT_PORT_DDR, LED_OFF);
11418c2ecf20Sopenharmony_ci	nsp32_index_write1(base, EXT_PORT,     LED_OFF);
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	return TRUE;
11448c2ecf20Sopenharmony_ci}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci/* interrupt routine */
11488c2ecf20Sopenharmony_cistatic irqreturn_t do_nsp32_isr(int irq, void *dev_id)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	nsp32_hw_data *data = dev_id;
11518c2ecf20Sopenharmony_ci	unsigned int base = data->BaseAddress;
11528c2ecf20Sopenharmony_ci	struct scsi_cmnd *SCpnt = data->CurrentSC;
11538c2ecf20Sopenharmony_ci	unsigned short auto_stat, irq_stat, trans_stat;
11548c2ecf20Sopenharmony_ci	unsigned char busmon, busphase;
11558c2ecf20Sopenharmony_ci	unsigned long flags;
11568c2ecf20Sopenharmony_ci	int ret;
11578c2ecf20Sopenharmony_ci	int handled = 0;
11588c2ecf20Sopenharmony_ci	struct Scsi_Host *host = data->Host;
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	spin_lock_irqsave(host->host_lock, flags);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	/*
11638c2ecf20Sopenharmony_ci	 * IRQ check, then enable IRQ mask
11648c2ecf20Sopenharmony_ci	 */
11658c2ecf20Sopenharmony_ci	irq_stat = nsp32_read2(base, IRQ_STATUS);
11668c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_INTR,
11678c2ecf20Sopenharmony_ci		  "enter IRQ: %d, IRQstatus: 0x%x", irq, irq_stat);
11688c2ecf20Sopenharmony_ci	/* is this interrupt comes from Ninja asic? */
11698c2ecf20Sopenharmony_ci	if ((irq_stat & IRQSTATUS_ANY_IRQ) == 0) {
11708c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INTR, "shared interrupt: irq other 0x%x", irq_stat);
11718c2ecf20Sopenharmony_ci		goto out2;
11728c2ecf20Sopenharmony_ci	}
11738c2ecf20Sopenharmony_ci	handled = 1;
11748c2ecf20Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	busmon = nsp32_read1(base, SCSI_BUS_MONITOR);
11778c2ecf20Sopenharmony_ci	busphase = busmon & BUSMON_PHASE_MASK;
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	trans_stat = nsp32_read2(base, TRANSFER_STATUS);
11808c2ecf20Sopenharmony_ci	if ((irq_stat == 0xffff) && (trans_stat == 0xffff)) {
11818c2ecf20Sopenharmony_ci		nsp32_msg(KERN_INFO, "card disconnect");
11828c2ecf20Sopenharmony_ci		if (data->CurrentSC != NULL) {
11838c2ecf20Sopenharmony_ci			nsp32_msg(KERN_INFO, "clean up current SCSI command");
11848c2ecf20Sopenharmony_ci			SCpnt->result = DID_BAD_TARGET << 16;
11858c2ecf20Sopenharmony_ci			nsp32_scsi_done(SCpnt);
11868c2ecf20Sopenharmony_ci		}
11878c2ecf20Sopenharmony_ci		goto out;
11888c2ecf20Sopenharmony_ci	}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	/* Timer IRQ */
11918c2ecf20Sopenharmony_ci	if (irq_stat & IRQSTATUS_TIMER_IRQ) {
11928c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INTR, "timer stop");
11938c2ecf20Sopenharmony_ci		nsp32_write2(base, TIMER_SET, TIMER_STOP);
11948c2ecf20Sopenharmony_ci		goto out;
11958c2ecf20Sopenharmony_ci	}
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	/* SCSI reset */
11988c2ecf20Sopenharmony_ci	if (irq_stat & IRQSTATUS_SCSIRESET_IRQ) {
11998c2ecf20Sopenharmony_ci		nsp32_msg(KERN_INFO, "detected someone do bus reset");
12008c2ecf20Sopenharmony_ci		nsp32_do_bus_reset(data);
12018c2ecf20Sopenharmony_ci		if (SCpnt != NULL) {
12028c2ecf20Sopenharmony_ci			SCpnt->result = DID_RESET << 16;
12038c2ecf20Sopenharmony_ci			nsp32_scsi_done(SCpnt);
12048c2ecf20Sopenharmony_ci		}
12058c2ecf20Sopenharmony_ci		goto out;
12068c2ecf20Sopenharmony_ci	}
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	if (SCpnt == NULL) {
12098c2ecf20Sopenharmony_ci		nsp32_msg(KERN_WARNING, "SCpnt==NULL this can't be happened");
12108c2ecf20Sopenharmony_ci		nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat);
12118c2ecf20Sopenharmony_ci		goto out;
12128c2ecf20Sopenharmony_ci	}
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	/*
12158c2ecf20Sopenharmony_ci	 * AutoSCSI Interrupt.
12168c2ecf20Sopenharmony_ci	 * Note: This interrupt is occurred when AutoSCSI is finished.  Then
12178c2ecf20Sopenharmony_ci	 * check SCSIEXECUTEPHASE, and do appropriate action.  Each phases are
12188c2ecf20Sopenharmony_ci	 * recorded when AutoSCSI sequencer has been processed.
12198c2ecf20Sopenharmony_ci	 */
12208c2ecf20Sopenharmony_ci	if(irq_stat & IRQSTATUS_AUTOSCSI_IRQ) {
12218c2ecf20Sopenharmony_ci		/* getting SCSI executed phase */
12228c2ecf20Sopenharmony_ci		auto_stat = nsp32_read2(base, SCSI_EXECUTE_PHASE);
12238c2ecf20Sopenharmony_ci		nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci		/* Selection Timeout, go busfree phase. */
12268c2ecf20Sopenharmony_ci		if (auto_stat & SELECTION_TIMEOUT) {
12278c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR,
12288c2ecf20Sopenharmony_ci				  "selection timeout occurred");
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci			SCpnt->result = DID_TIME_OUT << 16;
12318c2ecf20Sopenharmony_ci			nsp32_scsi_done(SCpnt);
12328c2ecf20Sopenharmony_ci			goto out;
12338c2ecf20Sopenharmony_ci		}
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci		if (auto_stat & MSGOUT_PHASE) {
12368c2ecf20Sopenharmony_ci			/*
12378c2ecf20Sopenharmony_ci			 * MsgOut phase was processed.
12388c2ecf20Sopenharmony_ci			 * If MSG_IN_OCCUER is not set, then MsgOut phase is
12398c2ecf20Sopenharmony_ci			 * completed. Thus, msgout_len must reset.  Otherwise,
12408c2ecf20Sopenharmony_ci			 * nothing to do here. If MSG_OUT_OCCUER is occurred,
12418c2ecf20Sopenharmony_ci			 * then we will encounter the condition and check.
12428c2ecf20Sopenharmony_ci			 */
12438c2ecf20Sopenharmony_ci			if (!(auto_stat & MSG_IN_OCCUER) &&
12448c2ecf20Sopenharmony_ci			     (data->msgout_len <= 3)) {
12458c2ecf20Sopenharmony_ci				/*
12468c2ecf20Sopenharmony_ci				 * !MSG_IN_OCCUER && msgout_len <=3
12478c2ecf20Sopenharmony_ci				 *   ---> AutoSCSI with MSGOUTreg is processed.
12488c2ecf20Sopenharmony_ci				 */
12498c2ecf20Sopenharmony_ci				data->msgout_len = 0;
12508c2ecf20Sopenharmony_ci			}
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "MsgOut phase processed");
12538c2ecf20Sopenharmony_ci		}
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci		if ((auto_stat & DATA_IN_PHASE) &&
12568c2ecf20Sopenharmony_ci		    (scsi_get_resid(SCpnt) > 0) &&
12578c2ecf20Sopenharmony_ci		    ((nsp32_read2(base, FIFO_REST_CNT) & FIFO_REST_MASK) != 0)) {
12588c2ecf20Sopenharmony_ci			printk( "auto+fifo\n");
12598c2ecf20Sopenharmony_ci			//nsp32_pio_read(SCpnt);
12608c2ecf20Sopenharmony_ci		}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci		if (auto_stat & (DATA_IN_PHASE | DATA_OUT_PHASE)) {
12638c2ecf20Sopenharmony_ci			/* DATA_IN_PHASE/DATA_OUT_PHASE was processed. */
12648c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR,
12658c2ecf20Sopenharmony_ci				  "Data in/out phase processed");
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci			/* read BMCNT, SGT pointer addr */
12688c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "BMCNT=0x%lx",
12698c2ecf20Sopenharmony_ci				    nsp32_read4(base, BM_CNT));
12708c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "addr=0x%lx",
12718c2ecf20Sopenharmony_ci				    nsp32_read4(base, SGT_ADR));
12728c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "SACK=0x%lx",
12738c2ecf20Sopenharmony_ci				    nsp32_read4(base, SACK_CNT));
12748c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx",
12758c2ecf20Sopenharmony_ci				    nsp32_read4(base, SAVED_SACK_CNT));
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci			scsi_set_resid(SCpnt, 0); /* all data transferred! */
12788c2ecf20Sopenharmony_ci		}
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci		/*
12818c2ecf20Sopenharmony_ci		 * MsgIn Occur
12828c2ecf20Sopenharmony_ci		 */
12838c2ecf20Sopenharmony_ci		if (auto_stat & MSG_IN_OCCUER) {
12848c2ecf20Sopenharmony_ci			nsp32_msgin_occur(SCpnt, irq_stat, auto_stat);
12858c2ecf20Sopenharmony_ci		}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci		/*
12888c2ecf20Sopenharmony_ci		 * MsgOut Occur
12898c2ecf20Sopenharmony_ci		 */
12908c2ecf20Sopenharmony_ci		if (auto_stat & MSG_OUT_OCCUER) {
12918c2ecf20Sopenharmony_ci			nsp32_msgout_occur(SCpnt);
12928c2ecf20Sopenharmony_ci		}
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci		/*
12958c2ecf20Sopenharmony_ci		 * Bus Free Occur
12968c2ecf20Sopenharmony_ci		 */
12978c2ecf20Sopenharmony_ci		if (auto_stat & BUS_FREE_OCCUER) {
12988c2ecf20Sopenharmony_ci			ret = nsp32_busfree_occur(SCpnt, auto_stat);
12998c2ecf20Sopenharmony_ci			if (ret == TRUE) {
13008c2ecf20Sopenharmony_ci				goto out;
13018c2ecf20Sopenharmony_ci			}
13028c2ecf20Sopenharmony_ci		}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci		if (auto_stat & STATUS_PHASE) {
13058c2ecf20Sopenharmony_ci			/*
13068c2ecf20Sopenharmony_ci			 * Read CSB and substitute CSB for SCpnt->result
13078c2ecf20Sopenharmony_ci			 * to save status phase stutas byte.
13088c2ecf20Sopenharmony_ci			 * scsi error handler checks host_byte (DID_*:
13098c2ecf20Sopenharmony_ci			 * low level driver to indicate status), then checks
13108c2ecf20Sopenharmony_ci			 * status_byte (SCSI status byte).
13118c2ecf20Sopenharmony_ci			 */
13128c2ecf20Sopenharmony_ci			SCpnt->result =	(int)nsp32_read1(base, SCSI_CSB_IN);
13138c2ecf20Sopenharmony_ci		}
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci		if (auto_stat & ILLEGAL_PHASE) {
13168c2ecf20Sopenharmony_ci			/* Illegal phase is detected. SACK is not back. */
13178c2ecf20Sopenharmony_ci			nsp32_msg(KERN_WARNING,
13188c2ecf20Sopenharmony_ci				  "AUTO SCSI ILLEGAL PHASE OCCUR!!!!");
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci			/* TODO: currently we don't have any action... bus reset? */
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci			/*
13238c2ecf20Sopenharmony_ci			 * To send back SACK, assert, wait, and negate.
13248c2ecf20Sopenharmony_ci			 */
13258c2ecf20Sopenharmony_ci			nsp32_sack_assert(data);
13268c2ecf20Sopenharmony_ci			nsp32_wait_req(data, NEGATE);
13278c2ecf20Sopenharmony_ci			nsp32_sack_negate(data);
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci		}
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci		if (auto_stat & COMMAND_PHASE) {
13328c2ecf20Sopenharmony_ci			/* nothing to do */
13338c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "Command phase processed");
13348c2ecf20Sopenharmony_ci		}
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci		if (auto_stat & AUTOSCSI_BUSY) {
13378c2ecf20Sopenharmony_ci			/* AutoSCSI is running */
13388c2ecf20Sopenharmony_ci		}
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci		show_autophase(auto_stat);
13418c2ecf20Sopenharmony_ci	}
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	/* FIFO_SHLD_IRQ */
13448c2ecf20Sopenharmony_ci	if (irq_stat & IRQSTATUS_FIFO_SHLD_IRQ) {
13458c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INTR, "FIFO IRQ");
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci		switch(busphase) {
13488c2ecf20Sopenharmony_ci		case BUSPHASE_DATA_OUT:
13498c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/write");
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci			//nsp32_pio_write(SCpnt);
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci			break;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci		case BUSPHASE_DATA_IN:
13568c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/read");
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci			//nsp32_pio_read(SCpnt);
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci			break;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci		case BUSPHASE_STATUS:
13638c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/status");
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci			SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN);
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci			break;
13688c2ecf20Sopenharmony_ci		default:
13698c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/other phase");
13708c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat);
13718c2ecf20Sopenharmony_ci			show_busphase(busphase);
13728c2ecf20Sopenharmony_ci			break;
13738c2ecf20Sopenharmony_ci		}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci		goto out;
13768c2ecf20Sopenharmony_ci	}
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	/* Phase Change IRQ */
13798c2ecf20Sopenharmony_ci	if (irq_stat & IRQSTATUS_PHASE_CHANGE_IRQ) {
13808c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INTR, "phase change IRQ");
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci		switch(busphase) {
13838c2ecf20Sopenharmony_ci		case BUSPHASE_MESSAGE_IN:
13848c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_INTR, "phase chg/msg in");
13858c2ecf20Sopenharmony_ci			nsp32_msgin_occur(SCpnt, irq_stat, 0);
13868c2ecf20Sopenharmony_ci			break;
13878c2ecf20Sopenharmony_ci		default:
13888c2ecf20Sopenharmony_ci			nsp32_msg(KERN_WARNING, "phase chg/other phase?");
13898c2ecf20Sopenharmony_ci			nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x\n",
13908c2ecf20Sopenharmony_ci				  irq_stat, trans_stat);
13918c2ecf20Sopenharmony_ci			show_busphase(busphase);
13928c2ecf20Sopenharmony_ci			break;
13938c2ecf20Sopenharmony_ci		}
13948c2ecf20Sopenharmony_ci		goto out;
13958c2ecf20Sopenharmony_ci	}
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	/* PCI_IRQ */
13988c2ecf20Sopenharmony_ci	if (irq_stat & IRQSTATUS_PCI_IRQ) {
13998c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_INTR, "PCI IRQ occurred");
14008c2ecf20Sopenharmony_ci		/* Do nothing */
14018c2ecf20Sopenharmony_ci	}
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci	/* BMCNTERR_IRQ */
14048c2ecf20Sopenharmony_ci	if (irq_stat & IRQSTATUS_BMCNTERR_IRQ) {
14058c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "Received unexpected BMCNTERR IRQ! ");
14068c2ecf20Sopenharmony_ci		/*
14078c2ecf20Sopenharmony_ci		 * TODO: To be implemented improving bus master
14088c2ecf20Sopenharmony_ci		 * transfer reliability when BMCNTERR is occurred in
14098c2ecf20Sopenharmony_ci		 * AutoSCSI phase described in specification.
14108c2ecf20Sopenharmony_ci		 */
14118c2ecf20Sopenharmony_ci	}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci#if 0
14148c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_INTR,
14158c2ecf20Sopenharmony_ci		  "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat);
14168c2ecf20Sopenharmony_ci	show_busphase(busphase);
14178c2ecf20Sopenharmony_ci#endif
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci out:
14208c2ecf20Sopenharmony_ci	/* disable IRQ mask */
14218c2ecf20Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, 0);
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci out2:
14248c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(host->host_lock, flags);
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_INTR, "exit");
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	return IRQ_RETVAL(handled);
14298c2ecf20Sopenharmony_ci}
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_cistatic int nsp32_show_info(struct seq_file *m, struct Scsi_Host *host)
14338c2ecf20Sopenharmony_ci{
14348c2ecf20Sopenharmony_ci	unsigned long     flags;
14358c2ecf20Sopenharmony_ci	nsp32_hw_data    *data;
14368c2ecf20Sopenharmony_ci	int               hostno;
14378c2ecf20Sopenharmony_ci	unsigned int      base;
14388c2ecf20Sopenharmony_ci	unsigned char     mode_reg;
14398c2ecf20Sopenharmony_ci	int               id, speed;
14408c2ecf20Sopenharmony_ci	long              model;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	hostno = host->host_no;
14438c2ecf20Sopenharmony_ci	data = (nsp32_hw_data *)host->hostdata;
14448c2ecf20Sopenharmony_ci	base = host->io_port;
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	seq_puts(m, "NinjaSCSI-32 status\n\n");
14478c2ecf20Sopenharmony_ci	seq_printf(m, "Driver version:        %s, $Revision: 1.33 $\n", nsp32_release_version);
14488c2ecf20Sopenharmony_ci	seq_printf(m, "SCSI host No.:         %d\n",		hostno);
14498c2ecf20Sopenharmony_ci	seq_printf(m, "IRQ:                   %d\n",		host->irq);
14508c2ecf20Sopenharmony_ci	seq_printf(m, "IO:                    0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
14518c2ecf20Sopenharmony_ci	seq_printf(m, "MMIO(virtual address): 0x%lx-0x%lx\n",	host->base, host->base + data->MmioLength - 1);
14528c2ecf20Sopenharmony_ci	seq_printf(m, "sg_tablesize:          %d\n",		host->sg_tablesize);
14538c2ecf20Sopenharmony_ci	seq_printf(m, "Chip revision:         0x%x\n",		(nsp32_read2(base, INDEX_REG) >> 8) & 0xff);
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	mode_reg = nsp32_index_read1(base, CHIP_MODE);
14568c2ecf20Sopenharmony_ci	model    = data->pci_devid->driver_data;
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
14598c2ecf20Sopenharmony_ci	seq_printf(m, "Power Management:      %s\n",          (mode_reg & OPTF) ? "yes" : "no");
14608c2ecf20Sopenharmony_ci#endif
14618c2ecf20Sopenharmony_ci	seq_printf(m, "OEM:                   %ld, %s\n",     (mode_reg & (OEM0|OEM1)), nsp32_model[model]);
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	spin_lock_irqsave(&(data->Lock), flags);
14648c2ecf20Sopenharmony_ci	seq_printf(m, "CurrentSC:             0x%p\n\n",      data->CurrentSC);
14658c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&(data->Lock), flags);
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	seq_puts(m, "SDTR status\n");
14698c2ecf20Sopenharmony_ci	for (id = 0; id < ARRAY_SIZE(data->target); id++) {
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci		seq_printf(m, "id %d: ", id);
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci		if (id == host->this_id) {
14748c2ecf20Sopenharmony_ci			seq_puts(m, "----- NinjaSCSI-32 host adapter\n");
14758c2ecf20Sopenharmony_ci			continue;
14768c2ecf20Sopenharmony_ci		}
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci		if (data->target[id].sync_flag == SDTR_DONE) {
14798c2ecf20Sopenharmony_ci			if (data->target[id].period == 0            &&
14808c2ecf20Sopenharmony_ci			    data->target[id].offset == ASYNC_OFFSET ) {
14818c2ecf20Sopenharmony_ci				seq_puts(m, "async");
14828c2ecf20Sopenharmony_ci			} else {
14838c2ecf20Sopenharmony_ci				seq_puts(m, " sync");
14848c2ecf20Sopenharmony_ci			}
14858c2ecf20Sopenharmony_ci		} else {
14868c2ecf20Sopenharmony_ci			seq_puts(m, " none");
14878c2ecf20Sopenharmony_ci		}
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci		if (data->target[id].period != 0) {
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci			speed = 1000000 / (data->target[id].period * 4);
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci			seq_printf(m, " transfer %d.%dMB/s, offset %d",
14948c2ecf20Sopenharmony_ci				speed / 1000,
14958c2ecf20Sopenharmony_ci				speed % 1000,
14968c2ecf20Sopenharmony_ci				data->target[id].offset
14978c2ecf20Sopenharmony_ci				);
14988c2ecf20Sopenharmony_ci		}
14998c2ecf20Sopenharmony_ci		seq_putc(m, '\n');
15008c2ecf20Sopenharmony_ci	}
15018c2ecf20Sopenharmony_ci	return 0;
15028c2ecf20Sopenharmony_ci}
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci/*
15078c2ecf20Sopenharmony_ci * Reset parameters and call scsi_done for data->cur_lunt.
15088c2ecf20Sopenharmony_ci * Be careful setting SCpnt->result = DID_* before calling this function.
15098c2ecf20Sopenharmony_ci */
15108c2ecf20Sopenharmony_cistatic void nsp32_scsi_done(struct scsi_cmnd *SCpnt)
15118c2ecf20Sopenharmony_ci{
15128c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
15138c2ecf20Sopenharmony_ci	unsigned int   base = SCpnt->device->host->io_port;
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	scsi_dma_unmap(SCpnt);
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	/*
15188c2ecf20Sopenharmony_ci	 * clear TRANSFERCONTROL_BM_START
15198c2ecf20Sopenharmony_ci	 */
15208c2ecf20Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL, 0);
15218c2ecf20Sopenharmony_ci	nsp32_write4(base, BM_CNT,           0);
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	/*
15248c2ecf20Sopenharmony_ci	 * call scsi_done
15258c2ecf20Sopenharmony_ci	 */
15268c2ecf20Sopenharmony_ci	(*SCpnt->scsi_done)(SCpnt);
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	/*
15298c2ecf20Sopenharmony_ci	 * reset parameters
15308c2ecf20Sopenharmony_ci	 */
15318c2ecf20Sopenharmony_ci	data->cur_lunt->SCpnt = NULL;
15328c2ecf20Sopenharmony_ci	data->cur_lunt        = NULL;
15338c2ecf20Sopenharmony_ci	data->cur_target      = NULL;
15348c2ecf20Sopenharmony_ci	data->CurrentSC      = NULL;
15358c2ecf20Sopenharmony_ci}
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci/*
15398c2ecf20Sopenharmony_ci * Bus Free Occur
15408c2ecf20Sopenharmony_ci *
15418c2ecf20Sopenharmony_ci * Current Phase is BUSFREE. AutoSCSI is automatically execute BUSFREE phase
15428c2ecf20Sopenharmony_ci * with ACK reply when below condition is matched:
15438c2ecf20Sopenharmony_ci *	MsgIn 00: Command Complete.
15448c2ecf20Sopenharmony_ci *	MsgIn 02: Save Data Pointer.
15458c2ecf20Sopenharmony_ci *	MsgIn 04: Disconnect.
15468c2ecf20Sopenharmony_ci * In other case, unexpected BUSFREE is detected.
15478c2ecf20Sopenharmony_ci */
15488c2ecf20Sopenharmony_cistatic int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph)
15498c2ecf20Sopenharmony_ci{
15508c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
15518c2ecf20Sopenharmony_ci	unsigned int base   = SCpnt->device->host->io_port;
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_BUSFREE, "enter execph=0x%x", execph);
15548c2ecf20Sopenharmony_ci	show_autophase(execph);
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	nsp32_write4(base, BM_CNT,           0);
15578c2ecf20Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL, 0);
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	/*
15608c2ecf20Sopenharmony_ci	 * MsgIn 02: Save Data Pointer
15618c2ecf20Sopenharmony_ci	 *
15628c2ecf20Sopenharmony_ci	 * VALID:
15638c2ecf20Sopenharmony_ci	 *   Save Data Pointer is received. Adjust pointer.
15648c2ecf20Sopenharmony_ci	 *
15658c2ecf20Sopenharmony_ci	 * NO-VALID:
15668c2ecf20Sopenharmony_ci	 *   SCSI-3 says if Save Data Pointer is not received, then we restart
15678c2ecf20Sopenharmony_ci	 *   processing and we can't adjust any SCSI data pointer in next data
15688c2ecf20Sopenharmony_ci	 *   phase.
15698c2ecf20Sopenharmony_ci	 */
15708c2ecf20Sopenharmony_ci	if (execph & MSGIN_02_VALID) {
15718c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_BUSFREE, "MsgIn02_Valid");
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci		/*
15748c2ecf20Sopenharmony_ci		 * Check sack_cnt/saved_sack_cnt, then adjust sg table if
15758c2ecf20Sopenharmony_ci		 * needed.
15768c2ecf20Sopenharmony_ci		 */
15778c2ecf20Sopenharmony_ci		if (!(execph & MSGIN_00_VALID) &&
15788c2ecf20Sopenharmony_ci		    ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE))) {
15798c2ecf20Sopenharmony_ci			unsigned int sacklen, s_sacklen;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci			/*
15828c2ecf20Sopenharmony_ci			 * Read SACK count and SAVEDSACK count, then compare.
15838c2ecf20Sopenharmony_ci			 */
15848c2ecf20Sopenharmony_ci			sacklen   = nsp32_read4(base, SACK_CNT      );
15858c2ecf20Sopenharmony_ci			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci			/*
15888c2ecf20Sopenharmony_ci			 * If SAVEDSACKCNT == 0, it means SavedDataPointer is
15898c2ecf20Sopenharmony_ci			 * come after data transferring.
15908c2ecf20Sopenharmony_ci			 */
15918c2ecf20Sopenharmony_ci			if (s_sacklen > 0) {
15928c2ecf20Sopenharmony_ci				/*
15938c2ecf20Sopenharmony_ci				 * Comparing between sack and savedsack to
15948c2ecf20Sopenharmony_ci				 * check the condition of AutoMsgIn03.
15958c2ecf20Sopenharmony_ci				 *
15968c2ecf20Sopenharmony_ci				 * If they are same, set msgin03 == TRUE,
15978c2ecf20Sopenharmony_ci				 * COMMANDCONTROL_AUTO_MSGIN_03 is enabled at
15988c2ecf20Sopenharmony_ci				 * reselection.  On the other hand, if they
15998c2ecf20Sopenharmony_ci				 * aren't same, set msgin03 == FALSE, and
16008c2ecf20Sopenharmony_ci				 * COMMANDCONTROL_AUTO_MSGIN_03 is disabled at
16018c2ecf20Sopenharmony_ci				 * reselection.
16028c2ecf20Sopenharmony_ci				 */
16038c2ecf20Sopenharmony_ci				if (sacklen != s_sacklen) {
16048c2ecf20Sopenharmony_ci					data->cur_lunt->msgin03 = FALSE;
16058c2ecf20Sopenharmony_ci				} else {
16068c2ecf20Sopenharmony_ci					data->cur_lunt->msgin03 = TRUE;
16078c2ecf20Sopenharmony_ci				}
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci				nsp32_adjust_busfree(SCpnt, s_sacklen);
16108c2ecf20Sopenharmony_ci			}
16118c2ecf20Sopenharmony_ci		}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci		/* This value has not substitude with valid value yet... */
16148c2ecf20Sopenharmony_ci		//data->cur_lunt->save_datp = data->cur_datp;
16158c2ecf20Sopenharmony_ci	} else {
16168c2ecf20Sopenharmony_ci		/*
16178c2ecf20Sopenharmony_ci		 * no processing.
16188c2ecf20Sopenharmony_ci		 */
16198c2ecf20Sopenharmony_ci	}
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	if (execph & MSGIN_03_VALID) {
16228c2ecf20Sopenharmony_ci		/* MsgIn03 was valid to be processed. No need processing. */
16238c2ecf20Sopenharmony_ci	}
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci	/*
16268c2ecf20Sopenharmony_ci	 * target SDTR check
16278c2ecf20Sopenharmony_ci	 */
16288c2ecf20Sopenharmony_ci	if (data->cur_target->sync_flag & SDTR_INITIATOR) {
16298c2ecf20Sopenharmony_ci		/*
16308c2ecf20Sopenharmony_ci		 * SDTR negotiation pulled by the initiator has not
16318c2ecf20Sopenharmony_ci		 * finished yet. Fall back to ASYNC mode.
16328c2ecf20Sopenharmony_ci		 */
16338c2ecf20Sopenharmony_ci		nsp32_set_async(data, data->cur_target);
16348c2ecf20Sopenharmony_ci		data->cur_target->sync_flag &= ~SDTR_INITIATOR;
16358c2ecf20Sopenharmony_ci		data->cur_target->sync_flag |= SDTR_DONE;
16368c2ecf20Sopenharmony_ci	} else if (data->cur_target->sync_flag & SDTR_TARGET) {
16378c2ecf20Sopenharmony_ci		/*
16388c2ecf20Sopenharmony_ci		 * SDTR negotiation pulled by the target has been
16398c2ecf20Sopenharmony_ci		 * negotiating.
16408c2ecf20Sopenharmony_ci		 */
16418c2ecf20Sopenharmony_ci		if (execph & (MSGIN_00_VALID | MSGIN_04_VALID)) {
16428c2ecf20Sopenharmony_ci			/*
16438c2ecf20Sopenharmony_ci			 * If valid message is received, then
16448c2ecf20Sopenharmony_ci			 * negotiation is succeeded.
16458c2ecf20Sopenharmony_ci			 */
16468c2ecf20Sopenharmony_ci		} else {
16478c2ecf20Sopenharmony_ci			/*
16488c2ecf20Sopenharmony_ci			 * On the contrary, if unexpected bus free is
16498c2ecf20Sopenharmony_ci			 * occurred, then negotiation is failed. Fall
16508c2ecf20Sopenharmony_ci			 * back to ASYNC mode.
16518c2ecf20Sopenharmony_ci			 */
16528c2ecf20Sopenharmony_ci			nsp32_set_async(data, data->cur_target);
16538c2ecf20Sopenharmony_ci		}
16548c2ecf20Sopenharmony_ci		data->cur_target->sync_flag &= ~SDTR_TARGET;
16558c2ecf20Sopenharmony_ci		data->cur_target->sync_flag |= SDTR_DONE;
16568c2ecf20Sopenharmony_ci	}
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	/*
16598c2ecf20Sopenharmony_ci	 * It is always ensured by SCSI standard that initiator
16608c2ecf20Sopenharmony_ci	 * switches into Bus Free Phase after
16618c2ecf20Sopenharmony_ci	 * receiving message 00 (Command Complete), 04 (Disconnect).
16628c2ecf20Sopenharmony_ci	 * It's the reason that processing here is valid.
16638c2ecf20Sopenharmony_ci	 */
16648c2ecf20Sopenharmony_ci	if (execph & MSGIN_00_VALID) {
16658c2ecf20Sopenharmony_ci		/* MsgIn 00: Command Complete */
16668c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_BUSFREE, "command complete");
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci		SCpnt->SCp.Status  = nsp32_read1(base, SCSI_CSB_IN);
16698c2ecf20Sopenharmony_ci		SCpnt->SCp.Message = 0;
16708c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_BUSFREE,
16718c2ecf20Sopenharmony_ci			  "normal end stat=0x%x resid=0x%x\n",
16728c2ecf20Sopenharmony_ci			  SCpnt->SCp.Status, scsi_get_resid(SCpnt));
16738c2ecf20Sopenharmony_ci		SCpnt->result = (DID_OK             << 16) |
16748c2ecf20Sopenharmony_ci			        (SCpnt->SCp.Message <<  8) |
16758c2ecf20Sopenharmony_ci			        (SCpnt->SCp.Status  <<  0);
16768c2ecf20Sopenharmony_ci		nsp32_scsi_done(SCpnt);
16778c2ecf20Sopenharmony_ci		/* All operation is done */
16788c2ecf20Sopenharmony_ci		return TRUE;
16798c2ecf20Sopenharmony_ci	} else if (execph & MSGIN_04_VALID) {
16808c2ecf20Sopenharmony_ci		/* MsgIn 04: Disconnect */
16818c2ecf20Sopenharmony_ci		SCpnt->SCp.Status  = nsp32_read1(base, SCSI_CSB_IN);
16828c2ecf20Sopenharmony_ci		SCpnt->SCp.Message = 4;
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_BUSFREE, "disconnect");
16858c2ecf20Sopenharmony_ci		return TRUE;
16868c2ecf20Sopenharmony_ci	} else {
16878c2ecf20Sopenharmony_ci		/* Unexpected bus free */
16888c2ecf20Sopenharmony_ci		nsp32_msg(KERN_WARNING, "unexpected bus free occurred");
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci		/* DID_ERROR? */
16918c2ecf20Sopenharmony_ci		//SCpnt->result   = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0);
16928c2ecf20Sopenharmony_ci		SCpnt->result = DID_ERROR << 16;
16938c2ecf20Sopenharmony_ci		nsp32_scsi_done(SCpnt);
16948c2ecf20Sopenharmony_ci		return TRUE;
16958c2ecf20Sopenharmony_ci	}
16968c2ecf20Sopenharmony_ci	return FALSE;
16978c2ecf20Sopenharmony_ci}
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci/*
17018c2ecf20Sopenharmony_ci * nsp32_adjust_busfree - adjusting SG table
17028c2ecf20Sopenharmony_ci *
17038c2ecf20Sopenharmony_ci * Note: This driver adjust the SG table using SCSI ACK
17048c2ecf20Sopenharmony_ci *       counter instead of BMCNT counter!
17058c2ecf20Sopenharmony_ci */
17068c2ecf20Sopenharmony_cistatic void nsp32_adjust_busfree(struct scsi_cmnd *SCpnt, unsigned int s_sacklen)
17078c2ecf20Sopenharmony_ci{
17088c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
17098c2ecf20Sopenharmony_ci	int                   old_entry = data->cur_entry;
17108c2ecf20Sopenharmony_ci	int                   new_entry;
17118c2ecf20Sopenharmony_ci	int                   sg_num = data->cur_lunt->sg_num;
17128c2ecf20Sopenharmony_ci	nsp32_sgtable *sgt    = data->cur_lunt->sglun->sgt;
17138c2ecf20Sopenharmony_ci	unsigned int          restlen, sentlen;
17148c2ecf20Sopenharmony_ci	u32_le                len, addr;
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_SGLIST, "old resid=0x%x", scsi_get_resid(SCpnt));
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	/* adjust saved SACK count with 4 byte start address boundary */
17198c2ecf20Sopenharmony_ci	s_sacklen -= le32_to_cpu(sgt[old_entry].addr) & 3;
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	/*
17228c2ecf20Sopenharmony_ci	 * calculate new_entry from sack count and each sgt[].len
17238c2ecf20Sopenharmony_ci	 * calculate the byte which is intent to send
17248c2ecf20Sopenharmony_ci	 */
17258c2ecf20Sopenharmony_ci	sentlen = 0;
17268c2ecf20Sopenharmony_ci	for (new_entry = old_entry; new_entry < sg_num; new_entry++) {
17278c2ecf20Sopenharmony_ci		sentlen += (le32_to_cpu(sgt[new_entry].len) & ~SGTEND);
17288c2ecf20Sopenharmony_ci		if (sentlen > s_sacklen) {
17298c2ecf20Sopenharmony_ci			break;
17308c2ecf20Sopenharmony_ci		}
17318c2ecf20Sopenharmony_ci	}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	/* all sgt is processed */
17348c2ecf20Sopenharmony_ci	if (new_entry == sg_num) {
17358c2ecf20Sopenharmony_ci		goto last;
17368c2ecf20Sopenharmony_ci	}
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	if (sentlen == s_sacklen) {
17398c2ecf20Sopenharmony_ci		/* XXX: confirm it's ok or not */
17408c2ecf20Sopenharmony_ci		/* In this case, it's ok because we are at
17418c2ecf20Sopenharmony_ci		   the head element of the sg. restlen is correctly calculated. */
17428c2ecf20Sopenharmony_ci	}
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	/* calculate the rest length for transferring */
17458c2ecf20Sopenharmony_ci	restlen = sentlen - s_sacklen;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	/* update adjusting current SG table entry */
17488c2ecf20Sopenharmony_ci	len  = le32_to_cpu(sgt[new_entry].len);
17498c2ecf20Sopenharmony_ci	addr = le32_to_cpu(sgt[new_entry].addr);
17508c2ecf20Sopenharmony_ci	addr += (len - restlen);
17518c2ecf20Sopenharmony_ci	sgt[new_entry].addr = cpu_to_le32(addr);
17528c2ecf20Sopenharmony_ci	sgt[new_entry].len  = cpu_to_le32(restlen);
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci	/* set cur_entry with new_entry */
17558c2ecf20Sopenharmony_ci	data->cur_entry = new_entry;
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	return;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci last:
17608c2ecf20Sopenharmony_ci	if (scsi_get_resid(SCpnt) < sentlen) {
17618c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "resid underflow");
17628c2ecf20Sopenharmony_ci	}
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) - sentlen);
17658c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_SGLIST, "new resid=0x%x", scsi_get_resid(SCpnt));
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	/* update hostdata and lun */
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci	return;
17708c2ecf20Sopenharmony_ci}
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci/*
17748c2ecf20Sopenharmony_ci * It's called MsgOut phase occur.
17758c2ecf20Sopenharmony_ci * NinjaSCSI-32Bi/UDE automatically processes up to 3 messages in
17768c2ecf20Sopenharmony_ci * message out phase. It, however, has more than 3 messages,
17778c2ecf20Sopenharmony_ci * HBA creates the interrupt and we have to process by hand.
17788c2ecf20Sopenharmony_ci */
17798c2ecf20Sopenharmony_cistatic void nsp32_msgout_occur(struct scsi_cmnd *SCpnt)
17808c2ecf20Sopenharmony_ci{
17818c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
17828c2ecf20Sopenharmony_ci	unsigned int base   = SCpnt->device->host->io_port;
17838c2ecf20Sopenharmony_ci	//unsigned short command;
17848c2ecf20Sopenharmony_ci	long new_sgtp;
17858c2ecf20Sopenharmony_ci	int i;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,
17888c2ecf20Sopenharmony_ci		  "enter: msgout_len: 0x%x", data->msgout_len);
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	/*
17918c2ecf20Sopenharmony_ci	 * If MsgOut phase is occurred without having any
17928c2ecf20Sopenharmony_ci	 * message, then No_Operation is sent (SCSI-2).
17938c2ecf20Sopenharmony_ci	 */
17948c2ecf20Sopenharmony_ci	if (data->msgout_len == 0) {
17958c2ecf20Sopenharmony_ci		nsp32_build_nop(SCpnt);
17968c2ecf20Sopenharmony_ci	}
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci	/*
17998c2ecf20Sopenharmony_ci	 * Set SGTP ADDR current entry for restarting AUTOSCSI,
18008c2ecf20Sopenharmony_ci	 * because SGTP is incremented next point.
18018c2ecf20Sopenharmony_ci	 * There is few statement in the specification...
18028c2ecf20Sopenharmony_ci	 */
18038c2ecf20Sopenharmony_ci 	new_sgtp = data->cur_lunt->sglun_paddr +
18048c2ecf20Sopenharmony_ci		   (data->cur_lunt->cur_entry * sizeof(nsp32_sgtable));
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	/*
18078c2ecf20Sopenharmony_ci	 * send messages
18088c2ecf20Sopenharmony_ci	 */
18098c2ecf20Sopenharmony_ci	for (i = 0; i < data->msgout_len; i++) {
18108c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,
18118c2ecf20Sopenharmony_ci			  "%d : 0x%x", i, data->msgoutbuf[i]);
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci		/*
18148c2ecf20Sopenharmony_ci		 * Check REQ is asserted.
18158c2ecf20Sopenharmony_ci		 */
18168c2ecf20Sopenharmony_ci		nsp32_wait_req(data, ASSERT);
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci		if (i == (data->msgout_len - 1)) {
18198c2ecf20Sopenharmony_ci			/*
18208c2ecf20Sopenharmony_ci			 * If the last message, set the AutoSCSI restart
18218c2ecf20Sopenharmony_ci			 * before send back the ack message. AutoSCSI
18228c2ecf20Sopenharmony_ci			 * restart automatically negate ATN signal.
18238c2ecf20Sopenharmony_ci			 */
18248c2ecf20Sopenharmony_ci			//command = (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);
18258c2ecf20Sopenharmony_ci			//nsp32_restart_autoscsi(SCpnt, command);
18268c2ecf20Sopenharmony_ci			nsp32_write2(base, COMMAND_CONTROL,
18278c2ecf20Sopenharmony_ci					 (CLEAR_CDB_FIFO_POINTER |
18288c2ecf20Sopenharmony_ci					  AUTO_COMMAND_PHASE     |
18298c2ecf20Sopenharmony_ci					  AUTOSCSI_RESTART       |
18308c2ecf20Sopenharmony_ci					  AUTO_MSGIN_00_OR_04    |
18318c2ecf20Sopenharmony_ci					  AUTO_MSGIN_02          ));
18328c2ecf20Sopenharmony_ci		}
18338c2ecf20Sopenharmony_ci		/*
18348c2ecf20Sopenharmony_ci		 * Write data with SACK, then wait sack is
18358c2ecf20Sopenharmony_ci		 * automatically negated.
18368c2ecf20Sopenharmony_ci		 */
18378c2ecf20Sopenharmony_ci		nsp32_write1(base, SCSI_DATA_WITH_ACK, data->msgoutbuf[i]);
18388c2ecf20Sopenharmony_ci		nsp32_wait_sack(data, NEGATE);
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "bus: 0x%x\n",
18418c2ecf20Sopenharmony_ci			  nsp32_read1(base, SCSI_BUS_MONITOR));
18428c2ecf20Sopenharmony_ci	}
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci	data->msgout_len = 0;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "exit");
18478c2ecf20Sopenharmony_ci}
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci/*
18508c2ecf20Sopenharmony_ci * Restart AutoSCSI
18518c2ecf20Sopenharmony_ci *
18528c2ecf20Sopenharmony_ci * Note: Restarting AutoSCSI needs set:
18538c2ecf20Sopenharmony_ci *		SYNC_REG, ACK_WIDTH, SGT_ADR, TRANSFER_CONTROL
18548c2ecf20Sopenharmony_ci */
18558c2ecf20Sopenharmony_cistatic void nsp32_restart_autoscsi(struct scsi_cmnd *SCpnt, unsigned short command)
18568c2ecf20Sopenharmony_ci{
18578c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
18588c2ecf20Sopenharmony_ci	unsigned int   base = data->BaseAddress;
18598c2ecf20Sopenharmony_ci	unsigned short transfer = 0;
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_RESTART, "enter");
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci	if (data->cur_target == NULL || data->cur_lunt == NULL) {
18648c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "Target or Lun is invalid");
18658c2ecf20Sopenharmony_ci	}
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci	/*
18688c2ecf20Sopenharmony_ci	 * set SYNC_REG
18698c2ecf20Sopenharmony_ci	 * Don't set BM_START_ADR before setting this register.
18708c2ecf20Sopenharmony_ci	 */
18718c2ecf20Sopenharmony_ci	nsp32_write1(base, SYNC_REG, data->cur_target->syncreg);
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	/*
18748c2ecf20Sopenharmony_ci	 * set ACKWIDTH
18758c2ecf20Sopenharmony_ci	 */
18768c2ecf20Sopenharmony_ci	nsp32_write1(base, ACK_WIDTH, data->cur_target->ackwidth);
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci	/*
18798c2ecf20Sopenharmony_ci	 * set SREQ hazard killer sampling rate
18808c2ecf20Sopenharmony_ci	 */
18818c2ecf20Sopenharmony_ci	nsp32_write1(base, SREQ_SMPL_RATE, data->cur_target->sample_reg);
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci	/*
18848c2ecf20Sopenharmony_ci	 * set SGT ADDR (physical address)
18858c2ecf20Sopenharmony_ci	 */
18868c2ecf20Sopenharmony_ci	nsp32_write4(base, SGT_ADR, data->cur_lunt->sglun_paddr);
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	/*
18898c2ecf20Sopenharmony_ci	 * set TRANSFER CONTROL REG
18908c2ecf20Sopenharmony_ci	 */
18918c2ecf20Sopenharmony_ci	transfer = 0;
18928c2ecf20Sopenharmony_ci	transfer |= (TRANSFER_GO | ALL_COUNTER_CLR);
18938c2ecf20Sopenharmony_ci	if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
18948c2ecf20Sopenharmony_ci		if (scsi_bufflen(SCpnt) > 0) {
18958c2ecf20Sopenharmony_ci			transfer |= BM_START;
18968c2ecf20Sopenharmony_ci		}
18978c2ecf20Sopenharmony_ci	} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
18988c2ecf20Sopenharmony_ci		transfer |= CB_MMIO_MODE;
18998c2ecf20Sopenharmony_ci	} else if (data->trans_method & NSP32_TRANSFER_PIO) {
19008c2ecf20Sopenharmony_ci		transfer |= CB_IO_MODE;
19018c2ecf20Sopenharmony_ci	}
19028c2ecf20Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL, transfer);
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_ci	/*
19058c2ecf20Sopenharmony_ci	 * restart AutoSCSI
19068c2ecf20Sopenharmony_ci	 *
19078c2ecf20Sopenharmony_ci	 * TODO: COMMANDCONTROL_AUTO_COMMAND_PHASE is needed ?
19088c2ecf20Sopenharmony_ci	 */
19098c2ecf20Sopenharmony_ci	command |= (CLEAR_CDB_FIFO_POINTER |
19108c2ecf20Sopenharmony_ci		    AUTO_COMMAND_PHASE     |
19118c2ecf20Sopenharmony_ci		    AUTOSCSI_RESTART       );
19128c2ecf20Sopenharmony_ci	nsp32_write2(base, COMMAND_CONTROL, command);
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_RESTART, "exit");
19158c2ecf20Sopenharmony_ci}
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci/*
19198c2ecf20Sopenharmony_ci * cannot run automatically message in occur
19208c2ecf20Sopenharmony_ci */
19218c2ecf20Sopenharmony_cistatic void nsp32_msgin_occur(struct scsi_cmnd     *SCpnt,
19228c2ecf20Sopenharmony_ci			      unsigned long  irq_status,
19238c2ecf20Sopenharmony_ci			      unsigned short execph)
19248c2ecf20Sopenharmony_ci{
19258c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
19268c2ecf20Sopenharmony_ci	unsigned int   base = SCpnt->device->host->io_port;
19278c2ecf20Sopenharmony_ci	unsigned char  msg;
19288c2ecf20Sopenharmony_ci	unsigned char  msgtype;
19298c2ecf20Sopenharmony_ci	unsigned char  newlun;
19308c2ecf20Sopenharmony_ci	unsigned short command  = 0;
19318c2ecf20Sopenharmony_ci	int            msgclear = TRUE;
19328c2ecf20Sopenharmony_ci	long           new_sgtp;
19338c2ecf20Sopenharmony_ci	int            ret;
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	/*
19368c2ecf20Sopenharmony_ci	 * read first message
19378c2ecf20Sopenharmony_ci	 *    Use SCSIDATA_W_ACK instead of SCSIDATAIN, because the procedure
19388c2ecf20Sopenharmony_ci	 *    of Message-In have to be processed before sending back SCSI ACK.
19398c2ecf20Sopenharmony_ci	 */
19408c2ecf20Sopenharmony_ci	msg = nsp32_read1(base, SCSI_DATA_IN);
19418c2ecf20Sopenharmony_ci	data->msginbuf[(unsigned char)data->msgin_len] = msg;
19428c2ecf20Sopenharmony_ci	msgtype = data->msginbuf[0];
19438c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR,
19448c2ecf20Sopenharmony_ci		  "enter: msglen: 0x%x msgin: 0x%x msgtype: 0x%x",
19458c2ecf20Sopenharmony_ci		  data->msgin_len, msg, msgtype);
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci	/*
19488c2ecf20Sopenharmony_ci	 * TODO: We need checking whether bus phase is message in?
19498c2ecf20Sopenharmony_ci	 */
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci	/*
19528c2ecf20Sopenharmony_ci	 * assert SCSI ACK
19538c2ecf20Sopenharmony_ci	 */
19548c2ecf20Sopenharmony_ci	nsp32_sack_assert(data);
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci	/*
19578c2ecf20Sopenharmony_ci	 * processing IDENTIFY
19588c2ecf20Sopenharmony_ci	 */
19598c2ecf20Sopenharmony_ci	if (msgtype & 0x80) {
19608c2ecf20Sopenharmony_ci		if (!(irq_status & IRQSTATUS_RESELECT_OCCUER)) {
19618c2ecf20Sopenharmony_ci			/* Invalid (non reselect) phase */
19628c2ecf20Sopenharmony_ci			goto reject;
19638c2ecf20Sopenharmony_ci		}
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci		newlun = msgtype & 0x1f; /* TODO: SPI-3 compliant? */
19668c2ecf20Sopenharmony_ci		ret = nsp32_reselection(SCpnt, newlun);
19678c2ecf20Sopenharmony_ci		if (ret == TRUE) {
19688c2ecf20Sopenharmony_ci			goto restart;
19698c2ecf20Sopenharmony_ci		} else {
19708c2ecf20Sopenharmony_ci			goto reject;
19718c2ecf20Sopenharmony_ci		}
19728c2ecf20Sopenharmony_ci	}
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci	/*
19758c2ecf20Sopenharmony_ci	 * processing messages except for IDENTIFY
19768c2ecf20Sopenharmony_ci	 *
19778c2ecf20Sopenharmony_ci	 * TODO: Messages are all SCSI-2 terminology. SCSI-3 compliance is TODO.
19788c2ecf20Sopenharmony_ci	 */
19798c2ecf20Sopenharmony_ci	switch (msgtype) {
19808c2ecf20Sopenharmony_ci	/*
19818c2ecf20Sopenharmony_ci	 * 1-byte message
19828c2ecf20Sopenharmony_ci	 */
19838c2ecf20Sopenharmony_ci	case COMMAND_COMPLETE:
19848c2ecf20Sopenharmony_ci	case DISCONNECT:
19858c2ecf20Sopenharmony_ci		/*
19868c2ecf20Sopenharmony_ci		 * These messages should not be occurred.
19878c2ecf20Sopenharmony_ci		 * They should be processed on AutoSCSI sequencer.
19888c2ecf20Sopenharmony_ci		 */
19898c2ecf20Sopenharmony_ci		nsp32_msg(KERN_WARNING,
19908c2ecf20Sopenharmony_ci			   "unexpected message of AutoSCSI MsgIn: 0x%x", msg);
19918c2ecf20Sopenharmony_ci		break;
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_ci	case RESTORE_POINTERS:
19948c2ecf20Sopenharmony_ci		/*
19958c2ecf20Sopenharmony_ci		 * AutoMsgIn03 is disabled, and HBA gets this message.
19968c2ecf20Sopenharmony_ci		 */
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci		if ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE)) {
19998c2ecf20Sopenharmony_ci			unsigned int s_sacklen;
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_ci			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);
20028c2ecf20Sopenharmony_ci			if ((execph & MSGIN_02_VALID) && (s_sacklen > 0)) {
20038c2ecf20Sopenharmony_ci				nsp32_adjust_busfree(SCpnt, s_sacklen);
20048c2ecf20Sopenharmony_ci			} else {
20058c2ecf20Sopenharmony_ci				/* No need to rewrite SGT */
20068c2ecf20Sopenharmony_ci			}
20078c2ecf20Sopenharmony_ci		}
20088c2ecf20Sopenharmony_ci		data->cur_lunt->msgin03 = FALSE;
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci		/* Update with the new value */
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci		/* reset SACK/SavedACK counter (or ALL clear?) */
20138c2ecf20Sopenharmony_ci		nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ci		/*
20168c2ecf20Sopenharmony_ci		 * set new sg pointer
20178c2ecf20Sopenharmony_ci		 */
20188c2ecf20Sopenharmony_ci		new_sgtp = data->cur_lunt->sglun_paddr +
20198c2ecf20Sopenharmony_ci			(data->cur_lunt->cur_entry * sizeof(nsp32_sgtable));
20208c2ecf20Sopenharmony_ci		nsp32_write4(base, SGT_ADR, new_sgtp);
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci		break;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	case SAVE_POINTERS:
20258c2ecf20Sopenharmony_ci		/*
20268c2ecf20Sopenharmony_ci		 * These messages should not be occurred.
20278c2ecf20Sopenharmony_ci		 * They should be processed on AutoSCSI sequencer.
20288c2ecf20Sopenharmony_ci		 */
20298c2ecf20Sopenharmony_ci		nsp32_msg (KERN_WARNING,
20308c2ecf20Sopenharmony_ci			   "unexpected message of AutoSCSI MsgIn: SAVE_POINTERS");
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci		break;
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci	case MESSAGE_REJECT:
20358c2ecf20Sopenharmony_ci		/* If previous message_out is sending SDTR, and get
20368c2ecf20Sopenharmony_ci		   message_reject from target, SDTR negotiation is failed */
20378c2ecf20Sopenharmony_ci		if (data->cur_target->sync_flag &
20388c2ecf20Sopenharmony_ci				(SDTR_INITIATOR | SDTR_TARGET)) {
20398c2ecf20Sopenharmony_ci			/*
20408c2ecf20Sopenharmony_ci			 * Current target is negotiating SDTR, but it's
20418c2ecf20Sopenharmony_ci			 * failed.  Fall back to async transfer mode, and set
20428c2ecf20Sopenharmony_ci			 * SDTR_DONE.
20438c2ecf20Sopenharmony_ci			 */
20448c2ecf20Sopenharmony_ci			nsp32_set_async(data, data->cur_target);
20458c2ecf20Sopenharmony_ci			data->cur_target->sync_flag &= ~SDTR_INITIATOR;
20468c2ecf20Sopenharmony_ci			data->cur_target->sync_flag |= SDTR_DONE;
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci		}
20498c2ecf20Sopenharmony_ci		break;
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci	case LINKED_CMD_COMPLETE:
20528c2ecf20Sopenharmony_ci	case LINKED_FLG_CMD_COMPLETE:
20538c2ecf20Sopenharmony_ci		/* queue tag is not supported currently */
20548c2ecf20Sopenharmony_ci		nsp32_msg (KERN_WARNING,
20558c2ecf20Sopenharmony_ci			   "unsupported message: 0x%x", msgtype);
20568c2ecf20Sopenharmony_ci		break;
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci	case INITIATE_RECOVERY:
20598c2ecf20Sopenharmony_ci		/* staring ECA (Extended Contingent Allegiance) state. */
20608c2ecf20Sopenharmony_ci		/* This message is declined in SPI2 or later. */
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci		goto reject;
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	/*
20658c2ecf20Sopenharmony_ci	 * 2-byte message
20668c2ecf20Sopenharmony_ci	 */
20678c2ecf20Sopenharmony_ci	case SIMPLE_QUEUE_TAG:
20688c2ecf20Sopenharmony_ci	case 0x23:
20698c2ecf20Sopenharmony_ci		/*
20708c2ecf20Sopenharmony_ci		 * 0x23: Ignore_Wide_Residue is not declared in scsi.h.
20718c2ecf20Sopenharmony_ci		 * No support is needed.
20728c2ecf20Sopenharmony_ci		 */
20738c2ecf20Sopenharmony_ci		if (data->msgin_len >= 1) {
20748c2ecf20Sopenharmony_ci			goto reject;
20758c2ecf20Sopenharmony_ci		}
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci		/* current position is 1-byte of 2 byte */
20788c2ecf20Sopenharmony_ci		msgclear = FALSE;
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci		break;
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci	/*
20838c2ecf20Sopenharmony_ci	 * extended message
20848c2ecf20Sopenharmony_ci	 */
20858c2ecf20Sopenharmony_ci	case EXTENDED_MESSAGE:
20868c2ecf20Sopenharmony_ci		if (data->msgin_len < 1) {
20878c2ecf20Sopenharmony_ci			/*
20888c2ecf20Sopenharmony_ci			 * Current position does not reach 2-byte
20898c2ecf20Sopenharmony_ci			 * (2-byte is extended message length).
20908c2ecf20Sopenharmony_ci			 */
20918c2ecf20Sopenharmony_ci			msgclear = FALSE;
20928c2ecf20Sopenharmony_ci			break;
20938c2ecf20Sopenharmony_ci		}
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_ci		if ((data->msginbuf[1] + 1) > data->msgin_len) {
20968c2ecf20Sopenharmony_ci			/*
20978c2ecf20Sopenharmony_ci			 * Current extended message has msginbuf[1] + 2
20988c2ecf20Sopenharmony_ci			 * (msgin_len starts counting from 0, so buf[1] + 1).
20998c2ecf20Sopenharmony_ci			 * If current message position is not finished,
21008c2ecf20Sopenharmony_ci			 * continue receiving message.
21018c2ecf20Sopenharmony_ci			 */
21028c2ecf20Sopenharmony_ci			msgclear = FALSE;
21038c2ecf20Sopenharmony_ci			break;
21048c2ecf20Sopenharmony_ci		}
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci		/*
21078c2ecf20Sopenharmony_ci		 * Reach here means regular length of each type of
21088c2ecf20Sopenharmony_ci		 * extended messages.
21098c2ecf20Sopenharmony_ci		 */
21108c2ecf20Sopenharmony_ci		switch (data->msginbuf[2]) {
21118c2ecf20Sopenharmony_ci		case EXTENDED_MODIFY_DATA_POINTER:
21128c2ecf20Sopenharmony_ci			/* TODO */
21138c2ecf20Sopenharmony_ci			goto reject; /* not implemented yet */
21148c2ecf20Sopenharmony_ci			break;
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_ci		case EXTENDED_SDTR:
21178c2ecf20Sopenharmony_ci			/*
21188c2ecf20Sopenharmony_ci			 * Exchange this message between initiator and target.
21198c2ecf20Sopenharmony_ci			 */
21208c2ecf20Sopenharmony_ci			if (data->msgin_len != EXTENDED_SDTR_LEN + 1) {
21218c2ecf20Sopenharmony_ci				/*
21228c2ecf20Sopenharmony_ci				 * received inappropriate message.
21238c2ecf20Sopenharmony_ci				 */
21248c2ecf20Sopenharmony_ci				goto reject;
21258c2ecf20Sopenharmony_ci				break;
21268c2ecf20Sopenharmony_ci			}
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci			nsp32_analyze_sdtr(SCpnt);
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci			break;
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_ci		case EXTENDED_EXTENDED_IDENTIFY:
21338c2ecf20Sopenharmony_ci			/* SCSI-I only, not supported. */
21348c2ecf20Sopenharmony_ci			goto reject; /* not implemented yet */
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_ci			break;
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci		case EXTENDED_WDTR:
21398c2ecf20Sopenharmony_ci			goto reject; /* not implemented yet */
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci			break;
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_ci		default:
21448c2ecf20Sopenharmony_ci			goto reject;
21458c2ecf20Sopenharmony_ci		}
21468c2ecf20Sopenharmony_ci		break;
21478c2ecf20Sopenharmony_ci
21488c2ecf20Sopenharmony_ci	default:
21498c2ecf20Sopenharmony_ci		goto reject;
21508c2ecf20Sopenharmony_ci	}
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci restart:
21538c2ecf20Sopenharmony_ci	if (msgclear == TRUE) {
21548c2ecf20Sopenharmony_ci		data->msgin_len = 0;
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci		/*
21578c2ecf20Sopenharmony_ci		 * If restarting AutoSCSI, but there are some message to out
21588c2ecf20Sopenharmony_ci		 * (msgout_len > 0), set AutoATN, and set SCSIMSGOUT as 0
21598c2ecf20Sopenharmony_ci		 * (MV_VALID = 0). When commandcontrol is written with
21608c2ecf20Sopenharmony_ci		 * AutoSCSI restart, at the same time MsgOutOccur should be
21618c2ecf20Sopenharmony_ci		 * happened (however, such situation is really possible...?).
21628c2ecf20Sopenharmony_ci		 */
21638c2ecf20Sopenharmony_ci		if (data->msgout_len > 0) {
21648c2ecf20Sopenharmony_ci			nsp32_write4(base, SCSI_MSG_OUT, 0);
21658c2ecf20Sopenharmony_ci			command |= AUTO_ATN;
21668c2ecf20Sopenharmony_ci		}
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci		/*
21698c2ecf20Sopenharmony_ci		 * restart AutoSCSI
21708c2ecf20Sopenharmony_ci		 * If it's failed, COMMANDCONTROL_AUTO_COMMAND_PHASE is needed.
21718c2ecf20Sopenharmony_ci		 */
21728c2ecf20Sopenharmony_ci		command |= (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci		/*
21758c2ecf20Sopenharmony_ci		 * If current msgin03 is TRUE, then flag on.
21768c2ecf20Sopenharmony_ci		 */
21778c2ecf20Sopenharmony_ci		if (data->cur_lunt->msgin03 == TRUE) {
21788c2ecf20Sopenharmony_ci			command |= AUTO_MSGIN_03;
21798c2ecf20Sopenharmony_ci		}
21808c2ecf20Sopenharmony_ci		data->cur_lunt->msgin03 = FALSE;
21818c2ecf20Sopenharmony_ci	} else {
21828c2ecf20Sopenharmony_ci		data->msgin_len++;
21838c2ecf20Sopenharmony_ci	}
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_ci	/*
21868c2ecf20Sopenharmony_ci	 * restart AutoSCSI
21878c2ecf20Sopenharmony_ci	 */
21888c2ecf20Sopenharmony_ci	nsp32_restart_autoscsi(SCpnt, command);
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci	/*
21918c2ecf20Sopenharmony_ci	 * wait SCSI REQ negate for REQ-ACK handshake
21928c2ecf20Sopenharmony_ci	 */
21938c2ecf20Sopenharmony_ci	nsp32_wait_req(data, NEGATE);
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci	/*
21968c2ecf20Sopenharmony_ci	 * negate SCSI ACK
21978c2ecf20Sopenharmony_ci	 */
21988c2ecf20Sopenharmony_ci	nsp32_sack_negate(data);
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit");
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci	return;
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci reject:
22058c2ecf20Sopenharmony_ci	nsp32_msg(KERN_WARNING,
22068c2ecf20Sopenharmony_ci		  "invalid or unsupported MessageIn, rejected. "
22078c2ecf20Sopenharmony_ci		  "current msg: 0x%x (len: 0x%x), processing msg: 0x%x",
22088c2ecf20Sopenharmony_ci		  msg, data->msgin_len, msgtype);
22098c2ecf20Sopenharmony_ci	nsp32_build_reject(SCpnt);
22108c2ecf20Sopenharmony_ci	data->msgin_len = 0;
22118c2ecf20Sopenharmony_ci
22128c2ecf20Sopenharmony_ci	goto restart;
22138c2ecf20Sopenharmony_ci}
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci/*
22168c2ecf20Sopenharmony_ci *
22178c2ecf20Sopenharmony_ci */
22188c2ecf20Sopenharmony_cistatic void nsp32_analyze_sdtr(struct scsi_cmnd *SCpnt)
22198c2ecf20Sopenharmony_ci{
22208c2ecf20Sopenharmony_ci	nsp32_hw_data   *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
22218c2ecf20Sopenharmony_ci	nsp32_target     *target     = data->cur_target;
22228c2ecf20Sopenharmony_ci	nsp32_sync_table *synct;
22238c2ecf20Sopenharmony_ci	unsigned char     get_period = data->msginbuf[3];
22248c2ecf20Sopenharmony_ci	unsigned char     get_offset = data->msginbuf[4];
22258c2ecf20Sopenharmony_ci	int               entry;
22268c2ecf20Sopenharmony_ci	int               syncnum;
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "enter");
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci	synct   = data->synct;
22318c2ecf20Sopenharmony_ci	syncnum = data->syncnum;
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci	/*
22348c2ecf20Sopenharmony_ci	 * If this inititor sent the SDTR message, then target responds SDTR,
22358c2ecf20Sopenharmony_ci	 * initiator SYNCREG, ACKWIDTH from SDTR parameter.
22368c2ecf20Sopenharmony_ci	 * Messages are not appropriate, then send back reject message.
22378c2ecf20Sopenharmony_ci	 * If initiator did not send the SDTR, but target sends SDTR,
22388c2ecf20Sopenharmony_ci	 * initiator calculator the appropriate parameter and send back SDTR.
22398c2ecf20Sopenharmony_ci	 */
22408c2ecf20Sopenharmony_ci	if (target->sync_flag & SDTR_INITIATOR) {
22418c2ecf20Sopenharmony_ci		/*
22428c2ecf20Sopenharmony_ci		 * Initiator sent SDTR, the target responds and
22438c2ecf20Sopenharmony_ci		 * send back negotiation SDTR.
22448c2ecf20Sopenharmony_ci		 */
22458c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target responds SDTR");
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci		target->sync_flag &= ~SDTR_INITIATOR;
22488c2ecf20Sopenharmony_ci		target->sync_flag |= SDTR_DONE;
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci		/*
22518c2ecf20Sopenharmony_ci		 * offset:
22528c2ecf20Sopenharmony_ci		 */
22538c2ecf20Sopenharmony_ci		if (get_offset > SYNC_OFFSET) {
22548c2ecf20Sopenharmony_ci			/*
22558c2ecf20Sopenharmony_ci			 * Negotiation is failed, the target send back
22568c2ecf20Sopenharmony_ci			 * unexpected offset value.
22578c2ecf20Sopenharmony_ci			 */
22588c2ecf20Sopenharmony_ci			goto reject;
22598c2ecf20Sopenharmony_ci		}
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci		if (get_offset == ASYNC_OFFSET) {
22628c2ecf20Sopenharmony_ci			/*
22638c2ecf20Sopenharmony_ci			 * Negotiation is succeeded, the target want
22648c2ecf20Sopenharmony_ci			 * to fall back into asynchronous transfer mode.
22658c2ecf20Sopenharmony_ci			 */
22668c2ecf20Sopenharmony_ci			goto async;
22678c2ecf20Sopenharmony_ci		}
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci		/*
22708c2ecf20Sopenharmony_ci		 * period:
22718c2ecf20Sopenharmony_ci		 *    Check whether sync period is too short. If too short,
22728c2ecf20Sopenharmony_ci		 *    fall back to async mode. If it's ok, then investigate
22738c2ecf20Sopenharmony_ci		 *    the received sync period. If sync period is acceptable
22748c2ecf20Sopenharmony_ci		 *    between sync table start_period and end_period, then
22758c2ecf20Sopenharmony_ci		 *    set this I_T nexus as sent offset and period.
22768c2ecf20Sopenharmony_ci		 *    If it's not acceptable, send back reject and fall back
22778c2ecf20Sopenharmony_ci		 *    to async mode.
22788c2ecf20Sopenharmony_ci		 */
22798c2ecf20Sopenharmony_ci		if (get_period < data->synct[0].period_num) {
22808c2ecf20Sopenharmony_ci			/*
22818c2ecf20Sopenharmony_ci			 * Negotiation is failed, the target send back
22828c2ecf20Sopenharmony_ci			 * unexpected period value.
22838c2ecf20Sopenharmony_ci			 */
22848c2ecf20Sopenharmony_ci			goto reject;
22858c2ecf20Sopenharmony_ci		}
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci		entry = nsp32_search_period_entry(data, target, get_period);
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci		if (entry < 0) {
22908c2ecf20Sopenharmony_ci			/*
22918c2ecf20Sopenharmony_ci			 * Target want to use long period which is not
22928c2ecf20Sopenharmony_ci			 * acceptable NinjaSCSI-32Bi/UDE.
22938c2ecf20Sopenharmony_ci			 */
22948c2ecf20Sopenharmony_ci			goto reject;
22958c2ecf20Sopenharmony_ci		}
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci		/*
22988c2ecf20Sopenharmony_ci		 * Set new sync table and offset in this I_T nexus.
22998c2ecf20Sopenharmony_ci		 */
23008c2ecf20Sopenharmony_ci		nsp32_set_sync_entry(data, target, entry, get_offset);
23018c2ecf20Sopenharmony_ci	} else {
23028c2ecf20Sopenharmony_ci		/* Target send SDTR to initiator. */
23038c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target send SDTR");
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_ci		target->sync_flag |= SDTR_INITIATOR;
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_ci		/* offset: */
23088c2ecf20Sopenharmony_ci		if (get_offset > SYNC_OFFSET) {
23098c2ecf20Sopenharmony_ci			/* send back as SYNC_OFFSET */
23108c2ecf20Sopenharmony_ci			get_offset = SYNC_OFFSET;
23118c2ecf20Sopenharmony_ci		}
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci		/* period: */
23148c2ecf20Sopenharmony_ci		if (get_period < data->synct[0].period_num) {
23158c2ecf20Sopenharmony_ci			get_period = data->synct[0].period_num;
23168c2ecf20Sopenharmony_ci		}
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci		entry = nsp32_search_period_entry(data, target, get_period);
23198c2ecf20Sopenharmony_ci
23208c2ecf20Sopenharmony_ci		if (get_offset == ASYNC_OFFSET || entry < 0) {
23218c2ecf20Sopenharmony_ci			nsp32_set_async(data, target);
23228c2ecf20Sopenharmony_ci			nsp32_build_sdtr(SCpnt, 0, ASYNC_OFFSET);
23238c2ecf20Sopenharmony_ci		} else {
23248c2ecf20Sopenharmony_ci			nsp32_set_sync_entry(data, target, entry, get_offset);
23258c2ecf20Sopenharmony_ci			nsp32_build_sdtr(SCpnt, get_period, get_offset);
23268c2ecf20Sopenharmony_ci		}
23278c2ecf20Sopenharmony_ci	}
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_ci	target->period = get_period;
23308c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit");
23318c2ecf20Sopenharmony_ci	return;
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci reject:
23348c2ecf20Sopenharmony_ci	/*
23358c2ecf20Sopenharmony_ci	 * If the current message is unacceptable, send back to the target
23368c2ecf20Sopenharmony_ci	 * with reject message.
23378c2ecf20Sopenharmony_ci	 */
23388c2ecf20Sopenharmony_ci	nsp32_build_reject(SCpnt);
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci async:
23418c2ecf20Sopenharmony_ci	nsp32_set_async(data, target);	/* set as ASYNC transfer mode */
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_ci	target->period = 0;
23448c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit: set async");
23458c2ecf20Sopenharmony_ci	return;
23468c2ecf20Sopenharmony_ci}
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci/*
23508c2ecf20Sopenharmony_ci * Search config entry number matched in sync_table from given
23518c2ecf20Sopenharmony_ci * target and speed period value. If failed to search, return negative value.
23528c2ecf20Sopenharmony_ci */
23538c2ecf20Sopenharmony_cistatic int nsp32_search_period_entry(nsp32_hw_data *data,
23548c2ecf20Sopenharmony_ci				     nsp32_target  *target,
23558c2ecf20Sopenharmony_ci				     unsigned char  period)
23568c2ecf20Sopenharmony_ci{
23578c2ecf20Sopenharmony_ci	int i;
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_ci	if (target->limit_entry >= data->syncnum) {
23608c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "limit_entry exceeds syncnum!");
23618c2ecf20Sopenharmony_ci		target->limit_entry = 0;
23628c2ecf20Sopenharmony_ci	}
23638c2ecf20Sopenharmony_ci
23648c2ecf20Sopenharmony_ci	for (i = target->limit_entry; i < data->syncnum; i++) {
23658c2ecf20Sopenharmony_ci		if (period >= data->synct[i].start_period &&
23668c2ecf20Sopenharmony_ci		    period <= data->synct[i].end_period) {
23678c2ecf20Sopenharmony_ci				break;
23688c2ecf20Sopenharmony_ci		}
23698c2ecf20Sopenharmony_ci	}
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci	/*
23728c2ecf20Sopenharmony_ci	 * Check given period value is over the sync_table value.
23738c2ecf20Sopenharmony_ci	 * If so, return max value.
23748c2ecf20Sopenharmony_ci	 */
23758c2ecf20Sopenharmony_ci	if (i == data->syncnum) {
23768c2ecf20Sopenharmony_ci		i = -1;
23778c2ecf20Sopenharmony_ci	}
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci	return i;
23808c2ecf20Sopenharmony_ci}
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci/*
23848c2ecf20Sopenharmony_ci * target <-> initiator use ASYNC transfer
23858c2ecf20Sopenharmony_ci */
23868c2ecf20Sopenharmony_cistatic void nsp32_set_async(nsp32_hw_data *data, nsp32_target *target)
23878c2ecf20Sopenharmony_ci{
23888c2ecf20Sopenharmony_ci	unsigned char period = data->synct[target->limit_entry].period_num;
23898c2ecf20Sopenharmony_ci
23908c2ecf20Sopenharmony_ci	target->offset     = ASYNC_OFFSET;
23918c2ecf20Sopenharmony_ci	target->period     = 0;
23928c2ecf20Sopenharmony_ci	target->syncreg    = TO_SYNCREG(period, ASYNC_OFFSET);
23938c2ecf20Sopenharmony_ci	target->ackwidth   = 0;
23948c2ecf20Sopenharmony_ci	target->sample_reg = 0;
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_SYNC, "set async");
23978c2ecf20Sopenharmony_ci}
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_ci/*
24018c2ecf20Sopenharmony_ci * target <-> initiator use maximum SYNC transfer
24028c2ecf20Sopenharmony_ci */
24038c2ecf20Sopenharmony_cistatic void nsp32_set_max_sync(nsp32_hw_data *data,
24048c2ecf20Sopenharmony_ci			       nsp32_target  *target,
24058c2ecf20Sopenharmony_ci			       unsigned char *period,
24068c2ecf20Sopenharmony_ci			       unsigned char *offset)
24078c2ecf20Sopenharmony_ci{
24088c2ecf20Sopenharmony_ci	unsigned char period_num, ackwidth;
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci	period_num = data->synct[target->limit_entry].period_num;
24118c2ecf20Sopenharmony_ci	*period    = data->synct[target->limit_entry].start_period;
24128c2ecf20Sopenharmony_ci	ackwidth   = data->synct[target->limit_entry].ackwidth;
24138c2ecf20Sopenharmony_ci	*offset    = SYNC_OFFSET;
24148c2ecf20Sopenharmony_ci
24158c2ecf20Sopenharmony_ci	target->syncreg    = TO_SYNCREG(period_num, *offset);
24168c2ecf20Sopenharmony_ci	target->ackwidth   = ackwidth;
24178c2ecf20Sopenharmony_ci	target->offset     = *offset;
24188c2ecf20Sopenharmony_ci	target->sample_reg = 0;       /* disable SREQ sampling */
24198c2ecf20Sopenharmony_ci}
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci/*
24238c2ecf20Sopenharmony_ci * target <-> initiator use entry number speed
24248c2ecf20Sopenharmony_ci */
24258c2ecf20Sopenharmony_cistatic void nsp32_set_sync_entry(nsp32_hw_data *data,
24268c2ecf20Sopenharmony_ci				 nsp32_target  *target,
24278c2ecf20Sopenharmony_ci				 int            entry,
24288c2ecf20Sopenharmony_ci				 unsigned char  offset)
24298c2ecf20Sopenharmony_ci{
24308c2ecf20Sopenharmony_ci	unsigned char period, ackwidth, sample_rate;
24318c2ecf20Sopenharmony_ci
24328c2ecf20Sopenharmony_ci	period      = data->synct[entry].period_num;
24338c2ecf20Sopenharmony_ci	ackwidth    = data->synct[entry].ackwidth;
24348c2ecf20Sopenharmony_ci	sample_rate = data->synct[entry].sample_rate;
24358c2ecf20Sopenharmony_ci
24368c2ecf20Sopenharmony_ci	target->syncreg    = TO_SYNCREG(period, offset);
24378c2ecf20Sopenharmony_ci	target->ackwidth   = ackwidth;
24388c2ecf20Sopenharmony_ci	target->offset     = offset;
24398c2ecf20Sopenharmony_ci	target->sample_reg = sample_rate | SAMPLING_ENABLE;
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_SYNC, "set sync");
24428c2ecf20Sopenharmony_ci}
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci/*
24468c2ecf20Sopenharmony_ci * It waits until SCSI REQ becomes assertion or negation state.
24478c2ecf20Sopenharmony_ci *
24488c2ecf20Sopenharmony_ci * Note: If nsp32_msgin_occur is called, we asserts SCSI ACK. Then
24498c2ecf20Sopenharmony_ci *     connected target responds SCSI REQ negation.  We have to wait
24508c2ecf20Sopenharmony_ci *     SCSI REQ becomes negation in order to negate SCSI ACK signal for
24518c2ecf20Sopenharmony_ci *     REQ-ACK handshake.
24528c2ecf20Sopenharmony_ci */
24538c2ecf20Sopenharmony_cistatic void nsp32_wait_req(nsp32_hw_data *data, int state)
24548c2ecf20Sopenharmony_ci{
24558c2ecf20Sopenharmony_ci	unsigned int  base      = data->BaseAddress;
24568c2ecf20Sopenharmony_ci	int           wait_time = 0;
24578c2ecf20Sopenharmony_ci	unsigned char bus, req_bit;
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci	if (!((state == ASSERT) || (state == NEGATE))) {
24608c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "unknown state designation");
24618c2ecf20Sopenharmony_ci	}
24628c2ecf20Sopenharmony_ci	/* REQ is BIT(5) */
24638c2ecf20Sopenharmony_ci	req_bit = (state == ASSERT ? BUSMON_REQ : 0);
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci	do {
24668c2ecf20Sopenharmony_ci		bus = nsp32_read1(base, SCSI_BUS_MONITOR);
24678c2ecf20Sopenharmony_ci		if ((bus & BUSMON_REQ) == req_bit) {
24688c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_WAIT,
24698c2ecf20Sopenharmony_ci				  "wait_time: %d", wait_time);
24708c2ecf20Sopenharmony_ci			return;
24718c2ecf20Sopenharmony_ci		}
24728c2ecf20Sopenharmony_ci		udelay(1);
24738c2ecf20Sopenharmony_ci		wait_time++;
24748c2ecf20Sopenharmony_ci	} while (wait_time < REQSACK_TIMEOUT_TIME);
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_ci	nsp32_msg(KERN_WARNING, "wait REQ timeout, req_bit: 0x%x", req_bit);
24778c2ecf20Sopenharmony_ci}
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_ci/*
24808c2ecf20Sopenharmony_ci * It waits until SCSI SACK becomes assertion or negation state.
24818c2ecf20Sopenharmony_ci */
24828c2ecf20Sopenharmony_cistatic void nsp32_wait_sack(nsp32_hw_data *data, int state)
24838c2ecf20Sopenharmony_ci{
24848c2ecf20Sopenharmony_ci	unsigned int  base      = data->BaseAddress;
24858c2ecf20Sopenharmony_ci	int           wait_time = 0;
24868c2ecf20Sopenharmony_ci	unsigned char bus, ack_bit;
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci	if (!((state == ASSERT) || (state == NEGATE))) {
24898c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "unknown state designation");
24908c2ecf20Sopenharmony_ci	}
24918c2ecf20Sopenharmony_ci	/* ACK is BIT(4) */
24928c2ecf20Sopenharmony_ci	ack_bit = (state == ASSERT ? BUSMON_ACK : 0);
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	do {
24958c2ecf20Sopenharmony_ci		bus = nsp32_read1(base, SCSI_BUS_MONITOR);
24968c2ecf20Sopenharmony_ci		if ((bus & BUSMON_ACK) == ack_bit) {
24978c2ecf20Sopenharmony_ci			nsp32_dbg(NSP32_DEBUG_WAIT,
24988c2ecf20Sopenharmony_ci				  "wait_time: %d", wait_time);
24998c2ecf20Sopenharmony_ci			return;
25008c2ecf20Sopenharmony_ci		}
25018c2ecf20Sopenharmony_ci		udelay(1);
25028c2ecf20Sopenharmony_ci		wait_time++;
25038c2ecf20Sopenharmony_ci	} while (wait_time < REQSACK_TIMEOUT_TIME);
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci	nsp32_msg(KERN_WARNING, "wait SACK timeout, ack_bit: 0x%x", ack_bit);
25068c2ecf20Sopenharmony_ci}
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci/*
25098c2ecf20Sopenharmony_ci * assert SCSI ACK
25108c2ecf20Sopenharmony_ci *
25118c2ecf20Sopenharmony_ci * Note: SCSI ACK assertion needs with ACKENB=1, AUTODIRECTION=1.
25128c2ecf20Sopenharmony_ci */
25138c2ecf20Sopenharmony_cistatic void nsp32_sack_assert(nsp32_hw_data *data)
25148c2ecf20Sopenharmony_ci{
25158c2ecf20Sopenharmony_ci	unsigned int  base = data->BaseAddress;
25168c2ecf20Sopenharmony_ci	unsigned char busctrl;
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci	busctrl  = nsp32_read1(base, SCSI_BUS_CONTROL);
25198c2ecf20Sopenharmony_ci	busctrl	|= (BUSCTL_ACK | AUTODIRECTION | ACKENB);
25208c2ecf20Sopenharmony_ci	nsp32_write1(base, SCSI_BUS_CONTROL, busctrl);
25218c2ecf20Sopenharmony_ci}
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci/*
25248c2ecf20Sopenharmony_ci * negate SCSI ACK
25258c2ecf20Sopenharmony_ci */
25268c2ecf20Sopenharmony_cistatic void nsp32_sack_negate(nsp32_hw_data *data)
25278c2ecf20Sopenharmony_ci{
25288c2ecf20Sopenharmony_ci	unsigned int  base = data->BaseAddress;
25298c2ecf20Sopenharmony_ci	unsigned char busctrl;
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_ci	busctrl  = nsp32_read1(base, SCSI_BUS_CONTROL);
25328c2ecf20Sopenharmony_ci	busctrl	&= ~BUSCTL_ACK;
25338c2ecf20Sopenharmony_ci	nsp32_write1(base, SCSI_BUS_CONTROL, busctrl);
25348c2ecf20Sopenharmony_ci}
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_ci
25378c2ecf20Sopenharmony_ci
25388c2ecf20Sopenharmony_ci/*
25398c2ecf20Sopenharmony_ci * Note: n_io_port is defined as 0x7f because I/O register port is
25408c2ecf20Sopenharmony_ci *	 assigned as:
25418c2ecf20Sopenharmony_ci *	0x800-0x8ff: memory mapped I/O port
25428c2ecf20Sopenharmony_ci *	0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly)
25438c2ecf20Sopenharmony_ci *	0xc00-0xfff: CardBus status registers
25448c2ecf20Sopenharmony_ci */
25458c2ecf20Sopenharmony_cistatic int nsp32_detect(struct pci_dev *pdev)
25468c2ecf20Sopenharmony_ci{
25478c2ecf20Sopenharmony_ci	struct Scsi_Host *host;	/* registered host structure */
25488c2ecf20Sopenharmony_ci	struct resource  *res;
25498c2ecf20Sopenharmony_ci	nsp32_hw_data    *data;
25508c2ecf20Sopenharmony_ci	int               ret;
25518c2ecf20Sopenharmony_ci	int               i, j;
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci	/*
25568c2ecf20Sopenharmony_ci	 * register this HBA as SCSI device
25578c2ecf20Sopenharmony_ci	 */
25588c2ecf20Sopenharmony_ci	host = scsi_host_alloc(&nsp32_template, sizeof(nsp32_hw_data));
25598c2ecf20Sopenharmony_ci	if (host == NULL) {
25608c2ecf20Sopenharmony_ci		nsp32_msg (KERN_ERR, "failed to scsi register");
25618c2ecf20Sopenharmony_ci		goto err;
25628c2ecf20Sopenharmony_ci	}
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci	/*
25658c2ecf20Sopenharmony_ci	 * set nsp32_hw_data
25668c2ecf20Sopenharmony_ci	 */
25678c2ecf20Sopenharmony_ci	data = (nsp32_hw_data *)host->hostdata;
25688c2ecf20Sopenharmony_ci
25698c2ecf20Sopenharmony_ci	memcpy(data, &nsp32_data_base, sizeof(nsp32_hw_data));
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_ci	host->irq       = data->IrqNumber;
25728c2ecf20Sopenharmony_ci	host->io_port   = data->BaseAddress;
25738c2ecf20Sopenharmony_ci	host->unique_id = data->BaseAddress;
25748c2ecf20Sopenharmony_ci	host->n_io_port	= data->NumAddress;
25758c2ecf20Sopenharmony_ci	host->base      = (unsigned long)data->MmioAddress;
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_ci	data->Host      = host;
25788c2ecf20Sopenharmony_ci	spin_lock_init(&(data->Lock));
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	data->cur_lunt   = NULL;
25818c2ecf20Sopenharmony_ci	data->cur_target = NULL;
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci	/*
25848c2ecf20Sopenharmony_ci	 * Bus master transfer mode is supported currently.
25858c2ecf20Sopenharmony_ci	 */
25868c2ecf20Sopenharmony_ci	data->trans_method = NSP32_TRANSFER_BUSMASTER;
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci	/*
25898c2ecf20Sopenharmony_ci	 * Set clock div, CLOCK_4 (HBA has own external clock, and
25908c2ecf20Sopenharmony_ci	 * dividing * 100ns/4).
25918c2ecf20Sopenharmony_ci	 * Currently CLOCK_4 has only tested, not for CLOCK_2/PCICLK yet.
25928c2ecf20Sopenharmony_ci	 */
25938c2ecf20Sopenharmony_ci	data->clock = CLOCK_4;
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci	/*
25968c2ecf20Sopenharmony_ci	 * Select appropriate nsp32_sync_table and set I_CLOCKDIV.
25978c2ecf20Sopenharmony_ci	 */
25988c2ecf20Sopenharmony_ci	switch (data->clock) {
25998c2ecf20Sopenharmony_ci	case CLOCK_4:
26008c2ecf20Sopenharmony_ci		/* If data->clock is CLOCK_4, then select 40M sync table. */
26018c2ecf20Sopenharmony_ci		data->synct   = nsp32_sync_table_40M;
26028c2ecf20Sopenharmony_ci		data->syncnum = ARRAY_SIZE(nsp32_sync_table_40M);
26038c2ecf20Sopenharmony_ci		break;
26048c2ecf20Sopenharmony_ci	case CLOCK_2:
26058c2ecf20Sopenharmony_ci		/* If data->clock is CLOCK_2, then select 20M sync table. */
26068c2ecf20Sopenharmony_ci		data->synct   = nsp32_sync_table_20M;
26078c2ecf20Sopenharmony_ci		data->syncnum = ARRAY_SIZE(nsp32_sync_table_20M);
26088c2ecf20Sopenharmony_ci		break;
26098c2ecf20Sopenharmony_ci	case PCICLK:
26108c2ecf20Sopenharmony_ci		/* If data->clock is PCICLK, then select pci sync table. */
26118c2ecf20Sopenharmony_ci		data->synct   = nsp32_sync_table_pci;
26128c2ecf20Sopenharmony_ci		data->syncnum = ARRAY_SIZE(nsp32_sync_table_pci);
26138c2ecf20Sopenharmony_ci		break;
26148c2ecf20Sopenharmony_ci	default:
26158c2ecf20Sopenharmony_ci		nsp32_msg(KERN_WARNING,
26168c2ecf20Sopenharmony_ci			  "Invalid clock div is selected, set CLOCK_4.");
26178c2ecf20Sopenharmony_ci		/* Use default value CLOCK_4 */
26188c2ecf20Sopenharmony_ci		data->clock   = CLOCK_4;
26198c2ecf20Sopenharmony_ci		data->synct   = nsp32_sync_table_40M;
26208c2ecf20Sopenharmony_ci		data->syncnum = ARRAY_SIZE(nsp32_sync_table_40M);
26218c2ecf20Sopenharmony_ci	}
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_ci	/*
26248c2ecf20Sopenharmony_ci	 * setup nsp32_lunt
26258c2ecf20Sopenharmony_ci	 */
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	/*
26288c2ecf20Sopenharmony_ci	 * setup DMA
26298c2ecf20Sopenharmony_ci	 */
26308c2ecf20Sopenharmony_ci	if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
26318c2ecf20Sopenharmony_ci		nsp32_msg (KERN_ERR, "failed to set PCI DMA mask");
26328c2ecf20Sopenharmony_ci		goto scsi_unregister;
26338c2ecf20Sopenharmony_ci	}
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_ci	/*
26368c2ecf20Sopenharmony_ci	 * allocate autoparam DMA resource.
26378c2ecf20Sopenharmony_ci	 */
26388c2ecf20Sopenharmony_ci	data->autoparam = dma_alloc_coherent(&pdev->dev,
26398c2ecf20Sopenharmony_ci			sizeof(nsp32_autoparam), &(data->auto_paddr),
26408c2ecf20Sopenharmony_ci			GFP_KERNEL);
26418c2ecf20Sopenharmony_ci	if (data->autoparam == NULL) {
26428c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
26438c2ecf20Sopenharmony_ci		goto scsi_unregister;
26448c2ecf20Sopenharmony_ci	}
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_ci	/*
26478c2ecf20Sopenharmony_ci	 * allocate scatter-gather DMA resource.
26488c2ecf20Sopenharmony_ci	 */
26498c2ecf20Sopenharmony_ci	data->sg_list = dma_alloc_coherent(&pdev->dev, NSP32_SG_TABLE_SIZE,
26508c2ecf20Sopenharmony_ci			&data->sg_paddr, GFP_KERNEL);
26518c2ecf20Sopenharmony_ci	if (data->sg_list == NULL) {
26528c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
26538c2ecf20Sopenharmony_ci		goto free_autoparam;
26548c2ecf20Sopenharmony_ci	}
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->lunt); i++) {
26578c2ecf20Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(data->lunt[0]); j++) {
26588c2ecf20Sopenharmony_ci			int offset = i * ARRAY_SIZE(data->lunt[0]) + j;
26598c2ecf20Sopenharmony_ci			nsp32_lunt tmp = {
26608c2ecf20Sopenharmony_ci				.SCpnt       = NULL,
26618c2ecf20Sopenharmony_ci				.save_datp   = 0,
26628c2ecf20Sopenharmony_ci				.msgin03     = FALSE,
26638c2ecf20Sopenharmony_ci				.sg_num      = 0,
26648c2ecf20Sopenharmony_ci				.cur_entry   = 0,
26658c2ecf20Sopenharmony_ci				.sglun       = &(data->sg_list[offset]),
26668c2ecf20Sopenharmony_ci				.sglun_paddr = data->sg_paddr + (offset * sizeof(nsp32_sglun)),
26678c2ecf20Sopenharmony_ci			};
26688c2ecf20Sopenharmony_ci
26698c2ecf20Sopenharmony_ci			data->lunt[i][j] = tmp;
26708c2ecf20Sopenharmony_ci		}
26718c2ecf20Sopenharmony_ci	}
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci	/*
26748c2ecf20Sopenharmony_ci	 * setup target
26758c2ecf20Sopenharmony_ci	 */
26768c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->target); i++) {
26778c2ecf20Sopenharmony_ci		nsp32_target *target = &(data->target[i]);
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_ci		target->limit_entry  = 0;
26808c2ecf20Sopenharmony_ci		target->sync_flag    = 0;
26818c2ecf20Sopenharmony_ci		nsp32_set_async(data, target);
26828c2ecf20Sopenharmony_ci	}
26838c2ecf20Sopenharmony_ci
26848c2ecf20Sopenharmony_ci	/*
26858c2ecf20Sopenharmony_ci	 * EEPROM check
26868c2ecf20Sopenharmony_ci	 */
26878c2ecf20Sopenharmony_ci	ret = nsp32_getprom_param(data);
26888c2ecf20Sopenharmony_ci	if (ret == FALSE) {
26898c2ecf20Sopenharmony_ci		data->resettime = 3;	/* default 3 */
26908c2ecf20Sopenharmony_ci	}
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_ci	/*
26938c2ecf20Sopenharmony_ci	 * setup HBA
26948c2ecf20Sopenharmony_ci	 */
26958c2ecf20Sopenharmony_ci	nsp32hw_init(data);
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci	snprintf(data->info_str, sizeof(data->info_str),
26988c2ecf20Sopenharmony_ci		 "NinjaSCSI-32Bi/UDE: irq %d, io 0x%lx+0x%x",
26998c2ecf20Sopenharmony_ci		 host->irq, host->io_port, host->n_io_port);
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci	/*
27028c2ecf20Sopenharmony_ci	 * SCSI bus reset
27038c2ecf20Sopenharmony_ci	 *
27048c2ecf20Sopenharmony_ci	 * Note: It's important to reset SCSI bus in initialization phase.
27058c2ecf20Sopenharmony_ci	 *     NinjaSCSI-32Bi/UDE HBA EEPROM seems to exchange SDTR when
27068c2ecf20Sopenharmony_ci	 *     system is coming up, so SCSI devices connected to HBA is set as
27078c2ecf20Sopenharmony_ci	 *     un-asynchronous mode.  It brings the merit that this HBA is
27088c2ecf20Sopenharmony_ci	 *     ready to start synchronous transfer without any preparation,
27098c2ecf20Sopenharmony_ci	 *     but we are difficult to control transfer speed.  In addition,
27108c2ecf20Sopenharmony_ci	 *     it prevents device transfer speed from effecting EEPROM start-up
27118c2ecf20Sopenharmony_ci	 *     SDTR.  NinjaSCSI-32Bi/UDE has the feature if EEPROM is set as
27128c2ecf20Sopenharmony_ci	 *     Auto Mode, then FAST-10M is selected when SCSI devices are
27138c2ecf20Sopenharmony_ci	 *     connected same or more than 4 devices.  It should be avoided
27148c2ecf20Sopenharmony_ci	 *     depending on this specification. Thus, resetting the SCSI bus
27158c2ecf20Sopenharmony_ci	 *     restores all connected SCSI devices to asynchronous mode, then
27168c2ecf20Sopenharmony_ci	 *     this driver set SDTR safely later, and we can control all SCSI
27178c2ecf20Sopenharmony_ci	 *     device transfer mode.
27188c2ecf20Sopenharmony_ci	 */
27198c2ecf20Sopenharmony_ci	nsp32_do_bus_reset(data);
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci	ret = request_irq(host->irq, do_nsp32_isr, IRQF_SHARED, "nsp32", data);
27228c2ecf20Sopenharmony_ci	if (ret < 0) {
27238c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NinjaSCSI32 "
27248c2ecf20Sopenharmony_ci			  "SCSI PCI controller. Interrupt: %d", host->irq);
27258c2ecf20Sopenharmony_ci		goto free_sg_list;
27268c2ecf20Sopenharmony_ci	}
27278c2ecf20Sopenharmony_ci
27288c2ecf20Sopenharmony_ci        /*
27298c2ecf20Sopenharmony_ci         * PCI IO register
27308c2ecf20Sopenharmony_ci         */
27318c2ecf20Sopenharmony_ci	res = request_region(host->io_port, host->n_io_port, "nsp32");
27328c2ecf20Sopenharmony_ci	if (res == NULL) {
27338c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR,
27348c2ecf20Sopenharmony_ci			  "I/O region 0x%lx+0x%lx is already used",
27358c2ecf20Sopenharmony_ci			  data->BaseAddress, data->NumAddress);
27368c2ecf20Sopenharmony_ci		goto free_irq;
27378c2ecf20Sopenharmony_ci        }
27388c2ecf20Sopenharmony_ci
27398c2ecf20Sopenharmony_ci	ret = scsi_add_host(host, &pdev->dev);
27408c2ecf20Sopenharmony_ci	if (ret) {
27418c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "failed to add scsi host");
27428c2ecf20Sopenharmony_ci		goto free_region;
27438c2ecf20Sopenharmony_ci	}
27448c2ecf20Sopenharmony_ci	scsi_scan_host(host);
27458c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, host);
27468c2ecf20Sopenharmony_ci	return 0;
27478c2ecf20Sopenharmony_ci
27488c2ecf20Sopenharmony_ci free_region:
27498c2ecf20Sopenharmony_ci	release_region(host->io_port, host->n_io_port);
27508c2ecf20Sopenharmony_ci
27518c2ecf20Sopenharmony_ci free_irq:
27528c2ecf20Sopenharmony_ci	free_irq(host->irq, data);
27538c2ecf20Sopenharmony_ci
27548c2ecf20Sopenharmony_ci free_sg_list:
27558c2ecf20Sopenharmony_ci	dma_free_coherent(&pdev->dev, NSP32_SG_TABLE_SIZE,
27568c2ecf20Sopenharmony_ci			    data->sg_list, data->sg_paddr);
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci free_autoparam:
27598c2ecf20Sopenharmony_ci	dma_free_coherent(&pdev->dev, sizeof(nsp32_autoparam),
27608c2ecf20Sopenharmony_ci			    data->autoparam, data->auto_paddr);
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_ci scsi_unregister:
27638c2ecf20Sopenharmony_ci	scsi_host_put(host);
27648c2ecf20Sopenharmony_ci
27658c2ecf20Sopenharmony_ci err:
27668c2ecf20Sopenharmony_ci	return 1;
27678c2ecf20Sopenharmony_ci}
27688c2ecf20Sopenharmony_ci
27698c2ecf20Sopenharmony_cistatic int nsp32_release(struct Scsi_Host *host)
27708c2ecf20Sopenharmony_ci{
27718c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata;
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_ci	if (data->autoparam) {
27748c2ecf20Sopenharmony_ci		dma_free_coherent(&data->Pci->dev, sizeof(nsp32_autoparam),
27758c2ecf20Sopenharmony_ci				    data->autoparam, data->auto_paddr);
27768c2ecf20Sopenharmony_ci	}
27778c2ecf20Sopenharmony_ci
27788c2ecf20Sopenharmony_ci	if (data->sg_list) {
27798c2ecf20Sopenharmony_ci		dma_free_coherent(&data->Pci->dev, NSP32_SG_TABLE_SIZE,
27808c2ecf20Sopenharmony_ci				    data->sg_list, data->sg_paddr);
27818c2ecf20Sopenharmony_ci	}
27828c2ecf20Sopenharmony_ci
27838c2ecf20Sopenharmony_ci	if (host->irq) {
27848c2ecf20Sopenharmony_ci		free_irq(host->irq, data);
27858c2ecf20Sopenharmony_ci	}
27868c2ecf20Sopenharmony_ci
27878c2ecf20Sopenharmony_ci	if (host->io_port && host->n_io_port) {
27888c2ecf20Sopenharmony_ci		release_region(host->io_port, host->n_io_port);
27898c2ecf20Sopenharmony_ci	}
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	if (data->MmioAddress) {
27928c2ecf20Sopenharmony_ci		iounmap(data->MmioAddress);
27938c2ecf20Sopenharmony_ci	}
27948c2ecf20Sopenharmony_ci
27958c2ecf20Sopenharmony_ci	return 0;
27968c2ecf20Sopenharmony_ci}
27978c2ecf20Sopenharmony_ci
27988c2ecf20Sopenharmony_cistatic const char *nsp32_info(struct Scsi_Host *shpnt)
27998c2ecf20Sopenharmony_ci{
28008c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata;
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci	return data->info_str;
28038c2ecf20Sopenharmony_ci}
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_ci/****************************************************************************
28078c2ecf20Sopenharmony_ci * error handler
28088c2ecf20Sopenharmony_ci */
28098c2ecf20Sopenharmony_cistatic int nsp32_eh_abort(struct scsi_cmnd *SCpnt)
28108c2ecf20Sopenharmony_ci{
28118c2ecf20Sopenharmony_ci	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
28128c2ecf20Sopenharmony_ci	unsigned int   base = SCpnt->device->host->io_port;
28138c2ecf20Sopenharmony_ci
28148c2ecf20Sopenharmony_ci	nsp32_msg(KERN_WARNING, "abort");
28158c2ecf20Sopenharmony_ci
28168c2ecf20Sopenharmony_ci	if (data->cur_lunt->SCpnt == NULL) {
28178c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_BUSRESET, "abort failed");
28188c2ecf20Sopenharmony_ci		return FAILED;
28198c2ecf20Sopenharmony_ci	}
28208c2ecf20Sopenharmony_ci
28218c2ecf20Sopenharmony_ci	if (data->cur_target->sync_flag & (SDTR_INITIATOR | SDTR_TARGET)) {
28228c2ecf20Sopenharmony_ci		/* reset SDTR negotiation */
28238c2ecf20Sopenharmony_ci		data->cur_target->sync_flag = 0;
28248c2ecf20Sopenharmony_ci		nsp32_set_async(data, data->cur_target);
28258c2ecf20Sopenharmony_ci	}
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL, 0);
28288c2ecf20Sopenharmony_ci	nsp32_write2(base, BM_CNT,           0);
28298c2ecf20Sopenharmony_ci
28308c2ecf20Sopenharmony_ci	SCpnt->result = DID_ABORT << 16;
28318c2ecf20Sopenharmony_ci	nsp32_scsi_done(SCpnt);
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_BUSRESET, "abort success");
28348c2ecf20Sopenharmony_ci	return SUCCESS;
28358c2ecf20Sopenharmony_ci}
28368c2ecf20Sopenharmony_ci
28378c2ecf20Sopenharmony_cistatic void nsp32_do_bus_reset(nsp32_hw_data *data)
28388c2ecf20Sopenharmony_ci{
28398c2ecf20Sopenharmony_ci	unsigned int   base = data->BaseAddress;
28408c2ecf20Sopenharmony_ci	unsigned short intrdat;
28418c2ecf20Sopenharmony_ci	int i;
28428c2ecf20Sopenharmony_ci
28438c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_BUSRESET, "in");
28448c2ecf20Sopenharmony_ci
28458c2ecf20Sopenharmony_ci	/*
28468c2ecf20Sopenharmony_ci	 * stop all transfer
28478c2ecf20Sopenharmony_ci	 * clear TRANSFERCONTROL_BM_START
28488c2ecf20Sopenharmony_ci	 * clear counter
28498c2ecf20Sopenharmony_ci	 */
28508c2ecf20Sopenharmony_ci	nsp32_write2(base, TRANSFER_CONTROL, 0);
28518c2ecf20Sopenharmony_ci	nsp32_write4(base, BM_CNT,           0);
28528c2ecf20Sopenharmony_ci	nsp32_write4(base, CLR_COUNTER,      CLRCOUNTER_ALLMASK);
28538c2ecf20Sopenharmony_ci
28548c2ecf20Sopenharmony_ci	/*
28558c2ecf20Sopenharmony_ci	 * fall back to asynchronous transfer mode
28568c2ecf20Sopenharmony_ci	 * initialize SDTR negotiation flag
28578c2ecf20Sopenharmony_ci	 */
28588c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->target); i++) {
28598c2ecf20Sopenharmony_ci		nsp32_target *target = &data->target[i];
28608c2ecf20Sopenharmony_ci
28618c2ecf20Sopenharmony_ci		target->sync_flag = 0;
28628c2ecf20Sopenharmony_ci		nsp32_set_async(data, target);
28638c2ecf20Sopenharmony_ci	}
28648c2ecf20Sopenharmony_ci
28658c2ecf20Sopenharmony_ci	/*
28668c2ecf20Sopenharmony_ci	 * reset SCSI bus
28678c2ecf20Sopenharmony_ci	 */
28688c2ecf20Sopenharmony_ci	nsp32_write1(base, SCSI_BUS_CONTROL, BUSCTL_RST);
28698c2ecf20Sopenharmony_ci	mdelay(RESET_HOLD_TIME / 1000);
28708c2ecf20Sopenharmony_ci	nsp32_write1(base, SCSI_BUS_CONTROL, 0);
28718c2ecf20Sopenharmony_ci	for(i = 0; i < 5; i++) {
28728c2ecf20Sopenharmony_ci		intrdat = nsp32_read2(base, IRQ_STATUS); /* dummy read */
28738c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_BUSRESET, "irq:1: 0x%x", intrdat);
28748c2ecf20Sopenharmony_ci        }
28758c2ecf20Sopenharmony_ci
28768c2ecf20Sopenharmony_ci	data->CurrentSC = NULL;
28778c2ecf20Sopenharmony_ci}
28788c2ecf20Sopenharmony_ci
28798c2ecf20Sopenharmony_cistatic int nsp32_eh_host_reset(struct scsi_cmnd *SCpnt)
28808c2ecf20Sopenharmony_ci{
28818c2ecf20Sopenharmony_ci	struct Scsi_Host *host = SCpnt->device->host;
28828c2ecf20Sopenharmony_ci	unsigned int      base = SCpnt->device->host->io_port;
28838c2ecf20Sopenharmony_ci	nsp32_hw_data    *data = (nsp32_hw_data *)host->hostdata;
28848c2ecf20Sopenharmony_ci
28858c2ecf20Sopenharmony_ci	nsp32_msg(KERN_INFO, "Host Reset");
28868c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt);
28878c2ecf20Sopenharmony_ci
28888c2ecf20Sopenharmony_ci	spin_lock_irq(SCpnt->device->host->host_lock);
28898c2ecf20Sopenharmony_ci
28908c2ecf20Sopenharmony_ci	nsp32hw_init(data);
28918c2ecf20Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
28928c2ecf20Sopenharmony_ci	nsp32_do_bus_reset(data);
28938c2ecf20Sopenharmony_ci	nsp32_write2(base, IRQ_CONTROL, 0);
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci	spin_unlock_irq(SCpnt->device->host->host_lock);
28968c2ecf20Sopenharmony_ci	return SUCCESS;	/* Host reset is succeeded at any time. */
28978c2ecf20Sopenharmony_ci}
28988c2ecf20Sopenharmony_ci
28998c2ecf20Sopenharmony_ci
29008c2ecf20Sopenharmony_ci/**************************************************************************
29018c2ecf20Sopenharmony_ci * EEPROM handler
29028c2ecf20Sopenharmony_ci */
29038c2ecf20Sopenharmony_ci
29048c2ecf20Sopenharmony_ci/*
29058c2ecf20Sopenharmony_ci * getting EEPROM parameter
29068c2ecf20Sopenharmony_ci */
29078c2ecf20Sopenharmony_cistatic int nsp32_getprom_param(nsp32_hw_data *data)
29088c2ecf20Sopenharmony_ci{
29098c2ecf20Sopenharmony_ci	int vendor = data->pci_devid->vendor;
29108c2ecf20Sopenharmony_ci	int device = data->pci_devid->device;
29118c2ecf20Sopenharmony_ci	int ret, val, i;
29128c2ecf20Sopenharmony_ci
29138c2ecf20Sopenharmony_ci	/*
29148c2ecf20Sopenharmony_ci	 * EEPROM checking.
29158c2ecf20Sopenharmony_ci	 */
29168c2ecf20Sopenharmony_ci	ret = nsp32_prom_read(data, 0x7e);
29178c2ecf20Sopenharmony_ci	if (ret != 0x55) {
29188c2ecf20Sopenharmony_ci		nsp32_msg(KERN_INFO, "No EEPROM detected: 0x%x", ret);
29198c2ecf20Sopenharmony_ci		return FALSE;
29208c2ecf20Sopenharmony_ci	}
29218c2ecf20Sopenharmony_ci	ret = nsp32_prom_read(data, 0x7f);
29228c2ecf20Sopenharmony_ci	if (ret != 0xaa) {
29238c2ecf20Sopenharmony_ci		nsp32_msg(KERN_INFO, "Invalid number: 0x%x", ret);
29248c2ecf20Sopenharmony_ci		return FALSE;
29258c2ecf20Sopenharmony_ci	}
29268c2ecf20Sopenharmony_ci
29278c2ecf20Sopenharmony_ci	/*
29288c2ecf20Sopenharmony_ci	 * check EEPROM type
29298c2ecf20Sopenharmony_ci	 */
29308c2ecf20Sopenharmony_ci	if (vendor == PCI_VENDOR_ID_WORKBIT &&
29318c2ecf20Sopenharmony_ci	    device == PCI_DEVICE_ID_WORKBIT_STANDARD) {
29328c2ecf20Sopenharmony_ci		ret = nsp32_getprom_c16(data);
29338c2ecf20Sopenharmony_ci	} else if (vendor == PCI_VENDOR_ID_WORKBIT &&
29348c2ecf20Sopenharmony_ci		   device == PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC) {
29358c2ecf20Sopenharmony_ci		ret = nsp32_getprom_at24(data);
29368c2ecf20Sopenharmony_ci	} else if (vendor == PCI_VENDOR_ID_WORKBIT &&
29378c2ecf20Sopenharmony_ci		   device == PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO ) {
29388c2ecf20Sopenharmony_ci		ret = nsp32_getprom_at24(data);
29398c2ecf20Sopenharmony_ci	} else {
29408c2ecf20Sopenharmony_ci		nsp32_msg(KERN_WARNING, "Unknown EEPROM");
29418c2ecf20Sopenharmony_ci		ret = FALSE;
29428c2ecf20Sopenharmony_ci	}
29438c2ecf20Sopenharmony_ci
29448c2ecf20Sopenharmony_ci	/* for debug : SPROM data full checking */
29458c2ecf20Sopenharmony_ci	for (i = 0; i <= 0x1f; i++) {
29468c2ecf20Sopenharmony_ci		val = nsp32_prom_read(data, i);
29478c2ecf20Sopenharmony_ci		nsp32_dbg(NSP32_DEBUG_EEPROM,
29488c2ecf20Sopenharmony_ci			  "rom address 0x%x : 0x%x", i, val);
29498c2ecf20Sopenharmony_ci	}
29508c2ecf20Sopenharmony_ci
29518c2ecf20Sopenharmony_ci	return ret;
29528c2ecf20Sopenharmony_ci}
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci
29558c2ecf20Sopenharmony_ci/*
29568c2ecf20Sopenharmony_ci * AT24C01A (Logitec: LHA-600S), AT24C02 (Melco Buffalo: IFC-USLP) data map:
29578c2ecf20Sopenharmony_ci *
29588c2ecf20Sopenharmony_ci *   ROMADDR
29598c2ecf20Sopenharmony_ci *   0x00 - 0x06 :  Device Synchronous Transfer Period (SCSI ID 0 - 6)
29608c2ecf20Sopenharmony_ci *			Value 0x0: ASYNC, 0x0c: Ultra-20M, 0x19: Fast-10M
29618c2ecf20Sopenharmony_ci *   0x07        :  HBA Synchronous Transfer Period
29628c2ecf20Sopenharmony_ci *			Value 0: AutoSync, 1: Manual Setting
29638c2ecf20Sopenharmony_ci *   0x08 - 0x0f :  Not Used? (0x0)
29648c2ecf20Sopenharmony_ci *   0x10        :  Bus Termination
29658c2ecf20Sopenharmony_ci * 			Value 0: Auto[ON], 1: ON, 2: OFF
29668c2ecf20Sopenharmony_ci *   0x11        :  Not Used? (0)
29678c2ecf20Sopenharmony_ci *   0x12        :  Bus Reset Delay Time (0x03)
29688c2ecf20Sopenharmony_ci *   0x13        :  Bootable CD Support
29698c2ecf20Sopenharmony_ci *			Value 0: Disable, 1: Enable
29708c2ecf20Sopenharmony_ci *   0x14        :  Device Scan
29718c2ecf20Sopenharmony_ci *			Bit   7  6  5  4  3  2  1  0
29728c2ecf20Sopenharmony_ci *			      |  <----------------->
29738c2ecf20Sopenharmony_ci * 			      |    SCSI ID: Value 0: Skip, 1: YES
29748c2ecf20Sopenharmony_ci *			      |->  Value 0: ALL scan,  Value 1: Manual
29758c2ecf20Sopenharmony_ci *   0x15 - 0x1b :  Not Used? (0)
29768c2ecf20Sopenharmony_ci *   0x1c        :  Constant? (0x01) (clock div?)
29778c2ecf20Sopenharmony_ci *   0x1d - 0x7c :  Not Used (0xff)
29788c2ecf20Sopenharmony_ci *   0x7d	 :  Not Used? (0xff)
29798c2ecf20Sopenharmony_ci *   0x7e        :  Constant (0x55), Validity signature
29808c2ecf20Sopenharmony_ci *   0x7f        :  Constant (0xaa), Validity signature
29818c2ecf20Sopenharmony_ci */
29828c2ecf20Sopenharmony_cistatic int nsp32_getprom_at24(nsp32_hw_data *data)
29838c2ecf20Sopenharmony_ci{
29848c2ecf20Sopenharmony_ci	int           ret, i;
29858c2ecf20Sopenharmony_ci	int           auto_sync;
29868c2ecf20Sopenharmony_ci	nsp32_target *target;
29878c2ecf20Sopenharmony_ci	int           entry;
29888c2ecf20Sopenharmony_ci
29898c2ecf20Sopenharmony_ci	/*
29908c2ecf20Sopenharmony_ci	 * Reset time which is designated by EEPROM.
29918c2ecf20Sopenharmony_ci	 *
29928c2ecf20Sopenharmony_ci	 * TODO: Not used yet.
29938c2ecf20Sopenharmony_ci	 */
29948c2ecf20Sopenharmony_ci	data->resettime = nsp32_prom_read(data, 0x12);
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_ci	/*
29978c2ecf20Sopenharmony_ci	 * HBA Synchronous Transfer Period
29988c2ecf20Sopenharmony_ci	 *
29998c2ecf20Sopenharmony_ci	 * Note: auto_sync = 0: auto, 1: manual.  Ninja SCSI HBA spec says
30008c2ecf20Sopenharmony_ci	 *	that if auto_sync is 0 (auto), and connected SCSI devices are
30018c2ecf20Sopenharmony_ci	 *	same or lower than 3, then transfer speed is set as ULTRA-20M.
30028c2ecf20Sopenharmony_ci	 *	On the contrary if connected SCSI devices are same or higher
30038c2ecf20Sopenharmony_ci	 *	than 4, then transfer speed is set as FAST-10M.
30048c2ecf20Sopenharmony_ci	 *
30058c2ecf20Sopenharmony_ci	 *	I break this rule. The number of connected SCSI devices are
30068c2ecf20Sopenharmony_ci	 *	only ignored. If auto_sync is 0 (auto), then transfer speed is
30078c2ecf20Sopenharmony_ci	 *	forced as ULTRA-20M.
30088c2ecf20Sopenharmony_ci	 */
30098c2ecf20Sopenharmony_ci	ret = nsp32_prom_read(data, 0x07);
30108c2ecf20Sopenharmony_ci	switch (ret) {
30118c2ecf20Sopenharmony_ci	case 0:
30128c2ecf20Sopenharmony_ci		auto_sync = TRUE;
30138c2ecf20Sopenharmony_ci		break;
30148c2ecf20Sopenharmony_ci	case 1:
30158c2ecf20Sopenharmony_ci		auto_sync = FALSE;
30168c2ecf20Sopenharmony_ci		break;
30178c2ecf20Sopenharmony_ci	default:
30188c2ecf20Sopenharmony_ci		nsp32_msg(KERN_WARNING,
30198c2ecf20Sopenharmony_ci			  "Unsupported Auto Sync mode. Fall back to manual mode.");
30208c2ecf20Sopenharmony_ci		auto_sync = TRUE;
30218c2ecf20Sopenharmony_ci	}
30228c2ecf20Sopenharmony_ci
30238c2ecf20Sopenharmony_ci	if (trans_mode == ULTRA20M_MODE) {
30248c2ecf20Sopenharmony_ci		auto_sync = TRUE;
30258c2ecf20Sopenharmony_ci	}
30268c2ecf20Sopenharmony_ci
30278c2ecf20Sopenharmony_ci	/*
30288c2ecf20Sopenharmony_ci	 * each device Synchronous Transfer Period
30298c2ecf20Sopenharmony_ci	 */
30308c2ecf20Sopenharmony_ci	for (i = 0; i < NSP32_HOST_SCSIID; i++) {
30318c2ecf20Sopenharmony_ci		target = &data->target[i];
30328c2ecf20Sopenharmony_ci		if (auto_sync == TRUE) {
30338c2ecf20Sopenharmony_ci			target->limit_entry = 0;   /* set as ULTRA20M */
30348c2ecf20Sopenharmony_ci		} else {
30358c2ecf20Sopenharmony_ci			ret   = nsp32_prom_read(data, i);
30368c2ecf20Sopenharmony_ci			entry = nsp32_search_period_entry(data, target, ret);
30378c2ecf20Sopenharmony_ci			if (entry < 0) {
30388c2ecf20Sopenharmony_ci				/* search failed... set maximum speed */
30398c2ecf20Sopenharmony_ci				entry = 0;
30408c2ecf20Sopenharmony_ci			}
30418c2ecf20Sopenharmony_ci			target->limit_entry = entry;
30428c2ecf20Sopenharmony_ci		}
30438c2ecf20Sopenharmony_ci	}
30448c2ecf20Sopenharmony_ci
30458c2ecf20Sopenharmony_ci	return TRUE;
30468c2ecf20Sopenharmony_ci}
30478c2ecf20Sopenharmony_ci
30488c2ecf20Sopenharmony_ci
30498c2ecf20Sopenharmony_ci/*
30508c2ecf20Sopenharmony_ci * C16 110 (I-O Data: SC-NBD) data map:
30518c2ecf20Sopenharmony_ci *
30528c2ecf20Sopenharmony_ci *   ROMADDR
30538c2ecf20Sopenharmony_ci *   0x00 - 0x06 :  Device Synchronous Transfer Period (SCSI ID 0 - 6)
30548c2ecf20Sopenharmony_ci *			Value 0x0: 20MB/S, 0x1: 10MB/S, 0x2: 5MB/S, 0x3: ASYNC
30558c2ecf20Sopenharmony_ci *   0x07        :  0 (HBA Synchronous Transfer Period: Auto Sync)
30568c2ecf20Sopenharmony_ci *   0x08 - 0x0f :  Not Used? (0x0)
30578c2ecf20Sopenharmony_ci *   0x10        :  Transfer Mode
30588c2ecf20Sopenharmony_ci *			Value 0: PIO, 1: Busmater
30598c2ecf20Sopenharmony_ci *   0x11        :  Bus Reset Delay Time (0x00-0x20)
30608c2ecf20Sopenharmony_ci *   0x12        :  Bus Termination
30618c2ecf20Sopenharmony_ci * 			Value 0: Disable, 1: Enable
30628c2ecf20Sopenharmony_ci *   0x13 - 0x19 :  Disconnection
30638c2ecf20Sopenharmony_ci *			Value 0: Disable, 1: Enable
30648c2ecf20Sopenharmony_ci *   0x1a - 0x7c :  Not Used? (0)
30658c2ecf20Sopenharmony_ci *   0x7d	 :  Not Used? (0xf8)
30668c2ecf20Sopenharmony_ci *   0x7e        :  Constant (0x55), Validity signature
30678c2ecf20Sopenharmony_ci *   0x7f        :  Constant (0xaa), Validity signature
30688c2ecf20Sopenharmony_ci */
30698c2ecf20Sopenharmony_cistatic int nsp32_getprom_c16(nsp32_hw_data *data)
30708c2ecf20Sopenharmony_ci{
30718c2ecf20Sopenharmony_ci	int           ret, i;
30728c2ecf20Sopenharmony_ci	nsp32_target *target;
30738c2ecf20Sopenharmony_ci	int           entry, val;
30748c2ecf20Sopenharmony_ci
30758c2ecf20Sopenharmony_ci	/*
30768c2ecf20Sopenharmony_ci	 * Reset time which is designated by EEPROM.
30778c2ecf20Sopenharmony_ci	 *
30788c2ecf20Sopenharmony_ci	 * TODO: Not used yet.
30798c2ecf20Sopenharmony_ci	 */
30808c2ecf20Sopenharmony_ci	data->resettime = nsp32_prom_read(data, 0x11);
30818c2ecf20Sopenharmony_ci
30828c2ecf20Sopenharmony_ci	/*
30838c2ecf20Sopenharmony_ci	 * each device Synchronous Transfer Period
30848c2ecf20Sopenharmony_ci	 */
30858c2ecf20Sopenharmony_ci	for (i = 0; i < NSP32_HOST_SCSIID; i++) {
30868c2ecf20Sopenharmony_ci		target = &data->target[i];
30878c2ecf20Sopenharmony_ci		ret = nsp32_prom_read(data, i);
30888c2ecf20Sopenharmony_ci		switch (ret) {
30898c2ecf20Sopenharmony_ci		case 0:		/* 20MB/s */
30908c2ecf20Sopenharmony_ci			val = 0x0c;
30918c2ecf20Sopenharmony_ci			break;
30928c2ecf20Sopenharmony_ci		case 1:		/* 10MB/s */
30938c2ecf20Sopenharmony_ci			val = 0x19;
30948c2ecf20Sopenharmony_ci			break;
30958c2ecf20Sopenharmony_ci		case 2:		/* 5MB/s */
30968c2ecf20Sopenharmony_ci			val = 0x32;
30978c2ecf20Sopenharmony_ci			break;
30988c2ecf20Sopenharmony_ci		case 3:		/* ASYNC */
30998c2ecf20Sopenharmony_ci			val = 0x00;
31008c2ecf20Sopenharmony_ci			break;
31018c2ecf20Sopenharmony_ci		default:	/* default 20MB/s */
31028c2ecf20Sopenharmony_ci			val = 0x0c;
31038c2ecf20Sopenharmony_ci			break;
31048c2ecf20Sopenharmony_ci		}
31058c2ecf20Sopenharmony_ci		entry = nsp32_search_period_entry(data, target, val);
31068c2ecf20Sopenharmony_ci		if (entry < 0 || trans_mode == ULTRA20M_MODE) {
31078c2ecf20Sopenharmony_ci			/* search failed... set maximum speed */
31088c2ecf20Sopenharmony_ci			entry = 0;
31098c2ecf20Sopenharmony_ci		}
31108c2ecf20Sopenharmony_ci		target->limit_entry = entry;
31118c2ecf20Sopenharmony_ci	}
31128c2ecf20Sopenharmony_ci
31138c2ecf20Sopenharmony_ci	return TRUE;
31148c2ecf20Sopenharmony_ci}
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci
31178c2ecf20Sopenharmony_ci/*
31188c2ecf20Sopenharmony_ci * Atmel AT24C01A (drived in 5V) serial EEPROM routines
31198c2ecf20Sopenharmony_ci */
31208c2ecf20Sopenharmony_cistatic int nsp32_prom_read(nsp32_hw_data *data, int romaddr)
31218c2ecf20Sopenharmony_ci{
31228c2ecf20Sopenharmony_ci	int i, val;
31238c2ecf20Sopenharmony_ci
31248c2ecf20Sopenharmony_ci	/* start condition */
31258c2ecf20Sopenharmony_ci	nsp32_prom_start(data);
31268c2ecf20Sopenharmony_ci
31278c2ecf20Sopenharmony_ci	/* device address */
31288c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 1);	/* 1 */
31298c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* 0 */
31308c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 1);	/* 1 */
31318c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* 0 */
31328c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* A2: 0 (GND) */
31338c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* A1: 0 (GND) */
31348c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* A0: 0 (GND) */
31358c2ecf20Sopenharmony_ci
31368c2ecf20Sopenharmony_ci	/* R/W: W for dummy write */
31378c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);
31388c2ecf20Sopenharmony_ci
31398c2ecf20Sopenharmony_ci	/* ack */
31408c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci	/* word address */
31438c2ecf20Sopenharmony_ci	for (i = 7; i >= 0; i--) {
31448c2ecf20Sopenharmony_ci		nsp32_prom_write_bit(data, ((romaddr >> i) & 1));
31458c2ecf20Sopenharmony_ci	}
31468c2ecf20Sopenharmony_ci
31478c2ecf20Sopenharmony_ci	/* ack */
31488c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);
31498c2ecf20Sopenharmony_ci
31508c2ecf20Sopenharmony_ci	/* start condition */
31518c2ecf20Sopenharmony_ci	nsp32_prom_start(data);
31528c2ecf20Sopenharmony_ci
31538c2ecf20Sopenharmony_ci	/* device address */
31548c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 1);	/* 1 */
31558c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* 0 */
31568c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 1);	/* 1 */
31578c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* 0 */
31588c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* A2: 0 (GND) */
31598c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* A1: 0 (GND) */
31608c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);	/* A0: 0 (GND) */
31618c2ecf20Sopenharmony_ci
31628c2ecf20Sopenharmony_ci	/* R/W: R */
31638c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 1);
31648c2ecf20Sopenharmony_ci
31658c2ecf20Sopenharmony_ci	/* ack */
31668c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 0);
31678c2ecf20Sopenharmony_ci
31688c2ecf20Sopenharmony_ci	/* data... */
31698c2ecf20Sopenharmony_ci	val = 0;
31708c2ecf20Sopenharmony_ci	for (i = 7; i >= 0; i--) {
31718c2ecf20Sopenharmony_ci		val += (nsp32_prom_read_bit(data) << i);
31728c2ecf20Sopenharmony_ci	}
31738c2ecf20Sopenharmony_ci
31748c2ecf20Sopenharmony_ci	/* no ack */
31758c2ecf20Sopenharmony_ci	nsp32_prom_write_bit(data, 1);
31768c2ecf20Sopenharmony_ci
31778c2ecf20Sopenharmony_ci	/* stop condition */
31788c2ecf20Sopenharmony_ci	nsp32_prom_stop(data);
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci	return val;
31818c2ecf20Sopenharmony_ci}
31828c2ecf20Sopenharmony_ci
31838c2ecf20Sopenharmony_cistatic void nsp32_prom_set(nsp32_hw_data *data, int bit, int val)
31848c2ecf20Sopenharmony_ci{
31858c2ecf20Sopenharmony_ci	int base = data->BaseAddress;
31868c2ecf20Sopenharmony_ci	int tmp;
31878c2ecf20Sopenharmony_ci
31888c2ecf20Sopenharmony_ci	tmp = nsp32_index_read1(base, SERIAL_ROM_CTL);
31898c2ecf20Sopenharmony_ci
31908c2ecf20Sopenharmony_ci	if (val == 0) {
31918c2ecf20Sopenharmony_ci		tmp &= ~bit;
31928c2ecf20Sopenharmony_ci	} else {
31938c2ecf20Sopenharmony_ci		tmp |=  bit;
31948c2ecf20Sopenharmony_ci	}
31958c2ecf20Sopenharmony_ci
31968c2ecf20Sopenharmony_ci	nsp32_index_write1(base, SERIAL_ROM_CTL, tmp);
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_ci	udelay(10);
31998c2ecf20Sopenharmony_ci}
32008c2ecf20Sopenharmony_ci
32018c2ecf20Sopenharmony_cistatic int nsp32_prom_get(nsp32_hw_data *data, int bit)
32028c2ecf20Sopenharmony_ci{
32038c2ecf20Sopenharmony_ci	int base = data->BaseAddress;
32048c2ecf20Sopenharmony_ci	int tmp, ret;
32058c2ecf20Sopenharmony_ci
32068c2ecf20Sopenharmony_ci	if (bit != SDA) {
32078c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "return value is not appropriate");
32088c2ecf20Sopenharmony_ci		return 0;
32098c2ecf20Sopenharmony_ci	}
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_ci
32128c2ecf20Sopenharmony_ci	tmp = nsp32_index_read1(base, SERIAL_ROM_CTL) & bit;
32138c2ecf20Sopenharmony_ci
32148c2ecf20Sopenharmony_ci	if (tmp == 0) {
32158c2ecf20Sopenharmony_ci		ret = 0;
32168c2ecf20Sopenharmony_ci	} else {
32178c2ecf20Sopenharmony_ci		ret = 1;
32188c2ecf20Sopenharmony_ci	}
32198c2ecf20Sopenharmony_ci
32208c2ecf20Sopenharmony_ci	udelay(10);
32218c2ecf20Sopenharmony_ci
32228c2ecf20Sopenharmony_ci	return ret;
32238c2ecf20Sopenharmony_ci}
32248c2ecf20Sopenharmony_ci
32258c2ecf20Sopenharmony_cistatic void nsp32_prom_start (nsp32_hw_data *data)
32268c2ecf20Sopenharmony_ci{
32278c2ecf20Sopenharmony_ci	/* start condition */
32288c2ecf20Sopenharmony_ci	nsp32_prom_set(data, SCL, 1);
32298c2ecf20Sopenharmony_ci	nsp32_prom_set(data, SDA, 1);
32308c2ecf20Sopenharmony_ci	nsp32_prom_set(data, ENA, 1);	/* output mode */
32318c2ecf20Sopenharmony_ci	nsp32_prom_set(data, SDA, 0);	/* keeping SCL=1 and transiting
32328c2ecf20Sopenharmony_ci					 * SDA 1->0 is start condition */
32338c2ecf20Sopenharmony_ci	nsp32_prom_set(data, SCL, 0);
32348c2ecf20Sopenharmony_ci}
32358c2ecf20Sopenharmony_ci
32368c2ecf20Sopenharmony_cistatic void nsp32_prom_stop (nsp32_hw_data *data)
32378c2ecf20Sopenharmony_ci{
32388c2ecf20Sopenharmony_ci	/* stop condition */
32398c2ecf20Sopenharmony_ci	nsp32_prom_set(data, SCL, 1);
32408c2ecf20Sopenharmony_ci	nsp32_prom_set(data, SDA, 0);
32418c2ecf20Sopenharmony_ci	nsp32_prom_set(data, ENA, 1);	/* output mode */
32428c2ecf20Sopenharmony_ci	nsp32_prom_set(data, SDA, 1);
32438c2ecf20Sopenharmony_ci	nsp32_prom_set(data, SCL, 0);
32448c2ecf20Sopenharmony_ci}
32458c2ecf20Sopenharmony_ci
32468c2ecf20Sopenharmony_cistatic void nsp32_prom_write_bit(nsp32_hw_data *data, int val)
32478c2ecf20Sopenharmony_ci{
32488c2ecf20Sopenharmony_ci	/* write */
32498c2ecf20Sopenharmony_ci	nsp32_prom_set(data, SDA, val);
32508c2ecf20Sopenharmony_ci	nsp32_prom_set(data, SCL, 1  );
32518c2ecf20Sopenharmony_ci	nsp32_prom_set(data, SCL, 0  );
32528c2ecf20Sopenharmony_ci}
32538c2ecf20Sopenharmony_ci
32548c2ecf20Sopenharmony_cistatic int nsp32_prom_read_bit(nsp32_hw_data *data)
32558c2ecf20Sopenharmony_ci{
32568c2ecf20Sopenharmony_ci	int val;
32578c2ecf20Sopenharmony_ci
32588c2ecf20Sopenharmony_ci	/* read */
32598c2ecf20Sopenharmony_ci	nsp32_prom_set(data, ENA, 0);	/* input mode */
32608c2ecf20Sopenharmony_ci	nsp32_prom_set(data, SCL, 1);
32618c2ecf20Sopenharmony_ci
32628c2ecf20Sopenharmony_ci	val = nsp32_prom_get(data, SDA);
32638c2ecf20Sopenharmony_ci
32648c2ecf20Sopenharmony_ci	nsp32_prom_set(data, SCL, 0);
32658c2ecf20Sopenharmony_ci	nsp32_prom_set(data, ENA, 1);	/* output mode */
32668c2ecf20Sopenharmony_ci
32678c2ecf20Sopenharmony_ci	return val;
32688c2ecf20Sopenharmony_ci}
32698c2ecf20Sopenharmony_ci
32708c2ecf20Sopenharmony_ci
32718c2ecf20Sopenharmony_ci/**************************************************************************
32728c2ecf20Sopenharmony_ci * Power Management
32738c2ecf20Sopenharmony_ci */
32748c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
32758c2ecf20Sopenharmony_ci
32768c2ecf20Sopenharmony_ci/* Device suspended */
32778c2ecf20Sopenharmony_cistatic int nsp32_suspend(struct pci_dev *pdev, pm_message_t state)
32788c2ecf20Sopenharmony_ci{
32798c2ecf20Sopenharmony_ci	struct Scsi_Host *host = pci_get_drvdata(pdev);
32808c2ecf20Sopenharmony_ci
32818c2ecf20Sopenharmony_ci	nsp32_msg(KERN_INFO, "pci-suspend: pdev=0x%p, state=%ld, slot=%s, host=0x%p", pdev, state, pci_name(pdev), host);
32828c2ecf20Sopenharmony_ci
32838c2ecf20Sopenharmony_ci	pci_save_state     (pdev);
32848c2ecf20Sopenharmony_ci	pci_disable_device (pdev);
32858c2ecf20Sopenharmony_ci	pci_set_power_state(pdev, pci_choose_state(pdev, state));
32868c2ecf20Sopenharmony_ci
32878c2ecf20Sopenharmony_ci	return 0;
32888c2ecf20Sopenharmony_ci}
32898c2ecf20Sopenharmony_ci
32908c2ecf20Sopenharmony_ci/* Device woken up */
32918c2ecf20Sopenharmony_cistatic int nsp32_resume(struct pci_dev *pdev)
32928c2ecf20Sopenharmony_ci{
32938c2ecf20Sopenharmony_ci	struct Scsi_Host *host = pci_get_drvdata(pdev);
32948c2ecf20Sopenharmony_ci	nsp32_hw_data    *data = (nsp32_hw_data *)host->hostdata;
32958c2ecf20Sopenharmony_ci	unsigned short    reg;
32968c2ecf20Sopenharmony_ci
32978c2ecf20Sopenharmony_ci	nsp32_msg(KERN_INFO, "pci-resume: pdev=0x%p, slot=%s, host=0x%p", pdev, pci_name(pdev), host);
32988c2ecf20Sopenharmony_ci
32998c2ecf20Sopenharmony_ci	pci_set_power_state(pdev, PCI_D0);
33008c2ecf20Sopenharmony_ci	pci_enable_wake    (pdev, PCI_D0, 0);
33018c2ecf20Sopenharmony_ci	pci_restore_state  (pdev);
33028c2ecf20Sopenharmony_ci
33038c2ecf20Sopenharmony_ci	reg = nsp32_read2(data->BaseAddress, INDEX_REG);
33048c2ecf20Sopenharmony_ci
33058c2ecf20Sopenharmony_ci	nsp32_msg(KERN_INFO, "io=0x%x reg=0x%x", data->BaseAddress, reg);
33068c2ecf20Sopenharmony_ci
33078c2ecf20Sopenharmony_ci	if (reg == 0xffff) {
33088c2ecf20Sopenharmony_ci		nsp32_msg(KERN_INFO, "missing device. abort resume.");
33098c2ecf20Sopenharmony_ci		return 0;
33108c2ecf20Sopenharmony_ci	}
33118c2ecf20Sopenharmony_ci
33128c2ecf20Sopenharmony_ci	nsp32hw_init      (data);
33138c2ecf20Sopenharmony_ci	nsp32_do_bus_reset(data);
33148c2ecf20Sopenharmony_ci
33158c2ecf20Sopenharmony_ci	nsp32_msg(KERN_INFO, "resume success");
33168c2ecf20Sopenharmony_ci
33178c2ecf20Sopenharmony_ci	return 0;
33188c2ecf20Sopenharmony_ci}
33198c2ecf20Sopenharmony_ci
33208c2ecf20Sopenharmony_ci#endif
33218c2ecf20Sopenharmony_ci
33228c2ecf20Sopenharmony_ci/************************************************************************
33238c2ecf20Sopenharmony_ci * PCI/Cardbus probe/remove routine
33248c2ecf20Sopenharmony_ci */
33258c2ecf20Sopenharmony_cistatic int nsp32_probe(struct pci_dev *pdev, const struct pci_device_id *id)
33268c2ecf20Sopenharmony_ci{
33278c2ecf20Sopenharmony_ci	int ret;
33288c2ecf20Sopenharmony_ci	nsp32_hw_data *data = &nsp32_data_base;
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
33318c2ecf20Sopenharmony_ci
33328c2ecf20Sopenharmony_ci        ret = pci_enable_device(pdev);
33338c2ecf20Sopenharmony_ci	if (ret) {
33348c2ecf20Sopenharmony_ci		nsp32_msg(KERN_ERR, "failed to enable pci device");
33358c2ecf20Sopenharmony_ci		return ret;
33368c2ecf20Sopenharmony_ci	}
33378c2ecf20Sopenharmony_ci
33388c2ecf20Sopenharmony_ci	data->Pci         = pdev;
33398c2ecf20Sopenharmony_ci	data->pci_devid   = id;
33408c2ecf20Sopenharmony_ci	data->IrqNumber   = pdev->irq;
33418c2ecf20Sopenharmony_ci	data->BaseAddress = pci_resource_start(pdev, 0);
33428c2ecf20Sopenharmony_ci	data->NumAddress  = pci_resource_len  (pdev, 0);
33438c2ecf20Sopenharmony_ci	data->MmioAddress = pci_ioremap_bar(pdev, 1);
33448c2ecf20Sopenharmony_ci	data->MmioLength  = pci_resource_len  (pdev, 1);
33458c2ecf20Sopenharmony_ci
33468c2ecf20Sopenharmony_ci	pci_set_master(pdev);
33478c2ecf20Sopenharmony_ci
33488c2ecf20Sopenharmony_ci	ret = nsp32_detect(pdev);
33498c2ecf20Sopenharmony_ci
33508c2ecf20Sopenharmony_ci	nsp32_msg(KERN_INFO, "irq: %i mmio: %p+0x%lx slot: %s model: %s",
33518c2ecf20Sopenharmony_ci		  pdev->irq,
33528c2ecf20Sopenharmony_ci		  data->MmioAddress, data->MmioLength,
33538c2ecf20Sopenharmony_ci		  pci_name(pdev),
33548c2ecf20Sopenharmony_ci		  nsp32_model[id->driver_data]);
33558c2ecf20Sopenharmony_ci
33568c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_REGISTER, "exit %d", ret);
33578c2ecf20Sopenharmony_ci
33588c2ecf20Sopenharmony_ci	return ret;
33598c2ecf20Sopenharmony_ci}
33608c2ecf20Sopenharmony_ci
33618c2ecf20Sopenharmony_cistatic void nsp32_remove(struct pci_dev *pdev)
33628c2ecf20Sopenharmony_ci{
33638c2ecf20Sopenharmony_ci	struct Scsi_Host *host = pci_get_drvdata(pdev);
33648c2ecf20Sopenharmony_ci
33658c2ecf20Sopenharmony_ci	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
33668c2ecf20Sopenharmony_ci
33678c2ecf20Sopenharmony_ci        scsi_remove_host(host);
33688c2ecf20Sopenharmony_ci
33698c2ecf20Sopenharmony_ci	nsp32_release(host);
33708c2ecf20Sopenharmony_ci
33718c2ecf20Sopenharmony_ci	scsi_host_put(host);
33728c2ecf20Sopenharmony_ci}
33738c2ecf20Sopenharmony_ci
33748c2ecf20Sopenharmony_cistatic struct pci_driver nsp32_driver = {
33758c2ecf20Sopenharmony_ci	.name		= "nsp32",
33768c2ecf20Sopenharmony_ci	.id_table	= nsp32_pci_table,
33778c2ecf20Sopenharmony_ci	.probe		= nsp32_probe,
33788c2ecf20Sopenharmony_ci	.remove		= nsp32_remove,
33798c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
33808c2ecf20Sopenharmony_ci	.suspend	= nsp32_suspend,
33818c2ecf20Sopenharmony_ci	.resume		= nsp32_resume,
33828c2ecf20Sopenharmony_ci#endif
33838c2ecf20Sopenharmony_ci};
33848c2ecf20Sopenharmony_ci
33858c2ecf20Sopenharmony_ci/*********************************************************************
33868c2ecf20Sopenharmony_ci * Moule entry point
33878c2ecf20Sopenharmony_ci */
33888c2ecf20Sopenharmony_cistatic int __init init_nsp32(void) {
33898c2ecf20Sopenharmony_ci	nsp32_msg(KERN_INFO, "loading...");
33908c2ecf20Sopenharmony_ci	return pci_register_driver(&nsp32_driver);
33918c2ecf20Sopenharmony_ci}
33928c2ecf20Sopenharmony_ci
33938c2ecf20Sopenharmony_cistatic void __exit exit_nsp32(void) {
33948c2ecf20Sopenharmony_ci	nsp32_msg(KERN_INFO, "unloading...");
33958c2ecf20Sopenharmony_ci	pci_unregister_driver(&nsp32_driver);
33968c2ecf20Sopenharmony_ci}
33978c2ecf20Sopenharmony_ci
33988c2ecf20Sopenharmony_cimodule_init(init_nsp32);
33998c2ecf20Sopenharmony_cimodule_exit(exit_nsp32);
34008c2ecf20Sopenharmony_ci
34018c2ecf20Sopenharmony_ci/* end */
3402