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