18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/************************************************************************ 38c2ecf20Sopenharmony_ci * Linux driver for * 48c2ecf20Sopenharmony_ci * ICP vortex GmbH: GDT PCI Disk Array Controllers * 58c2ecf20Sopenharmony_ci * Intel Corporation: Storage RAID Controllers * 68c2ecf20Sopenharmony_ci * * 78c2ecf20Sopenharmony_ci * gdth.c * 88c2ecf20Sopenharmony_ci * Copyright (C) 1995-06 ICP vortex GmbH, Achim Leubner * 98c2ecf20Sopenharmony_ci * Copyright (C) 2002-04 Intel Corporation * 108c2ecf20Sopenharmony_ci * Copyright (C) 2003-06 Adaptec Inc. * 118c2ecf20Sopenharmony_ci * <achim_leubner@adaptec.com> * 128c2ecf20Sopenharmony_ci * * 138c2ecf20Sopenharmony_ci * Additions/Fixes: * 148c2ecf20Sopenharmony_ci * Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com> * 158c2ecf20Sopenharmony_ci * Johannes Dinner <johannes_dinner@adaptec.com> * 168c2ecf20Sopenharmony_ci * * 178c2ecf20Sopenharmony_ci * * 188c2ecf20Sopenharmony_ci * Linux kernel 2.6.x supported * 198c2ecf20Sopenharmony_ci * * 208c2ecf20Sopenharmony_ci ************************************************************************/ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* All GDT Disk Array Controllers are fully supported by this driver. 238c2ecf20Sopenharmony_ci * This includes the PCI SCSI Disk Array Controllers and the 248c2ecf20Sopenharmony_ci * PCI Fibre Channel Disk Array Controllers. See gdth.h for a complete 258c2ecf20Sopenharmony_ci * list of all controller types. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * After the optional list of IRQ values, other possible 288c2ecf20Sopenharmony_ci * command line options are: 298c2ecf20Sopenharmony_ci * disable:Y disable driver 308c2ecf20Sopenharmony_ci * disable:N enable driver 318c2ecf20Sopenharmony_ci * reserve_mode:0 reserve no drives for the raw service 328c2ecf20Sopenharmony_ci * reserve_mode:1 reserve all not init., removable drives 338c2ecf20Sopenharmony_ci * reserve_mode:2 reserve all not init. drives 348c2ecf20Sopenharmony_ci * reserve_list:h,b,t,l,h,b,t,l,... reserve particular drive(s) with 358c2ecf20Sopenharmony_ci * h- controller no., b- channel no., 368c2ecf20Sopenharmony_ci * t- target ID, l- LUN 378c2ecf20Sopenharmony_ci * reverse_scan:Y reverse scan order for PCI controllers 388c2ecf20Sopenharmony_ci * reverse_scan:N scan PCI controllers like BIOS 398c2ecf20Sopenharmony_ci * max_ids:x x - target ID count per channel (1..MAXID) 408c2ecf20Sopenharmony_ci * rescan:Y rescan all channels/IDs 418c2ecf20Sopenharmony_ci * rescan:N use all devices found until now 428c2ecf20Sopenharmony_ci * hdr_channel:x x - number of virtual bus for host drives 438c2ecf20Sopenharmony_ci * shared_access:Y disable driver reserve/release protocol to 448c2ecf20Sopenharmony_ci * access a shared resource from several nodes, 458c2ecf20Sopenharmony_ci * appropriate controller firmware required 468c2ecf20Sopenharmony_ci * shared_access:N enable driver reserve/release protocol 478c2ecf20Sopenharmony_ci * force_dma32:Y use only 32 bit DMA mode 488c2ecf20Sopenharmony_ci * force_dma32:N use 64 bit DMA mode, if supported 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N, 518c2ecf20Sopenharmony_ci * max_ids:127,rescan:N,hdr_channel:0, 528c2ecf20Sopenharmony_ci * shared_access:Y,force_dma32:N". 538c2ecf20Sopenharmony_ci * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y". 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * When loading the gdth driver as a module, the same options are available. 568c2ecf20Sopenharmony_ci * You can set the IRQs with "IRQ=...". However, the syntax to specify the 578c2ecf20Sopenharmony_ci * options changes slightly. You must replace all ',' between options 588c2ecf20Sopenharmony_ci * with ' ' and all ':' with '=' and you must use 598c2ecf20Sopenharmony_ci * '1' in place of 'Y' and '0' in place of 'N'. 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0 628c2ecf20Sopenharmony_ci * max_ids=127 rescan=0 hdr_channel=0 shared_access=0 638c2ecf20Sopenharmony_ci * force_dma32=0" 648c2ecf20Sopenharmony_ci * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1". 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* The meaning of the Scsi_Pointer members in this driver is as follows: 688c2ecf20Sopenharmony_ci * ptr: Chaining 698c2ecf20Sopenharmony_ci * this_residual: unused 708c2ecf20Sopenharmony_ci * buffer: unused 718c2ecf20Sopenharmony_ci * dma_handle: unused 728c2ecf20Sopenharmony_ci * buffers_residual: unused 738c2ecf20Sopenharmony_ci * Status: unused 748c2ecf20Sopenharmony_ci * Message: unused 758c2ecf20Sopenharmony_ci * have_data_in: unused 768c2ecf20Sopenharmony_ci * sent_command: unused 778c2ecf20Sopenharmony_ci * phase: unused 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* statistics */ 818c2ecf20Sopenharmony_ci#define GDTH_STATISTICS 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#include <linux/module.h> 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#include <linux/version.h> 868c2ecf20Sopenharmony_ci#include <linux/kernel.h> 878c2ecf20Sopenharmony_ci#include <linux/types.h> 888c2ecf20Sopenharmony_ci#include <linux/pci.h> 898c2ecf20Sopenharmony_ci#include <linux/string.h> 908c2ecf20Sopenharmony_ci#include <linux/ctype.h> 918c2ecf20Sopenharmony_ci#include <linux/ioport.h> 928c2ecf20Sopenharmony_ci#include <linux/delay.h> 938c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 948c2ecf20Sopenharmony_ci#include <linux/in.h> 958c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 968c2ecf20Sopenharmony_ci#include <linux/time.h> 978c2ecf20Sopenharmony_ci#include <linux/timer.h> 988c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 998c2ecf20Sopenharmony_ci#include <linux/list.h> 1008c2ecf20Sopenharmony_ci#include <linux/mutex.h> 1018c2ecf20Sopenharmony_ci#include <linux/slab.h> 1028c2ecf20Sopenharmony_ci#include <linux/reboot.h> 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#include <asm/dma.h> 1058c2ecf20Sopenharmony_ci#include <asm/io.h> 1068c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 1078c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 1088c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 1098c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci#include "scsi.h" 1128c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 1138c2ecf20Sopenharmony_ci#include "gdth.h" 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(gdth_mutex); 1168c2ecf20Sopenharmony_cistatic void gdth_delay(int milliseconds); 1178c2ecf20Sopenharmony_cistatic void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs); 1188c2ecf20Sopenharmony_cistatic irqreturn_t gdth_interrupt(int irq, void *dev_id); 1198c2ecf20Sopenharmony_cistatic irqreturn_t __gdth_interrupt(gdth_ha_str *ha, 1208c2ecf20Sopenharmony_ci int gdth_from_wait, int* pIndex); 1218c2ecf20Sopenharmony_cistatic int gdth_sync_event(gdth_ha_str *ha, int service, u8 index, 1228c2ecf20Sopenharmony_ci struct scsi_cmnd *scp); 1238c2ecf20Sopenharmony_cistatic int gdth_async_event(gdth_ha_str *ha); 1248c2ecf20Sopenharmony_cistatic void gdth_log_event(gdth_evt_data *dvr, char *buffer); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic void gdth_putq(gdth_ha_str *ha, struct scsi_cmnd *scp, u8 priority); 1278c2ecf20Sopenharmony_cistatic void gdth_next(gdth_ha_str *ha); 1288c2ecf20Sopenharmony_cistatic int gdth_fill_raw_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, u8 b); 1298c2ecf20Sopenharmony_cistatic int gdth_special_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp); 1308c2ecf20Sopenharmony_cistatic gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source, 1318c2ecf20Sopenharmony_ci u16 idx, gdth_evt_data *evt); 1328c2ecf20Sopenharmony_cistatic int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr); 1338c2ecf20Sopenharmony_cistatic void gdth_readapp_event(gdth_ha_str *ha, u8 application, 1348c2ecf20Sopenharmony_ci gdth_evt_str *estr); 1358c2ecf20Sopenharmony_cistatic void gdth_clear_events(void); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void gdth_copy_internal_data(gdth_ha_str *ha, struct scsi_cmnd *scp, 1388c2ecf20Sopenharmony_ci char *buffer, u16 count); 1398c2ecf20Sopenharmony_cistatic int gdth_internal_cache_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp); 1408c2ecf20Sopenharmony_cistatic int gdth_fill_cache_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, 1418c2ecf20Sopenharmony_ci u16 hdrive); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void gdth_enable_int(gdth_ha_str *ha); 1448c2ecf20Sopenharmony_cistatic int gdth_test_busy(gdth_ha_str *ha); 1458c2ecf20Sopenharmony_cistatic int gdth_get_cmd_index(gdth_ha_str *ha); 1468c2ecf20Sopenharmony_cistatic void gdth_release_event(gdth_ha_str *ha); 1478c2ecf20Sopenharmony_cistatic int gdth_wait(gdth_ha_str *ha, int index,u32 time); 1488c2ecf20Sopenharmony_cistatic int gdth_internal_cmd(gdth_ha_str *ha, u8 service, u16 opcode, 1498c2ecf20Sopenharmony_ci u32 p1, u64 p2,u64 p3); 1508c2ecf20Sopenharmony_cistatic int gdth_search_drives(gdth_ha_str *ha); 1518c2ecf20Sopenharmony_cistatic int gdth_analyse_hdrive(gdth_ha_str *ha, u16 hdrive); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic const char *gdth_ctr_name(gdth_ha_str *ha); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int gdth_open(struct inode *inode, struct file *filep); 1568c2ecf20Sopenharmony_cistatic int gdth_close(struct inode *inode, struct file *filep); 1578c2ecf20Sopenharmony_cistatic long gdth_unlocked_ioctl(struct file *filep, unsigned int cmd, 1588c2ecf20Sopenharmony_ci unsigned long arg); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic void gdth_flush(gdth_ha_str *ha); 1618c2ecf20Sopenharmony_cistatic int gdth_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); 1628c2ecf20Sopenharmony_cistatic int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp, 1638c2ecf20Sopenharmony_ci struct gdth_cmndinfo *cmndinfo); 1648c2ecf20Sopenharmony_cistatic void gdth_scsi_done(struct scsi_cmnd *scp); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#ifdef DEBUG_GDTH 1678c2ecf20Sopenharmony_cistatic u8 DebugState = DEBUG_GDTH; 1688c2ecf20Sopenharmony_ci#define TRACE(a) {if (DebugState==1) {printk a;}} 1698c2ecf20Sopenharmony_ci#define TRACE2(a) {if (DebugState==1 || DebugState==2) {printk a;}} 1708c2ecf20Sopenharmony_ci#define TRACE3(a) {if (DebugState!=0) {printk a;}} 1718c2ecf20Sopenharmony_ci#else /* !DEBUG */ 1728c2ecf20Sopenharmony_ci#define TRACE(a) 1738c2ecf20Sopenharmony_ci#define TRACE2(a) 1748c2ecf20Sopenharmony_ci#define TRACE3(a) 1758c2ecf20Sopenharmony_ci#endif 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#ifdef GDTH_STATISTICS 1788c2ecf20Sopenharmony_cistatic u32 max_rq=0, max_index=0, max_sg=0; 1798c2ecf20Sopenharmony_cistatic u32 act_ints=0, act_ios=0, act_stats=0, act_rq=0; 1808c2ecf20Sopenharmony_cistatic struct timer_list gdth_timer; 1818c2ecf20Sopenharmony_ci#endif 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci#define PTR2USHORT(a) (u16)(unsigned long)(a) 1848c2ecf20Sopenharmony_ci#define GDTOFFSOF(a,b) (size_t)&(((a*)0)->b) 1858c2ecf20Sopenharmony_ci#define INDEX_OK(i,t) ((i)<ARRAY_SIZE(t)) 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci#define BUS_L2P(a,b) ((b)>(a)->virt_bus ? (b-1):(b)) 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic u8 gdth_polling; /* polling if TRUE */ 1908c2ecf20Sopenharmony_cistatic int gdth_ctr_count = 0; /* controller count */ 1918c2ecf20Sopenharmony_cistatic LIST_HEAD(gdth_instances); /* controller list */ 1928c2ecf20Sopenharmony_cistatic u8 gdth_write_through = FALSE; /* write through */ 1938c2ecf20Sopenharmony_cistatic gdth_evt_str ebuffer[MAX_EVENTS]; /* event buffer */ 1948c2ecf20Sopenharmony_cistatic int elastidx; 1958c2ecf20Sopenharmony_cistatic int eoldidx; 1968c2ecf20Sopenharmony_cistatic int major; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci#define DIN 1 /* IN data direction */ 1998c2ecf20Sopenharmony_ci#define DOU 2 /* OUT data direction */ 2008c2ecf20Sopenharmony_ci#define DNO DIN /* no data transfer */ 2018c2ecf20Sopenharmony_ci#define DUN DIN /* unknown data direction */ 2028c2ecf20Sopenharmony_cistatic u8 gdth_direction_tab[0x100] = { 2038c2ecf20Sopenharmony_ci DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN, 2048c2ecf20Sopenharmony_ci DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN, 2058c2ecf20Sopenharmony_ci DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DOU,DNO,DUN,DIN,DOU,DOU, 2068c2ecf20Sopenharmony_ci DOU,DOU,DOU,DNO,DIN,DNO,DNO,DIN,DOU,DOU,DOU,DOU,DIN,DOU,DIN,DOU, 2078c2ecf20Sopenharmony_ci DOU,DOU,DIN,DIN,DIN,DNO,DUN,DNO,DNO,DNO,DUN,DNO,DOU,DIN,DUN,DUN, 2088c2ecf20Sopenharmony_ci DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN, 2098c2ecf20Sopenharmony_ci DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, 2108c2ecf20Sopenharmony_ci DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, 2118c2ecf20Sopenharmony_ci DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN,DOU,DUN,DUN,DUN,DUN,DUN, 2128c2ecf20Sopenharmony_ci DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN, 2138c2ecf20Sopenharmony_ci DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DOU,DUN,DNO,DUN,DOU,DOU, 2148c2ecf20Sopenharmony_ci DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, 2158c2ecf20Sopenharmony_ci DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, 2168c2ecf20Sopenharmony_ci DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, 2178c2ecf20Sopenharmony_ci DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN, 2188c2ecf20Sopenharmony_ci DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/* LILO and modprobe/insmod parameters */ 2228c2ecf20Sopenharmony_ci/* disable driver flag */ 2238c2ecf20Sopenharmony_cistatic int disable __initdata = 0; 2248c2ecf20Sopenharmony_ci/* reserve flag */ 2258c2ecf20Sopenharmony_cistatic int reserve_mode = 1; 2268c2ecf20Sopenharmony_ci/* reserve list */ 2278c2ecf20Sopenharmony_cistatic int reserve_list[MAX_RES_ARGS] = 2288c2ecf20Sopenharmony_ci{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 2298c2ecf20Sopenharmony_ci 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 2308c2ecf20Sopenharmony_ci 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; 2318c2ecf20Sopenharmony_ci/* scan order for PCI controllers */ 2328c2ecf20Sopenharmony_cistatic int reverse_scan = 0; 2338c2ecf20Sopenharmony_ci/* virtual channel for the host drives */ 2348c2ecf20Sopenharmony_cistatic int hdr_channel = 0; 2358c2ecf20Sopenharmony_ci/* max. IDs per channel */ 2368c2ecf20Sopenharmony_cistatic int max_ids = MAXID; 2378c2ecf20Sopenharmony_ci/* rescan all IDs */ 2388c2ecf20Sopenharmony_cistatic int rescan = 0; 2398c2ecf20Sopenharmony_ci/* shared access */ 2408c2ecf20Sopenharmony_cistatic int shared_access = 1; 2418c2ecf20Sopenharmony_ci/* 64 bit DMA mode, support for drives > 2 TB, if force_dma32 = 0 */ 2428c2ecf20Sopenharmony_cistatic int force_dma32 = 0; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci/* parameters for modprobe/insmod */ 2458c2ecf20Sopenharmony_cimodule_param(disable, int, 0); 2468c2ecf20Sopenharmony_cimodule_param(reserve_mode, int, 0); 2478c2ecf20Sopenharmony_cimodule_param_array(reserve_list, int, NULL, 0); 2488c2ecf20Sopenharmony_cimodule_param(reverse_scan, int, 0); 2498c2ecf20Sopenharmony_cimodule_param(hdr_channel, int, 0); 2508c2ecf20Sopenharmony_cimodule_param(max_ids, int, 0); 2518c2ecf20Sopenharmony_cimodule_param(rescan, int, 0); 2528c2ecf20Sopenharmony_cimodule_param(shared_access, int, 0); 2538c2ecf20Sopenharmony_cimodule_param(force_dma32, int, 0); 2548c2ecf20Sopenharmony_ciMODULE_AUTHOR("Achim Leubner"); 2558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/* ioctl interface */ 2588c2ecf20Sopenharmony_cistatic const struct file_operations gdth_fops = { 2598c2ecf20Sopenharmony_ci .unlocked_ioctl = gdth_unlocked_ioctl, 2608c2ecf20Sopenharmony_ci .open = gdth_open, 2618c2ecf20Sopenharmony_ci .release = gdth_close, 2628c2ecf20Sopenharmony_ci .llseek = noop_llseek, 2638c2ecf20Sopenharmony_ci}; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci#include "gdth_proc.h" 2668c2ecf20Sopenharmony_ci#include "gdth_proc.c" 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic gdth_ha_str *gdth_find_ha(int hanum) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci gdth_ha_str *ha; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci list_for_each_entry(ha, &gdth_instances, list) 2738c2ecf20Sopenharmony_ci if (hanum == ha->hanum) 2748c2ecf20Sopenharmony_ci return ha; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci return NULL; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic struct gdth_cmndinfo *gdth_get_cmndinfo(gdth_ha_str *ha) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct gdth_cmndinfo *priv = NULL; 2828c2ecf20Sopenharmony_ci unsigned long flags; 2838c2ecf20Sopenharmony_ci int i; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci for (i=0; i<GDTH_MAXCMDS; ++i) { 2888c2ecf20Sopenharmony_ci if (ha->cmndinfo[i].index == 0) { 2898c2ecf20Sopenharmony_ci priv = &ha->cmndinfo[i]; 2908c2ecf20Sopenharmony_ci memset(priv, 0, sizeof(*priv)); 2918c2ecf20Sopenharmony_ci priv->index = i+1; 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci return priv; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void gdth_put_cmndinfo(struct gdth_cmndinfo *priv) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci BUG_ON(!priv); 3048c2ecf20Sopenharmony_ci priv->index = 0; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void gdth_delay(int milliseconds) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci if (milliseconds == 0) { 3108c2ecf20Sopenharmony_ci udelay(1); 3118c2ecf20Sopenharmony_ci } else { 3128c2ecf20Sopenharmony_ci mdelay(milliseconds); 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic void gdth_scsi_done(struct scsi_cmnd *scp) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); 3198c2ecf20Sopenharmony_ci int internal_command = cmndinfo->internal_command; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci TRACE2(("gdth_scsi_done()\n")); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci gdth_put_cmndinfo(cmndinfo); 3248c2ecf20Sopenharmony_ci scp->host_scribble = NULL; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (internal_command) 3278c2ecf20Sopenharmony_ci complete((struct completion *)scp->request); 3288c2ecf20Sopenharmony_ci else 3298c2ecf20Sopenharmony_ci scp->scsi_done(scp); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, 3338c2ecf20Sopenharmony_ci char *cmnd, int timeout, u32 *info) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci gdth_ha_str *ha = shost_priv(sdev->host); 3368c2ecf20Sopenharmony_ci struct scsi_cmnd *scp; 3378c2ecf20Sopenharmony_ci struct gdth_cmndinfo cmndinfo; 3388c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(wait); 3398c2ecf20Sopenharmony_ci int rval; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci scp = kzalloc(sizeof(*scp), GFP_KERNEL); 3428c2ecf20Sopenharmony_ci if (!scp) 3438c2ecf20Sopenharmony_ci return -ENOMEM; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci scp->sense_buffer = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); 3468c2ecf20Sopenharmony_ci if (!scp->sense_buffer) { 3478c2ecf20Sopenharmony_ci kfree(scp); 3488c2ecf20Sopenharmony_ci return -ENOMEM; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci scp->device = sdev; 3528c2ecf20Sopenharmony_ci memset(&cmndinfo, 0, sizeof(cmndinfo)); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* use request field to save the ptr. to completion struct. */ 3558c2ecf20Sopenharmony_ci scp->request = (struct request *)&wait; 3568c2ecf20Sopenharmony_ci scp->cmd_len = 12; 3578c2ecf20Sopenharmony_ci scp->cmnd = cmnd; 3588c2ecf20Sopenharmony_ci cmndinfo.priority = IOCTL_PRI; 3598c2ecf20Sopenharmony_ci cmndinfo.internal_cmd_str = gdtcmd; 3608c2ecf20Sopenharmony_ci cmndinfo.internal_command = 1; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci TRACE(("__gdth_execute() cmd 0x%x\n", scp->cmnd[0])); 3638c2ecf20Sopenharmony_ci __gdth_queuecommand(ha, scp, &cmndinfo); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci wait_for_completion(&wait); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci rval = cmndinfo.status; 3688c2ecf20Sopenharmony_ci if (info) 3698c2ecf20Sopenharmony_ci *info = cmndinfo.info; 3708c2ecf20Sopenharmony_ci kfree(scp->sense_buffer); 3718c2ecf20Sopenharmony_ci kfree(scp); 3728c2ecf20Sopenharmony_ci return rval; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ciint gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd, 3768c2ecf20Sopenharmony_ci int timeout, u32 *info) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct scsi_device *sdev = scsi_get_host_dev(shost); 3798c2ecf20Sopenharmony_ci int rval = __gdth_execute(sdev, gdtcmd, cmnd, timeout, info); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci scsi_free_host_dev(sdev); 3828c2ecf20Sopenharmony_ci return rval; 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci *cyls = size /HEADS/SECS; 3888c2ecf20Sopenharmony_ci if (*cyls <= MAXCYLS) { 3898c2ecf20Sopenharmony_ci *heads = HEADS; 3908c2ecf20Sopenharmony_ci *secs = SECS; 3918c2ecf20Sopenharmony_ci } else { /* too high for 64*32 */ 3928c2ecf20Sopenharmony_ci *cyls = size /MEDHEADS/MEDSECS; 3938c2ecf20Sopenharmony_ci if (*cyls <= MAXCYLS) { 3948c2ecf20Sopenharmony_ci *heads = MEDHEADS; 3958c2ecf20Sopenharmony_ci *secs = MEDSECS; 3968c2ecf20Sopenharmony_ci } else { /* too high for 127*63 */ 3978c2ecf20Sopenharmony_ci *cyls = size /BIGHEADS/BIGSECS; 3988c2ecf20Sopenharmony_ci *heads = BIGHEADS; 3998c2ecf20Sopenharmony_ci *secs = BIGSECS; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic bool gdth_search_vortex(u16 device) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci if (device <= PCI_DEVICE_ID_VORTEX_GDT6555) 4078c2ecf20Sopenharmony_ci return true; 4088c2ecf20Sopenharmony_ci if (device >= PCI_DEVICE_ID_VORTEX_GDT6x17RP && 4098c2ecf20Sopenharmony_ci device <= PCI_DEVICE_ID_VORTEX_GDTMAXRP) 4108c2ecf20Sopenharmony_ci return true; 4118c2ecf20Sopenharmony_ci if (device == PCI_DEVICE_ID_VORTEX_GDTNEWRX || 4128c2ecf20Sopenharmony_ci device == PCI_DEVICE_ID_VORTEX_GDTNEWRX2) 4138c2ecf20Sopenharmony_ci return true; 4148c2ecf20Sopenharmony_ci return false; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out); 4188c2ecf20Sopenharmony_cistatic int gdth_pci_init_one(struct pci_dev *pdev, 4198c2ecf20Sopenharmony_ci const struct pci_device_id *ent); 4208c2ecf20Sopenharmony_cistatic void gdth_pci_remove_one(struct pci_dev *pdev); 4218c2ecf20Sopenharmony_cistatic void gdth_remove_one(gdth_ha_str *ha); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/* Vortex only makes RAID controllers. 4248c2ecf20Sopenharmony_ci * We do not really want to specify all 550 ids here, so wildcard match. 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_cistatic const struct pci_device_id gdthtable[] = { 4278c2ecf20Sopenharmony_ci { PCI_VDEVICE(VORTEX, PCI_ANY_ID) }, 4288c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SRC) }, 4298c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SRC_XSCALE) }, 4308c2ecf20Sopenharmony_ci { } /* terminate list */ 4318c2ecf20Sopenharmony_ci}; 4328c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, gdthtable); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic struct pci_driver gdth_pci_driver = { 4358c2ecf20Sopenharmony_ci .name = "gdth", 4368c2ecf20Sopenharmony_ci .id_table = gdthtable, 4378c2ecf20Sopenharmony_ci .probe = gdth_pci_init_one, 4388c2ecf20Sopenharmony_ci .remove = gdth_pci_remove_one, 4398c2ecf20Sopenharmony_ci}; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic void gdth_pci_remove_one(struct pci_dev *pdev) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci gdth_ha_str *ha = pci_get_drvdata(pdev); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci list_del(&ha->list); 4468c2ecf20Sopenharmony_ci gdth_remove_one(ha); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci pci_disable_device(pdev); 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int gdth_pci_init_one(struct pci_dev *pdev, 4528c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci u16 vendor = pdev->vendor; 4558c2ecf20Sopenharmony_ci u16 device = pdev->device; 4568c2ecf20Sopenharmony_ci unsigned long base0, base1, base2; 4578c2ecf20Sopenharmony_ci int rc; 4588c2ecf20Sopenharmony_ci gdth_pci_str gdth_pcistr; 4598c2ecf20Sopenharmony_ci gdth_ha_str *ha = NULL; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci TRACE(("gdth_search_dev() cnt %d vendor %x device %x\n", 4628c2ecf20Sopenharmony_ci gdth_ctr_count, vendor, device)); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci memset(&gdth_pcistr, 0, sizeof(gdth_pcistr)); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (vendor == PCI_VENDOR_ID_VORTEX && !gdth_search_vortex(device)) 4678c2ecf20Sopenharmony_ci return -ENODEV; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci rc = pci_enable_device(pdev); 4708c2ecf20Sopenharmony_ci if (rc) 4718c2ecf20Sopenharmony_ci return rc; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (gdth_ctr_count >= MAXHA) 4748c2ecf20Sopenharmony_ci return -EBUSY; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* GDT PCI controller found, resources are already in pdev */ 4778c2ecf20Sopenharmony_ci gdth_pcistr.pdev = pdev; 4788c2ecf20Sopenharmony_ci base0 = pci_resource_flags(pdev, 0); 4798c2ecf20Sopenharmony_ci base1 = pci_resource_flags(pdev, 1); 4808c2ecf20Sopenharmony_ci base2 = pci_resource_flags(pdev, 2); 4818c2ecf20Sopenharmony_ci if (device <= PCI_DEVICE_ID_VORTEX_GDT6000B || /* GDT6000/B */ 4828c2ecf20Sopenharmony_ci device >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) { /* MPR */ 4838c2ecf20Sopenharmony_ci if (!(base0 & IORESOURCE_MEM)) 4848c2ecf20Sopenharmony_ci return -ENODEV; 4858c2ecf20Sopenharmony_ci gdth_pcistr.dpmem = pci_resource_start(pdev, 0); 4868c2ecf20Sopenharmony_ci } else { /* GDT6110, GDT6120, .. */ 4878c2ecf20Sopenharmony_ci if (!(base0 & IORESOURCE_MEM) || 4888c2ecf20Sopenharmony_ci !(base2 & IORESOURCE_MEM) || 4898c2ecf20Sopenharmony_ci !(base1 & IORESOURCE_IO)) 4908c2ecf20Sopenharmony_ci return -ENODEV; 4918c2ecf20Sopenharmony_ci gdth_pcistr.dpmem = pci_resource_start(pdev, 2); 4928c2ecf20Sopenharmony_ci gdth_pcistr.io = pci_resource_start(pdev, 1); 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n", 4958c2ecf20Sopenharmony_ci gdth_pcistr.pdev->bus->number, 4968c2ecf20Sopenharmony_ci PCI_SLOT(gdth_pcistr.pdev->devfn), 4978c2ecf20Sopenharmony_ci gdth_pcistr.irq, 4988c2ecf20Sopenharmony_ci gdth_pcistr.dpmem)); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci rc = gdth_pci_probe_one(&gdth_pcistr, &ha); 5018c2ecf20Sopenharmony_ci if (rc) 5028c2ecf20Sopenharmony_ci return rc; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return 0; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic int gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, 5088c2ecf20Sopenharmony_ci gdth_ha_str *ha) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci register gdt6_dpram_str __iomem *dp6_ptr; 5118c2ecf20Sopenharmony_ci register gdt6c_dpram_str __iomem *dp6c_ptr; 5128c2ecf20Sopenharmony_ci register gdt6m_dpram_str __iomem *dp6m_ptr; 5138c2ecf20Sopenharmony_ci u32 retries; 5148c2ecf20Sopenharmony_ci u8 prot_ver; 5158c2ecf20Sopenharmony_ci u16 command; 5168c2ecf20Sopenharmony_ci int i, found = FALSE; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci TRACE(("gdth_init_pci()\n")); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (pdev->vendor == PCI_VENDOR_ID_INTEL) 5218c2ecf20Sopenharmony_ci ha->oem_id = OEM_ID_INTEL; 5228c2ecf20Sopenharmony_ci else 5238c2ecf20Sopenharmony_ci ha->oem_id = OEM_ID_ICP; 5248c2ecf20Sopenharmony_ci ha->brd_phys = (pdev->bus->number << 8) | (pdev->devfn & 0xf8); 5258c2ecf20Sopenharmony_ci ha->stype = (u32)pdev->device; 5268c2ecf20Sopenharmony_ci ha->irq = pdev->irq; 5278c2ecf20Sopenharmony_ci ha->pdev = pdev; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (ha->pdev->device <= PCI_DEVICE_ID_VORTEX_GDT6000B) { /* GDT6000/B */ 5308c2ecf20Sopenharmony_ci TRACE2(("init_pci() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq)); 5318c2ecf20Sopenharmony_ci ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6_dpram_str)); 5328c2ecf20Sopenharmony_ci if (ha->brd == NULL) { 5338c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); 5348c2ecf20Sopenharmony_ci return 0; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci /* check and reset interface area */ 5378c2ecf20Sopenharmony_ci dp6_ptr = ha->brd; 5388c2ecf20Sopenharmony_ci writel(DPMEM_MAGIC, &dp6_ptr->u); 5398c2ecf20Sopenharmony_ci if (readl(&dp6_ptr->u) != DPMEM_MAGIC) { 5408c2ecf20Sopenharmony_ci printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 5418c2ecf20Sopenharmony_ci pcistr->dpmem); 5428c2ecf20Sopenharmony_ci found = FALSE; 5438c2ecf20Sopenharmony_ci for (i = 0xC8000; i < 0xE8000; i += 0x4000) { 5448c2ecf20Sopenharmony_ci iounmap(ha->brd); 5458c2ecf20Sopenharmony_ci ha->brd = ioremap(i, sizeof(u16)); 5468c2ecf20Sopenharmony_ci if (ha->brd == NULL) { 5478c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); 5488c2ecf20Sopenharmony_ci return 0; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci if (readw(ha->brd) != 0xffff) { 5518c2ecf20Sopenharmony_ci TRACE2(("init_pci_old() address 0x%x busy\n", i)); 5528c2ecf20Sopenharmony_ci continue; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci iounmap(ha->brd); 5558c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, i); 5568c2ecf20Sopenharmony_ci ha->brd = ioremap(i, sizeof(gdt6_dpram_str)); 5578c2ecf20Sopenharmony_ci if (ha->brd == NULL) { 5588c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); 5598c2ecf20Sopenharmony_ci return 0; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci dp6_ptr = ha->brd; 5628c2ecf20Sopenharmony_ci writel(DPMEM_MAGIC, &dp6_ptr->u); 5638c2ecf20Sopenharmony_ci if (readl(&dp6_ptr->u) == DPMEM_MAGIC) { 5648c2ecf20Sopenharmony_ci printk("GDT-PCI: Use free address at 0x%x\n", i); 5658c2ecf20Sopenharmony_ci found = TRUE; 5668c2ecf20Sopenharmony_ci break; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci if (!found) { 5708c2ecf20Sopenharmony_ci printk("GDT-PCI: No free address found!\n"); 5718c2ecf20Sopenharmony_ci iounmap(ha->brd); 5728c2ecf20Sopenharmony_ci return 0; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci memset_io(&dp6_ptr->u, 0, sizeof(dp6_ptr->u)); 5768c2ecf20Sopenharmony_ci if (readl(&dp6_ptr->u) != 0) { 5778c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DPMEM write error)\n"); 5788c2ecf20Sopenharmony_ci iounmap(ha->brd); 5798c2ecf20Sopenharmony_ci return 0; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* disable board interrupts, deinit services */ 5838c2ecf20Sopenharmony_ci writeb(0xff, &dp6_ptr->io.irqdel); 5848c2ecf20Sopenharmony_ci writeb(0x00, &dp6_ptr->io.irqen); 5858c2ecf20Sopenharmony_ci writeb(0x00, &dp6_ptr->u.ic.S_Status); 5868c2ecf20Sopenharmony_ci writeb(0x00, &dp6_ptr->u.ic.Cmd_Index); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]); 5898c2ecf20Sopenharmony_ci writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx); 5908c2ecf20Sopenharmony_ci writeb(0, &dp6_ptr->io.event); 5918c2ecf20Sopenharmony_ci retries = INIT_RETRIES; 5928c2ecf20Sopenharmony_ci gdth_delay(20); 5938c2ecf20Sopenharmony_ci while (readb(&dp6_ptr->u.ic.S_Status) != 0xff) { 5948c2ecf20Sopenharmony_ci if (--retries == 0) { 5958c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DEINIT failed)\n"); 5968c2ecf20Sopenharmony_ci iounmap(ha->brd); 5978c2ecf20Sopenharmony_ci return 0; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci gdth_delay(1); 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci prot_ver = (u8)readl(&dp6_ptr->u.ic.S_Info[0]); 6028c2ecf20Sopenharmony_ci writeb(0, &dp6_ptr->u.ic.S_Status); 6038c2ecf20Sopenharmony_ci writeb(0xff, &dp6_ptr->io.irqdel); 6048c2ecf20Sopenharmony_ci if (prot_ver != PROTOCOL_VERSION) { 6058c2ecf20Sopenharmony_ci printk("GDT-PCI: Illegal protocol version\n"); 6068c2ecf20Sopenharmony_ci iounmap(ha->brd); 6078c2ecf20Sopenharmony_ci return 0; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci ha->type = GDT_PCI; 6118c2ecf20Sopenharmony_ci ha->ic_all_size = sizeof(dp6_ptr->u); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci /* special command to controller BIOS */ 6148c2ecf20Sopenharmony_ci writel(0x00, &dp6_ptr->u.ic.S_Info[0]); 6158c2ecf20Sopenharmony_ci writel(0x00, &dp6_ptr->u.ic.S_Info[1]); 6168c2ecf20Sopenharmony_ci writel(0x00, &dp6_ptr->u.ic.S_Info[2]); 6178c2ecf20Sopenharmony_ci writel(0x00, &dp6_ptr->u.ic.S_Info[3]); 6188c2ecf20Sopenharmony_ci writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx); 6198c2ecf20Sopenharmony_ci writeb(0, &dp6_ptr->io.event); 6208c2ecf20Sopenharmony_ci retries = INIT_RETRIES; 6218c2ecf20Sopenharmony_ci gdth_delay(20); 6228c2ecf20Sopenharmony_ci while (readb(&dp6_ptr->u.ic.S_Status) != 0xfe) { 6238c2ecf20Sopenharmony_ci if (--retries == 0) { 6248c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error\n"); 6258c2ecf20Sopenharmony_ci iounmap(ha->brd); 6268c2ecf20Sopenharmony_ci return 0; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci gdth_delay(1); 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci writeb(0, &dp6_ptr->u.ic.S_Status); 6318c2ecf20Sopenharmony_ci writeb(0xff, &dp6_ptr->io.irqdel); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci ha->dma64_support = 0; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci } else if (ha->pdev->device <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, ... */ 6368c2ecf20Sopenharmony_ci ha->plx = (gdt6c_plx_regs *)pcistr->io; 6378c2ecf20Sopenharmony_ci TRACE2(("init_pci_new() dpmem %lx irq %d\n", 6388c2ecf20Sopenharmony_ci pcistr->dpmem,ha->irq)); 6398c2ecf20Sopenharmony_ci ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6c_dpram_str)); 6408c2ecf20Sopenharmony_ci if (ha->brd == NULL) { 6418c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); 6428c2ecf20Sopenharmony_ci iounmap(ha->brd); 6438c2ecf20Sopenharmony_ci return 0; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci /* check and reset interface area */ 6468c2ecf20Sopenharmony_ci dp6c_ptr = ha->brd; 6478c2ecf20Sopenharmony_ci writel(DPMEM_MAGIC, &dp6c_ptr->u); 6488c2ecf20Sopenharmony_ci if (readl(&dp6c_ptr->u) != DPMEM_MAGIC) { 6498c2ecf20Sopenharmony_ci printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 6508c2ecf20Sopenharmony_ci pcistr->dpmem); 6518c2ecf20Sopenharmony_ci found = FALSE; 6528c2ecf20Sopenharmony_ci for (i = 0xC8000; i < 0xE8000; i += 0x4000) { 6538c2ecf20Sopenharmony_ci iounmap(ha->brd); 6548c2ecf20Sopenharmony_ci ha->brd = ioremap(i, sizeof(u16)); 6558c2ecf20Sopenharmony_ci if (ha->brd == NULL) { 6568c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); 6578c2ecf20Sopenharmony_ci return 0; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci if (readw(ha->brd) != 0xffff) { 6608c2ecf20Sopenharmony_ci TRACE2(("init_pci_plx() address 0x%x busy\n", i)); 6618c2ecf20Sopenharmony_ci continue; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci iounmap(ha->brd); 6648c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, PCI_BASE_ADDRESS_2, i); 6658c2ecf20Sopenharmony_ci ha->brd = ioremap(i, sizeof(gdt6c_dpram_str)); 6668c2ecf20Sopenharmony_ci if (ha->brd == NULL) { 6678c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); 6688c2ecf20Sopenharmony_ci return 0; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci dp6c_ptr = ha->brd; 6718c2ecf20Sopenharmony_ci writel(DPMEM_MAGIC, &dp6c_ptr->u); 6728c2ecf20Sopenharmony_ci if (readl(&dp6c_ptr->u) == DPMEM_MAGIC) { 6738c2ecf20Sopenharmony_ci printk("GDT-PCI: Use free address at 0x%x\n", i); 6748c2ecf20Sopenharmony_ci found = TRUE; 6758c2ecf20Sopenharmony_ci break; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci if (!found) { 6798c2ecf20Sopenharmony_ci printk("GDT-PCI: No free address found!\n"); 6808c2ecf20Sopenharmony_ci iounmap(ha->brd); 6818c2ecf20Sopenharmony_ci return 0; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci memset_io(&dp6c_ptr->u, 0, sizeof(dp6c_ptr->u)); 6858c2ecf20Sopenharmony_ci if (readl(&dp6c_ptr->u) != 0) { 6868c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DPMEM write error)\n"); 6878c2ecf20Sopenharmony_ci iounmap(ha->brd); 6888c2ecf20Sopenharmony_ci return 0; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* disable board interrupts, deinit services */ 6928c2ecf20Sopenharmony_ci outb(0x00,PTR2USHORT(&ha->plx->control1)); 6938c2ecf20Sopenharmony_ci outb(0xff,PTR2USHORT(&ha->plx->edoor_reg)); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci writeb(0x00, &dp6c_ptr->u.ic.S_Status); 6968c2ecf20Sopenharmony_ci writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]); 6998c2ecf20Sopenharmony_ci writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci outb(1,PTR2USHORT(&ha->plx->ldoor_reg)); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci retries = INIT_RETRIES; 7048c2ecf20Sopenharmony_ci gdth_delay(20); 7058c2ecf20Sopenharmony_ci while (readb(&dp6c_ptr->u.ic.S_Status) != 0xff) { 7068c2ecf20Sopenharmony_ci if (--retries == 0) { 7078c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DEINIT failed)\n"); 7088c2ecf20Sopenharmony_ci iounmap(ha->brd); 7098c2ecf20Sopenharmony_ci return 0; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci gdth_delay(1); 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci prot_ver = (u8)readl(&dp6c_ptr->u.ic.S_Info[0]); 7148c2ecf20Sopenharmony_ci writeb(0, &dp6c_ptr->u.ic.Status); 7158c2ecf20Sopenharmony_ci if (prot_ver != PROTOCOL_VERSION) { 7168c2ecf20Sopenharmony_ci printk("GDT-PCI: Illegal protocol version\n"); 7178c2ecf20Sopenharmony_ci iounmap(ha->brd); 7188c2ecf20Sopenharmony_ci return 0; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci ha->type = GDT_PCINEW; 7228c2ecf20Sopenharmony_ci ha->ic_all_size = sizeof(dp6c_ptr->u); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* special command to controller BIOS */ 7258c2ecf20Sopenharmony_ci writel(0x00, &dp6c_ptr->u.ic.S_Info[0]); 7268c2ecf20Sopenharmony_ci writel(0x00, &dp6c_ptr->u.ic.S_Info[1]); 7278c2ecf20Sopenharmony_ci writel(0x00, &dp6c_ptr->u.ic.S_Info[2]); 7288c2ecf20Sopenharmony_ci writel(0x00, &dp6c_ptr->u.ic.S_Info[3]); 7298c2ecf20Sopenharmony_ci writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci outb(1,PTR2USHORT(&ha->plx->ldoor_reg)); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci retries = INIT_RETRIES; 7348c2ecf20Sopenharmony_ci gdth_delay(20); 7358c2ecf20Sopenharmony_ci while (readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) { 7368c2ecf20Sopenharmony_ci if (--retries == 0) { 7378c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error\n"); 7388c2ecf20Sopenharmony_ci iounmap(ha->brd); 7398c2ecf20Sopenharmony_ci return 0; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci gdth_delay(1); 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci writeb(0, &dp6c_ptr->u.ic.S_Status); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci ha->dma64_support = 0; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci } else { /* MPR */ 7488c2ecf20Sopenharmony_ci TRACE2(("init_pci_mpr() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq)); 7498c2ecf20Sopenharmony_ci ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6m_dpram_str)); 7508c2ecf20Sopenharmony_ci if (ha->brd == NULL) { 7518c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); 7528c2ecf20Sopenharmony_ci return 0; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* manipulate config. space to enable DPMEM, start RP controller */ 7568c2ecf20Sopenharmony_ci pci_read_config_word(pdev, PCI_COMMAND, &command); 7578c2ecf20Sopenharmony_ci command |= 6; 7588c2ecf20Sopenharmony_ci pci_write_config_word(pdev, PCI_COMMAND, command); 7598c2ecf20Sopenharmony_ci gdth_delay(1); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci dp6m_ptr = ha->brd; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci /* Ensure that it is safe to access the non HW portions of DPMEM. 7648c2ecf20Sopenharmony_ci * Aditional check needed for Xscale based RAID controllers */ 7658c2ecf20Sopenharmony_ci while( ((int)readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 ) 7668c2ecf20Sopenharmony_ci gdth_delay(1); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* check and reset interface area */ 7698c2ecf20Sopenharmony_ci writel(DPMEM_MAGIC, &dp6m_ptr->u); 7708c2ecf20Sopenharmony_ci if (readl(&dp6m_ptr->u) != DPMEM_MAGIC) { 7718c2ecf20Sopenharmony_ci printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 7728c2ecf20Sopenharmony_ci pcistr->dpmem); 7738c2ecf20Sopenharmony_ci found = FALSE; 7748c2ecf20Sopenharmony_ci for (i = 0xC8000; i < 0xE8000; i += 0x4000) { 7758c2ecf20Sopenharmony_ci iounmap(ha->brd); 7768c2ecf20Sopenharmony_ci ha->brd = ioremap(i, sizeof(u16)); 7778c2ecf20Sopenharmony_ci if (ha->brd == NULL) { 7788c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); 7798c2ecf20Sopenharmony_ci return 0; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci if (readw(ha->brd) != 0xffff) { 7828c2ecf20Sopenharmony_ci TRACE2(("init_pci_mpr() address 0x%x busy\n", i)); 7838c2ecf20Sopenharmony_ci continue; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci iounmap(ha->brd); 7868c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, i); 7878c2ecf20Sopenharmony_ci ha->brd = ioremap(i, sizeof(gdt6m_dpram_str)); 7888c2ecf20Sopenharmony_ci if (ha->brd == NULL) { 7898c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); 7908c2ecf20Sopenharmony_ci return 0; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci dp6m_ptr = ha->brd; 7938c2ecf20Sopenharmony_ci writel(DPMEM_MAGIC, &dp6m_ptr->u); 7948c2ecf20Sopenharmony_ci if (readl(&dp6m_ptr->u) == DPMEM_MAGIC) { 7958c2ecf20Sopenharmony_ci printk("GDT-PCI: Use free address at 0x%x\n", i); 7968c2ecf20Sopenharmony_ci found = TRUE; 7978c2ecf20Sopenharmony_ci break; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci if (!found) { 8018c2ecf20Sopenharmony_ci printk("GDT-PCI: No free address found!\n"); 8028c2ecf20Sopenharmony_ci iounmap(ha->brd); 8038c2ecf20Sopenharmony_ci return 0; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci memset_io(&dp6m_ptr->u, 0, sizeof(dp6m_ptr->u)); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* disable board interrupts, deinit services */ 8098c2ecf20Sopenharmony_ci writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) | 4, 8108c2ecf20Sopenharmony_ci &dp6m_ptr->i960r.edoor_en_reg); 8118c2ecf20Sopenharmony_ci writeb(0xff, &dp6m_ptr->i960r.edoor_reg); 8128c2ecf20Sopenharmony_ci writeb(0x00, &dp6m_ptr->u.ic.S_Status); 8138c2ecf20Sopenharmony_ci writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]); 8168c2ecf20Sopenharmony_ci writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx); 8178c2ecf20Sopenharmony_ci writeb(1, &dp6m_ptr->i960r.ldoor_reg); 8188c2ecf20Sopenharmony_ci retries = INIT_RETRIES; 8198c2ecf20Sopenharmony_ci gdth_delay(20); 8208c2ecf20Sopenharmony_ci while (readb(&dp6m_ptr->u.ic.S_Status) != 0xff) { 8218c2ecf20Sopenharmony_ci if (--retries == 0) { 8228c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DEINIT failed)\n"); 8238c2ecf20Sopenharmony_ci iounmap(ha->brd); 8248c2ecf20Sopenharmony_ci return 0; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci gdth_delay(1); 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci prot_ver = (u8)readl(&dp6m_ptr->u.ic.S_Info[0]); 8298c2ecf20Sopenharmony_ci writeb(0, &dp6m_ptr->u.ic.S_Status); 8308c2ecf20Sopenharmony_ci if (prot_ver != PROTOCOL_VERSION) { 8318c2ecf20Sopenharmony_ci printk("GDT-PCI: Illegal protocol version\n"); 8328c2ecf20Sopenharmony_ci iounmap(ha->brd); 8338c2ecf20Sopenharmony_ci return 0; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci ha->type = GDT_PCIMPR; 8378c2ecf20Sopenharmony_ci ha->ic_all_size = sizeof(dp6m_ptr->u); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci /* special command to controller BIOS */ 8408c2ecf20Sopenharmony_ci writel(0x00, &dp6m_ptr->u.ic.S_Info[0]); 8418c2ecf20Sopenharmony_ci writel(0x00, &dp6m_ptr->u.ic.S_Info[1]); 8428c2ecf20Sopenharmony_ci writel(0x00, &dp6m_ptr->u.ic.S_Info[2]); 8438c2ecf20Sopenharmony_ci writel(0x00, &dp6m_ptr->u.ic.S_Info[3]); 8448c2ecf20Sopenharmony_ci writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx); 8458c2ecf20Sopenharmony_ci writeb(1, &dp6m_ptr->i960r.ldoor_reg); 8468c2ecf20Sopenharmony_ci retries = INIT_RETRIES; 8478c2ecf20Sopenharmony_ci gdth_delay(20); 8488c2ecf20Sopenharmony_ci while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) { 8498c2ecf20Sopenharmony_ci if (--retries == 0) { 8508c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error\n"); 8518c2ecf20Sopenharmony_ci iounmap(ha->brd); 8528c2ecf20Sopenharmony_ci return 0; 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci gdth_delay(1); 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci writeb(0, &dp6m_ptr->u.ic.S_Status); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci /* read FW version to detect 64-bit DMA support */ 8598c2ecf20Sopenharmony_ci writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx); 8608c2ecf20Sopenharmony_ci writeb(1, &dp6m_ptr->i960r.ldoor_reg); 8618c2ecf20Sopenharmony_ci retries = INIT_RETRIES; 8628c2ecf20Sopenharmony_ci gdth_delay(20); 8638c2ecf20Sopenharmony_ci while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) { 8648c2ecf20Sopenharmony_ci if (--retries == 0) { 8658c2ecf20Sopenharmony_ci printk("GDT-PCI: Initialization error (DEINIT failed)\n"); 8668c2ecf20Sopenharmony_ci iounmap(ha->brd); 8678c2ecf20Sopenharmony_ci return 0; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci gdth_delay(1); 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci prot_ver = (u8)(readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16); 8728c2ecf20Sopenharmony_ci writeb(0, &dp6m_ptr->u.ic.S_Status); 8738c2ecf20Sopenharmony_ci if (prot_ver < 0x2b) /* FW < x.43: no 64-bit DMA support */ 8748c2ecf20Sopenharmony_ci ha->dma64_support = 0; 8758c2ecf20Sopenharmony_ci else 8768c2ecf20Sopenharmony_ci ha->dma64_support = 1; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci return 1; 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci/* controller protocol functions */ 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic void gdth_enable_int(gdth_ha_str *ha) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci unsigned long flags; 8878c2ecf20Sopenharmony_ci gdt6_dpram_str __iomem *dp6_ptr; 8888c2ecf20Sopenharmony_ci gdt6m_dpram_str __iomem *dp6m_ptr; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci TRACE(("gdth_enable_int() hanum %d\n",ha->hanum)); 8918c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if (ha->type == GDT_PCI) { 8948c2ecf20Sopenharmony_ci dp6_ptr = ha->brd; 8958c2ecf20Sopenharmony_ci writeb(1, &dp6_ptr->io.irqdel); 8968c2ecf20Sopenharmony_ci writeb(0, &dp6_ptr->u.ic.Cmd_Index); 8978c2ecf20Sopenharmony_ci writeb(1, &dp6_ptr->io.irqen); 8988c2ecf20Sopenharmony_ci } else if (ha->type == GDT_PCINEW) { 8998c2ecf20Sopenharmony_ci outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); 9008c2ecf20Sopenharmony_ci outb(0x03, PTR2USHORT(&ha->plx->control1)); 9018c2ecf20Sopenharmony_ci } else if (ha->type == GDT_PCIMPR) { 9028c2ecf20Sopenharmony_ci dp6m_ptr = ha->brd; 9038c2ecf20Sopenharmony_ci writeb(0xff, &dp6m_ptr->i960r.edoor_reg); 9048c2ecf20Sopenharmony_ci writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4, 9058c2ecf20Sopenharmony_ci &dp6m_ptr->i960r.edoor_en_reg); 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci/* return IStatus if interrupt was from this card else 0 */ 9118c2ecf20Sopenharmony_cistatic u8 gdth_get_status(gdth_ha_str *ha) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci u8 IStatus = 0; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci TRACE(("gdth_get_status() irq %d ctr_count %d\n", ha->irq, gdth_ctr_count)); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci if (ha->type == GDT_PCI) 9188c2ecf20Sopenharmony_ci IStatus = 9198c2ecf20Sopenharmony_ci readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); 9208c2ecf20Sopenharmony_ci else if (ha->type == GDT_PCINEW) 9218c2ecf20Sopenharmony_ci IStatus = inb(PTR2USHORT(&ha->plx->edoor_reg)); 9228c2ecf20Sopenharmony_ci else if (ha->type == GDT_PCIMPR) 9238c2ecf20Sopenharmony_ci IStatus = 9248c2ecf20Sopenharmony_ci readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci return IStatus; 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic int gdth_test_busy(gdth_ha_str *ha) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci register int gdtsema0 = 0; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci TRACE(("gdth_test_busy() hanum %d\n", ha->hanum)); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (ha->type == GDT_PCI) 9368c2ecf20Sopenharmony_ci gdtsema0 = (int)readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); 9378c2ecf20Sopenharmony_ci else if (ha->type == GDT_PCINEW) 9388c2ecf20Sopenharmony_ci gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg)); 9398c2ecf20Sopenharmony_ci else if (ha->type == GDT_PCIMPR) 9408c2ecf20Sopenharmony_ci gdtsema0 = 9418c2ecf20Sopenharmony_ci (int)readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci return (gdtsema0 & 1); 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic int gdth_get_cmd_index(gdth_ha_str *ha) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci int i; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci TRACE(("gdth_get_cmd_index() hanum %d\n", ha->hanum)); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci for (i=0; i<GDTH_MAXCMDS; ++i) { 9548c2ecf20Sopenharmony_ci if (ha->cmd_tab[i].cmnd == UNUSED_CMND) { 9558c2ecf20Sopenharmony_ci ha->cmd_tab[i].cmnd = ha->pccb->RequestBuffer; 9568c2ecf20Sopenharmony_ci ha->cmd_tab[i].service = ha->pccb->Service; 9578c2ecf20Sopenharmony_ci ha->pccb->CommandIndex = (u32)i+2; 9588c2ecf20Sopenharmony_ci return (i+2); 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci return 0; 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_cistatic void gdth_set_sema0(gdth_ha_str *ha) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci TRACE(("gdth_set_sema0() hanum %d\n", ha->hanum)); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (ha->type == GDT_PCI) { 9708c2ecf20Sopenharmony_ci writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); 9718c2ecf20Sopenharmony_ci } else if (ha->type == GDT_PCINEW) { 9728c2ecf20Sopenharmony_ci outb(1, PTR2USHORT(&ha->plx->sema0_reg)); 9738c2ecf20Sopenharmony_ci } else if (ha->type == GDT_PCIMPR) { 9748c2ecf20Sopenharmony_ci writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg); 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cistatic void gdth_copy_command(gdth_ha_str *ha) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci register gdth_cmd_str *cmd_ptr; 9828c2ecf20Sopenharmony_ci register gdt6m_dpram_str __iomem *dp6m_ptr; 9838c2ecf20Sopenharmony_ci register gdt6c_dpram_str __iomem *dp6c_ptr; 9848c2ecf20Sopenharmony_ci gdt6_dpram_str __iomem *dp6_ptr; 9858c2ecf20Sopenharmony_ci u16 cp_count,dp_offset,cmd_no; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci TRACE(("gdth_copy_command() hanum %d\n", ha->hanum)); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci cp_count = ha->cmd_len; 9908c2ecf20Sopenharmony_ci dp_offset= ha->cmd_offs_dpmem; 9918c2ecf20Sopenharmony_ci cmd_no = ha->cmd_cnt; 9928c2ecf20Sopenharmony_ci cmd_ptr = ha->pccb; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci ++ha->cmd_cnt; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci /* set cpcount dword aligned */ 9978c2ecf20Sopenharmony_ci if (cp_count & 3) 9988c2ecf20Sopenharmony_ci cp_count += (4 - (cp_count & 3)); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci ha->cmd_offs_dpmem += cp_count; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci /* set offset and service, copy command to DPMEM */ 10038c2ecf20Sopenharmony_ci if (ha->type == GDT_PCI) { 10048c2ecf20Sopenharmony_ci dp6_ptr = ha->brd; 10058c2ecf20Sopenharmony_ci writew(dp_offset + DPMEM_COMMAND_OFFSET, 10068c2ecf20Sopenharmony_ci &dp6_ptr->u.ic.comm_queue[cmd_no].offset); 10078c2ecf20Sopenharmony_ci writew((u16)cmd_ptr->Service, 10088c2ecf20Sopenharmony_ci &dp6_ptr->u.ic.comm_queue[cmd_no].serv_id); 10098c2ecf20Sopenharmony_ci memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); 10108c2ecf20Sopenharmony_ci } else if (ha->type == GDT_PCINEW) { 10118c2ecf20Sopenharmony_ci dp6c_ptr = ha->brd; 10128c2ecf20Sopenharmony_ci writew(dp_offset + DPMEM_COMMAND_OFFSET, 10138c2ecf20Sopenharmony_ci &dp6c_ptr->u.ic.comm_queue[cmd_no].offset); 10148c2ecf20Sopenharmony_ci writew((u16)cmd_ptr->Service, 10158c2ecf20Sopenharmony_ci &dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id); 10168c2ecf20Sopenharmony_ci memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); 10178c2ecf20Sopenharmony_ci } else if (ha->type == GDT_PCIMPR) { 10188c2ecf20Sopenharmony_ci dp6m_ptr = ha->brd; 10198c2ecf20Sopenharmony_ci writew(dp_offset + DPMEM_COMMAND_OFFSET, 10208c2ecf20Sopenharmony_ci &dp6m_ptr->u.ic.comm_queue[cmd_no].offset); 10218c2ecf20Sopenharmony_ci writew((u16)cmd_ptr->Service, 10228c2ecf20Sopenharmony_ci &dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id); 10238c2ecf20Sopenharmony_ci memcpy_toio(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_cistatic void gdth_release_event(gdth_ha_str *ha) 10298c2ecf20Sopenharmony_ci{ 10308c2ecf20Sopenharmony_ci TRACE(("gdth_release_event() hanum %d\n", ha->hanum)); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci#ifdef GDTH_STATISTICS 10338c2ecf20Sopenharmony_ci { 10348c2ecf20Sopenharmony_ci u32 i,j; 10358c2ecf20Sopenharmony_ci for (i=0,j=0; j<GDTH_MAXCMDS; ++j) { 10368c2ecf20Sopenharmony_ci if (ha->cmd_tab[j].cmnd != UNUSED_CMND) 10378c2ecf20Sopenharmony_ci ++i; 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci if (max_index < i) { 10408c2ecf20Sopenharmony_ci max_index = i; 10418c2ecf20Sopenharmony_ci TRACE3(("GDT: max_index = %d\n",(u16)i)); 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci#endif 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci if (ha->pccb->OpCode == GDT_INIT) 10478c2ecf20Sopenharmony_ci ha->pccb->Service |= 0x80; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (ha->type == GDT_PCI) { 10508c2ecf20Sopenharmony_ci writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event); 10518c2ecf20Sopenharmony_ci } else if (ha->type == GDT_PCINEW) { 10528c2ecf20Sopenharmony_ci outb(1, PTR2USHORT(&ha->plx->ldoor_reg)); 10538c2ecf20Sopenharmony_ci } else if (ha->type == GDT_PCIMPR) { 10548c2ecf20Sopenharmony_ci writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.ldoor_reg); 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_cistatic int gdth_wait(gdth_ha_str *ha, int index, u32 time) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci int answer_found = FALSE; 10618c2ecf20Sopenharmony_ci int wait_index = 0; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci TRACE(("gdth_wait() hanum %d index %d time %d\n", ha->hanum, index, time)); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (index == 0) 10668c2ecf20Sopenharmony_ci return 1; /* no wait required */ 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci do { 10698c2ecf20Sopenharmony_ci __gdth_interrupt(ha, true, &wait_index); 10708c2ecf20Sopenharmony_ci if (wait_index == index) { 10718c2ecf20Sopenharmony_ci answer_found = TRUE; 10728c2ecf20Sopenharmony_ci break; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci gdth_delay(1); 10758c2ecf20Sopenharmony_ci } while (--time); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci while (gdth_test_busy(ha)) 10788c2ecf20Sopenharmony_ci gdth_delay(0); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci return (answer_found); 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_cistatic int gdth_internal_cmd(gdth_ha_str *ha, u8 service, u16 opcode, 10858c2ecf20Sopenharmony_ci u32 p1, u64 p2, u64 p3) 10868c2ecf20Sopenharmony_ci{ 10878c2ecf20Sopenharmony_ci register gdth_cmd_str *cmd_ptr; 10888c2ecf20Sopenharmony_ci int retries,index; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci TRACE2(("gdth_internal_cmd() service %d opcode %d\n",service,opcode)); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci cmd_ptr = ha->pccb; 10938c2ecf20Sopenharmony_ci memset((char*)cmd_ptr,0,sizeof(gdth_cmd_str)); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci /* make command */ 10968c2ecf20Sopenharmony_ci for (retries = INIT_RETRIES;;) { 10978c2ecf20Sopenharmony_ci cmd_ptr->Service = service; 10988c2ecf20Sopenharmony_ci cmd_ptr->RequestBuffer = INTERNAL_CMND; 10998c2ecf20Sopenharmony_ci if (!(index=gdth_get_cmd_index(ha))) { 11008c2ecf20Sopenharmony_ci TRACE(("GDT: No free command index found\n")); 11018c2ecf20Sopenharmony_ci return 0; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci gdth_set_sema0(ha); 11048c2ecf20Sopenharmony_ci cmd_ptr->OpCode = opcode; 11058c2ecf20Sopenharmony_ci cmd_ptr->BoardNode = LOCALBOARD; 11068c2ecf20Sopenharmony_ci if (service == CACHESERVICE) { 11078c2ecf20Sopenharmony_ci if (opcode == GDT_IOCTL) { 11088c2ecf20Sopenharmony_ci cmd_ptr->u.ioctl.subfunc = p1; 11098c2ecf20Sopenharmony_ci cmd_ptr->u.ioctl.channel = (u32)p2; 11108c2ecf20Sopenharmony_ci cmd_ptr->u.ioctl.param_size = (u16)p3; 11118c2ecf20Sopenharmony_ci cmd_ptr->u.ioctl.p_param = ha->scratch_phys; 11128c2ecf20Sopenharmony_ci } else { 11138c2ecf20Sopenharmony_ci if (ha->cache_feat & GDT_64BIT) { 11148c2ecf20Sopenharmony_ci cmd_ptr->u.cache64.DeviceNo = (u16)p1; 11158c2ecf20Sopenharmony_ci cmd_ptr->u.cache64.BlockNo = p2; 11168c2ecf20Sopenharmony_ci } else { 11178c2ecf20Sopenharmony_ci cmd_ptr->u.cache.DeviceNo = (u16)p1; 11188c2ecf20Sopenharmony_ci cmd_ptr->u.cache.BlockNo = (u32)p2; 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci } else if (service == SCSIRAWSERVICE) { 11228c2ecf20Sopenharmony_ci if (ha->raw_feat & GDT_64BIT) { 11238c2ecf20Sopenharmony_ci cmd_ptr->u.raw64.direction = p1; 11248c2ecf20Sopenharmony_ci cmd_ptr->u.raw64.bus = (u8)p2; 11258c2ecf20Sopenharmony_ci cmd_ptr->u.raw64.target = (u8)p3; 11268c2ecf20Sopenharmony_ci cmd_ptr->u.raw64.lun = (u8)(p3 >> 8); 11278c2ecf20Sopenharmony_ci } else { 11288c2ecf20Sopenharmony_ci cmd_ptr->u.raw.direction = p1; 11298c2ecf20Sopenharmony_ci cmd_ptr->u.raw.bus = (u8)p2; 11308c2ecf20Sopenharmony_ci cmd_ptr->u.raw.target = (u8)p3; 11318c2ecf20Sopenharmony_ci cmd_ptr->u.raw.lun = (u8)(p3 >> 8); 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci } else if (service == SCREENSERVICE) { 11348c2ecf20Sopenharmony_ci if (opcode == GDT_REALTIME) { 11358c2ecf20Sopenharmony_ci *(u32 *)&cmd_ptr->u.screen.su.data[0] = p1; 11368c2ecf20Sopenharmony_ci *(u32 *)&cmd_ptr->u.screen.su.data[4] = (u32)p2; 11378c2ecf20Sopenharmony_ci *(u32 *)&cmd_ptr->u.screen.su.data[8] = (u32)p3; 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci ha->cmd_len = sizeof(gdth_cmd_str); 11418c2ecf20Sopenharmony_ci ha->cmd_offs_dpmem = 0; 11428c2ecf20Sopenharmony_ci ha->cmd_cnt = 0; 11438c2ecf20Sopenharmony_ci gdth_copy_command(ha); 11448c2ecf20Sopenharmony_ci gdth_release_event(ha); 11458c2ecf20Sopenharmony_ci gdth_delay(20); 11468c2ecf20Sopenharmony_ci if (!gdth_wait(ha, index, INIT_TIMEOUT)) { 11478c2ecf20Sopenharmony_ci printk("GDT: Initialization error (timeout service %d)\n",service); 11488c2ecf20Sopenharmony_ci return 0; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci if (ha->status != S_BSY || --retries == 0) 11518c2ecf20Sopenharmony_ci break; 11528c2ecf20Sopenharmony_ci gdth_delay(1); 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci return (ha->status != S_OK ? 0:1); 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci/* search for devices */ 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_cistatic int gdth_search_drives(gdth_ha_str *ha) 11628c2ecf20Sopenharmony_ci{ 11638c2ecf20Sopenharmony_ci u16 cdev_cnt, i; 11648c2ecf20Sopenharmony_ci int ok; 11658c2ecf20Sopenharmony_ci u32 bus_no, drv_cnt, drv_no, j; 11668c2ecf20Sopenharmony_ci gdth_getch_str *chn; 11678c2ecf20Sopenharmony_ci gdth_drlist_str *drl; 11688c2ecf20Sopenharmony_ci gdth_iochan_str *ioc; 11698c2ecf20Sopenharmony_ci gdth_raw_iochan_str *iocr; 11708c2ecf20Sopenharmony_ci gdth_arcdl_str *alst; 11718c2ecf20Sopenharmony_ci gdth_alist_str *alst2; 11728c2ecf20Sopenharmony_ci gdth_oem_str_ioctl *oemstr; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci TRACE(("gdth_search_drives() hanum %d\n", ha->hanum)); 11758c2ecf20Sopenharmony_ci ok = 0; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci /* initialize controller services, at first: screen service */ 11788c2ecf20Sopenharmony_ci ha->screen_feat = 0; 11798c2ecf20Sopenharmony_ci if (!force_dma32) { 11808c2ecf20Sopenharmony_ci ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_X_INIT_SCR, 0, 0, 0); 11818c2ecf20Sopenharmony_ci if (ok) 11828c2ecf20Sopenharmony_ci ha->screen_feat = GDT_64BIT; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC)) 11858c2ecf20Sopenharmony_ci ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_INIT, 0, 0, 0); 11868c2ecf20Sopenharmony_ci if (!ok) { 11878c2ecf20Sopenharmony_ci printk("GDT-HA %d: Initialization error screen service (code %d)\n", 11888c2ecf20Sopenharmony_ci ha->hanum, ha->status); 11898c2ecf20Sopenharmony_ci return 0; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n")); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci /* unfreeze all IOs */ 11948c2ecf20Sopenharmony_ci gdth_internal_cmd(ha, CACHESERVICE, GDT_UNFREEZE_IO, 0, 0, 0); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* initialize cache service */ 11978c2ecf20Sopenharmony_ci ha->cache_feat = 0; 11988c2ecf20Sopenharmony_ci if (!force_dma32) { 11998c2ecf20Sopenharmony_ci ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INIT_HOST, LINUX_OS, 12008c2ecf20Sopenharmony_ci 0, 0); 12018c2ecf20Sopenharmony_ci if (ok) 12028c2ecf20Sopenharmony_ci ha->cache_feat = GDT_64BIT; 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC)) 12058c2ecf20Sopenharmony_ci ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_INIT, LINUX_OS, 0, 0); 12068c2ecf20Sopenharmony_ci if (!ok) { 12078c2ecf20Sopenharmony_ci printk("GDT-HA %d: Initialization error cache service (code %d)\n", 12088c2ecf20Sopenharmony_ci ha->hanum, ha->status); 12098c2ecf20Sopenharmony_ci return 0; 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n")); 12128c2ecf20Sopenharmony_ci cdev_cnt = (u16)ha->info; 12138c2ecf20Sopenharmony_ci ha->fw_vers = ha->service; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci /* detect number of buses - try new IOCTL */ 12168c2ecf20Sopenharmony_ci iocr = (gdth_raw_iochan_str *)ha->pscratch; 12178c2ecf20Sopenharmony_ci iocr->hdr.version = 0xffffffff; 12188c2ecf20Sopenharmony_ci iocr->hdr.list_entries = MAXBUS; 12198c2ecf20Sopenharmony_ci iocr->hdr.first_chan = 0; 12208c2ecf20Sopenharmony_ci iocr->hdr.last_chan = MAXBUS-1; 12218c2ecf20Sopenharmony_ci iocr->hdr.list_offset = GDTOFFSOF(gdth_raw_iochan_str, list[0]); 12228c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, IOCHAN_RAW_DESC, 12238c2ecf20Sopenharmony_ci INVALID_CHANNEL,sizeof(gdth_raw_iochan_str))) { 12248c2ecf20Sopenharmony_ci TRACE2(("IOCHAN_RAW_DESC supported!\n")); 12258c2ecf20Sopenharmony_ci ha->bus_cnt = iocr->hdr.chan_count; 12268c2ecf20Sopenharmony_ci for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { 12278c2ecf20Sopenharmony_ci if (iocr->list[bus_no].proc_id < MAXID) 12288c2ecf20Sopenharmony_ci ha->bus_id[bus_no] = iocr->list[bus_no].proc_id; 12298c2ecf20Sopenharmony_ci else 12308c2ecf20Sopenharmony_ci ha->bus_id[bus_no] = 0xff; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci } else { 12338c2ecf20Sopenharmony_ci /* old method */ 12348c2ecf20Sopenharmony_ci chn = (gdth_getch_str *)ha->pscratch; 12358c2ecf20Sopenharmony_ci for (bus_no = 0; bus_no < MAXBUS; ++bus_no) { 12368c2ecf20Sopenharmony_ci chn->channel_no = bus_no; 12378c2ecf20Sopenharmony_ci if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, 12388c2ecf20Sopenharmony_ci SCSI_CHAN_CNT | L_CTRL_PATTERN, 12398c2ecf20Sopenharmony_ci IO_CHANNEL | INVALID_CHANNEL, 12408c2ecf20Sopenharmony_ci sizeof(gdth_getch_str))) { 12418c2ecf20Sopenharmony_ci if (bus_no == 0) { 12428c2ecf20Sopenharmony_ci printk("GDT-HA %d: Error detecting channel count (0x%x)\n", 12438c2ecf20Sopenharmony_ci ha->hanum, ha->status); 12448c2ecf20Sopenharmony_ci return 0; 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci break; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci if (chn->siop_id < MAXID) 12498c2ecf20Sopenharmony_ci ha->bus_id[bus_no] = chn->siop_id; 12508c2ecf20Sopenharmony_ci else 12518c2ecf20Sopenharmony_ci ha->bus_id[bus_no] = 0xff; 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci ha->bus_cnt = (u8)bus_no; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci TRACE2(("gdth_search_drives() %d channels\n",ha->bus_cnt)); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci /* read cache configuration */ 12588c2ecf20Sopenharmony_ci if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_INFO, 12598c2ecf20Sopenharmony_ci INVALID_CHANNEL,sizeof(gdth_cinfo_str))) { 12608c2ecf20Sopenharmony_ci printk("GDT-HA %d: Initialization error cache service (code %d)\n", 12618c2ecf20Sopenharmony_ci ha->hanum, ha->status); 12628c2ecf20Sopenharmony_ci return 0; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci ha->cpar = ((gdth_cinfo_str *)ha->pscratch)->cpar; 12658c2ecf20Sopenharmony_ci TRACE2(("gdth_search_drives() cinfo: vs %x sta %d str %d dw %d b %d\n", 12668c2ecf20Sopenharmony_ci ha->cpar.version,ha->cpar.state,ha->cpar.strategy, 12678c2ecf20Sopenharmony_ci ha->cpar.write_back,ha->cpar.block_size)); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci /* read board info and features */ 12708c2ecf20Sopenharmony_ci ha->more_proc = FALSE; 12718c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, BOARD_INFO, 12728c2ecf20Sopenharmony_ci INVALID_CHANNEL,sizeof(gdth_binfo_str))) { 12738c2ecf20Sopenharmony_ci memcpy(&ha->binfo, (gdth_binfo_str *)ha->pscratch, 12748c2ecf20Sopenharmony_ci sizeof(gdth_binfo_str)); 12758c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, BOARD_FEATURES, 12768c2ecf20Sopenharmony_ci INVALID_CHANNEL,sizeof(gdth_bfeat_str))) { 12778c2ecf20Sopenharmony_ci TRACE2(("BOARD_INFO/BOARD_FEATURES supported\n")); 12788c2ecf20Sopenharmony_ci ha->bfeat = *(gdth_bfeat_str *)ha->pscratch; 12798c2ecf20Sopenharmony_ci ha->more_proc = TRUE; 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci } else { 12828c2ecf20Sopenharmony_ci TRACE2(("BOARD_INFO requires firmware >= 1.10/2.08\n")); 12838c2ecf20Sopenharmony_ci strcpy(ha->binfo.type_string, gdth_ctr_name(ha)); 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci TRACE2(("Controller name: %s\n",ha->binfo.type_string)); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci /* read more informations */ 12888c2ecf20Sopenharmony_ci if (ha->more_proc) { 12898c2ecf20Sopenharmony_ci /* physical drives, channel addresses */ 12908c2ecf20Sopenharmony_ci ioc = (gdth_iochan_str *)ha->pscratch; 12918c2ecf20Sopenharmony_ci ioc->hdr.version = 0xffffffff; 12928c2ecf20Sopenharmony_ci ioc->hdr.list_entries = MAXBUS; 12938c2ecf20Sopenharmony_ci ioc->hdr.first_chan = 0; 12948c2ecf20Sopenharmony_ci ioc->hdr.last_chan = MAXBUS-1; 12958c2ecf20Sopenharmony_ci ioc->hdr.list_offset = GDTOFFSOF(gdth_iochan_str, list[0]); 12968c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, IOCHAN_DESC, 12978c2ecf20Sopenharmony_ci INVALID_CHANNEL,sizeof(gdth_iochan_str))) { 12988c2ecf20Sopenharmony_ci for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { 12998c2ecf20Sopenharmony_ci ha->raw[bus_no].address = ioc->list[bus_no].address; 13008c2ecf20Sopenharmony_ci ha->raw[bus_no].local_no = ioc->list[bus_no].local_no; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci } else { 13038c2ecf20Sopenharmony_ci for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { 13048c2ecf20Sopenharmony_ci ha->raw[bus_no].address = IO_CHANNEL; 13058c2ecf20Sopenharmony_ci ha->raw[bus_no].local_no = bus_no; 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { 13098c2ecf20Sopenharmony_ci chn = (gdth_getch_str *)ha->pscratch; 13108c2ecf20Sopenharmony_ci chn->channel_no = ha->raw[bus_no].local_no; 13118c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, 13128c2ecf20Sopenharmony_ci SCSI_CHAN_CNT | L_CTRL_PATTERN, 13138c2ecf20Sopenharmony_ci ha->raw[bus_no].address | INVALID_CHANNEL, 13148c2ecf20Sopenharmony_ci sizeof(gdth_getch_str))) { 13158c2ecf20Sopenharmony_ci ha->raw[bus_no].pdev_cnt = chn->drive_cnt; 13168c2ecf20Sopenharmony_ci TRACE2(("Channel %d: %d phys. drives\n", 13178c2ecf20Sopenharmony_ci bus_no,chn->drive_cnt)); 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci if (ha->raw[bus_no].pdev_cnt > 0) { 13208c2ecf20Sopenharmony_ci drl = (gdth_drlist_str *)ha->pscratch; 13218c2ecf20Sopenharmony_ci drl->sc_no = ha->raw[bus_no].local_no; 13228c2ecf20Sopenharmony_ci drl->sc_cnt = ha->raw[bus_no].pdev_cnt; 13238c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, 13248c2ecf20Sopenharmony_ci SCSI_DR_LIST | L_CTRL_PATTERN, 13258c2ecf20Sopenharmony_ci ha->raw[bus_no].address | INVALID_CHANNEL, 13268c2ecf20Sopenharmony_ci sizeof(gdth_drlist_str))) { 13278c2ecf20Sopenharmony_ci for (j = 0; j < ha->raw[bus_no].pdev_cnt; ++j) 13288c2ecf20Sopenharmony_ci ha->raw[bus_no].id_list[j] = drl->sc_list[j]; 13298c2ecf20Sopenharmony_ci } else { 13308c2ecf20Sopenharmony_ci ha->raw[bus_no].pdev_cnt = 0; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci /* logical drives */ 13368c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_CNT, 13378c2ecf20Sopenharmony_ci INVALID_CHANNEL,sizeof(u32))) { 13388c2ecf20Sopenharmony_ci drv_cnt = *(u32 *)ha->pscratch; 13398c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_LIST, 13408c2ecf20Sopenharmony_ci INVALID_CHANNEL,drv_cnt * sizeof(u32))) { 13418c2ecf20Sopenharmony_ci for (j = 0; j < drv_cnt; ++j) { 13428c2ecf20Sopenharmony_ci drv_no = ((u32 *)ha->pscratch)[j]; 13438c2ecf20Sopenharmony_ci if (drv_no < MAX_LDRIVES) { 13448c2ecf20Sopenharmony_ci ha->hdr[drv_no].is_logdrv = TRUE; 13458c2ecf20Sopenharmony_ci TRACE2(("Drive %d is log. drive\n",drv_no)); 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci alst = (gdth_arcdl_str *)ha->pscratch; 13508c2ecf20Sopenharmony_ci alst->entries_avail = MAX_LDRIVES; 13518c2ecf20Sopenharmony_ci alst->first_entry = 0; 13528c2ecf20Sopenharmony_ci alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]); 13538c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, 13548c2ecf20Sopenharmony_ci ARRAY_DRV_LIST2 | LA_CTRL_PATTERN, 13558c2ecf20Sopenharmony_ci INVALID_CHANNEL, sizeof(gdth_arcdl_str) + 13568c2ecf20Sopenharmony_ci (alst->entries_avail-1) * sizeof(gdth_alist_str))) { 13578c2ecf20Sopenharmony_ci for (j = 0; j < alst->entries_init; ++j) { 13588c2ecf20Sopenharmony_ci ha->hdr[j].is_arraydrv = alst->list[j].is_arrayd; 13598c2ecf20Sopenharmony_ci ha->hdr[j].is_master = alst->list[j].is_master; 13608c2ecf20Sopenharmony_ci ha->hdr[j].is_parity = alst->list[j].is_parity; 13618c2ecf20Sopenharmony_ci ha->hdr[j].is_hotfix = alst->list[j].is_hotfix; 13628c2ecf20Sopenharmony_ci ha->hdr[j].master_no = alst->list[j].cd_handle; 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci } else if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, 13658c2ecf20Sopenharmony_ci ARRAY_DRV_LIST | LA_CTRL_PATTERN, 13668c2ecf20Sopenharmony_ci 0, 35 * sizeof(gdth_alist_str))) { 13678c2ecf20Sopenharmony_ci for (j = 0; j < 35; ++j) { 13688c2ecf20Sopenharmony_ci alst2 = &((gdth_alist_str *)ha->pscratch)[j]; 13698c2ecf20Sopenharmony_ci ha->hdr[j].is_arraydrv = alst2->is_arrayd; 13708c2ecf20Sopenharmony_ci ha->hdr[j].is_master = alst2->is_master; 13718c2ecf20Sopenharmony_ci ha->hdr[j].is_parity = alst2->is_parity; 13728c2ecf20Sopenharmony_ci ha->hdr[j].is_hotfix = alst2->is_hotfix; 13738c2ecf20Sopenharmony_ci ha->hdr[j].master_no = alst2->cd_handle; 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci } 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci /* initialize raw service */ 13808c2ecf20Sopenharmony_ci ha->raw_feat = 0; 13818c2ecf20Sopenharmony_ci if (!force_dma32) { 13828c2ecf20Sopenharmony_ci ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_X_INIT_RAW, 0, 0, 0); 13838c2ecf20Sopenharmony_ci if (ok) 13848c2ecf20Sopenharmony_ci ha->raw_feat = GDT_64BIT; 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC)) 13878c2ecf20Sopenharmony_ci ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_INIT, 0, 0, 0); 13888c2ecf20Sopenharmony_ci if (!ok) { 13898c2ecf20Sopenharmony_ci printk("GDT-HA %d: Initialization error raw service (code %d)\n", 13908c2ecf20Sopenharmony_ci ha->hanum, ha->status); 13918c2ecf20Sopenharmony_ci return 0; 13928c2ecf20Sopenharmony_ci } 13938c2ecf20Sopenharmony_ci TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n")); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci /* set/get features raw service (scatter/gather) */ 13968c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_SET_FEAT, SCATTER_GATHER, 13978c2ecf20Sopenharmony_ci 0, 0)) { 13988c2ecf20Sopenharmony_ci TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n")); 13998c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_GET_FEAT, 0, 0, 0)) { 14008c2ecf20Sopenharmony_ci TRACE2(("gdth_search_dr(): get feat RAWSERVICE %d\n", 14018c2ecf20Sopenharmony_ci ha->info)); 14028c2ecf20Sopenharmony_ci ha->raw_feat |= (u16)ha->info; 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci /* set/get features cache service (equal to raw service) */ 14078c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_SET_FEAT, 0, 14088c2ecf20Sopenharmony_ci SCATTER_GATHER,0)) { 14098c2ecf20Sopenharmony_ci TRACE2(("gdth_search_drives(): set features CACHESERVICE OK\n")); 14108c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_GET_FEAT, 0, 0, 0)) { 14118c2ecf20Sopenharmony_ci TRACE2(("gdth_search_dr(): get feat CACHESERV. %d\n", 14128c2ecf20Sopenharmony_ci ha->info)); 14138c2ecf20Sopenharmony_ci ha->cache_feat |= (u16)ha->info; 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci /* reserve drives for raw service */ 14188c2ecf20Sopenharmony_ci if (reserve_mode != 0) { 14198c2ecf20Sopenharmony_ci gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESERVE_ALL, 14208c2ecf20Sopenharmony_ci reserve_mode == 1 ? 1 : 3, 0, 0); 14218c2ecf20Sopenharmony_ci TRACE2(("gdth_search_drives(): RESERVE_ALL code %d\n", 14228c2ecf20Sopenharmony_ci ha->status)); 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci for (i = 0; i < MAX_RES_ARGS; i += 4) { 14258c2ecf20Sopenharmony_ci if (reserve_list[i] == ha->hanum && reserve_list[i+1] < ha->bus_cnt && 14268c2ecf20Sopenharmony_ci reserve_list[i+2] < ha->tid_cnt && reserve_list[i+3] < MAXLUN) { 14278c2ecf20Sopenharmony_ci TRACE2(("gdth_search_drives(): reserve ha %d bus %d id %d lun %d\n", 14288c2ecf20Sopenharmony_ci reserve_list[i], reserve_list[i+1], 14298c2ecf20Sopenharmony_ci reserve_list[i+2], reserve_list[i+3])); 14308c2ecf20Sopenharmony_ci if (!gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESERVE, 0, 14318c2ecf20Sopenharmony_ci reserve_list[i+1], reserve_list[i+2] | 14328c2ecf20Sopenharmony_ci (reserve_list[i+3] << 8))) { 14338c2ecf20Sopenharmony_ci printk("GDT-HA %d: Error raw service (RESERVE, code %d)\n", 14348c2ecf20Sopenharmony_ci ha->hanum, ha->status); 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci /* Determine OEM string using IOCTL */ 14408c2ecf20Sopenharmony_ci oemstr = (gdth_oem_str_ioctl *)ha->pscratch; 14418c2ecf20Sopenharmony_ci oemstr->params.ctl_version = 0x01; 14428c2ecf20Sopenharmony_ci oemstr->params.buffer_size = sizeof(oemstr->text); 14438c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, 14448c2ecf20Sopenharmony_ci CACHE_READ_OEM_STRING_RECORD,INVALID_CHANNEL, 14458c2ecf20Sopenharmony_ci sizeof(gdth_oem_str_ioctl))) { 14468c2ecf20Sopenharmony_ci TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD OK\n")); 14478c2ecf20Sopenharmony_ci printk("GDT-HA %d: Vendor: %s Name: %s\n", 14488c2ecf20Sopenharmony_ci ha->hanum, oemstr->text.oem_company_name, ha->binfo.type_string); 14498c2ecf20Sopenharmony_ci /* Save the Host Drive inquiry data */ 14508c2ecf20Sopenharmony_ci strlcpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id, 14518c2ecf20Sopenharmony_ci sizeof(ha->oem_name)); 14528c2ecf20Sopenharmony_ci } else { 14538c2ecf20Sopenharmony_ci /* Old method, based on PCI ID */ 14548c2ecf20Sopenharmony_ci TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD failed\n")); 14558c2ecf20Sopenharmony_ci printk("GDT-HA %d: Name: %s\n", 14568c2ecf20Sopenharmony_ci ha->hanum, ha->binfo.type_string); 14578c2ecf20Sopenharmony_ci if (ha->oem_id == OEM_ID_INTEL) 14588c2ecf20Sopenharmony_ci strlcpy(ha->oem_name,"Intel ", sizeof(ha->oem_name)); 14598c2ecf20Sopenharmony_ci else 14608c2ecf20Sopenharmony_ci strlcpy(ha->oem_name,"ICP ", sizeof(ha->oem_name)); 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci /* scanning for host drives */ 14648c2ecf20Sopenharmony_ci for (i = 0; i < cdev_cnt; ++i) 14658c2ecf20Sopenharmony_ci gdth_analyse_hdrive(ha, i); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci TRACE(("gdth_search_drives() OK\n")); 14688c2ecf20Sopenharmony_ci return 1; 14698c2ecf20Sopenharmony_ci} 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_cistatic int gdth_analyse_hdrive(gdth_ha_str *ha, u16 hdrive) 14728c2ecf20Sopenharmony_ci{ 14738c2ecf20Sopenharmony_ci u32 drv_cyls; 14748c2ecf20Sopenharmony_ci int drv_hds, drv_secs; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n", ha->hanum, hdrive)); 14778c2ecf20Sopenharmony_ci if (hdrive >= MAX_HDRIVES) 14788c2ecf20Sopenharmony_ci return 0; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_INFO, hdrive, 0, 0)) 14818c2ecf20Sopenharmony_ci return 0; 14828c2ecf20Sopenharmony_ci ha->hdr[hdrive].present = TRUE; 14838c2ecf20Sopenharmony_ci ha->hdr[hdrive].size = ha->info; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci /* evaluate mapping (sectors per head, heads per cylinder) */ 14868c2ecf20Sopenharmony_ci ha->hdr[hdrive].size &= ~SECS32; 14878c2ecf20Sopenharmony_ci if (ha->info2 == 0) { 14888c2ecf20Sopenharmony_ci gdth_eval_mapping(ha->hdr[hdrive].size,&drv_cyls,&drv_hds,&drv_secs); 14898c2ecf20Sopenharmony_ci } else { 14908c2ecf20Sopenharmony_ci drv_hds = ha->info2 & 0xff; 14918c2ecf20Sopenharmony_ci drv_secs = (ha->info2 >> 8) & 0xff; 14928c2ecf20Sopenharmony_ci drv_cyls = (u32)ha->hdr[hdrive].size / drv_hds / drv_secs; 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci ha->hdr[hdrive].heads = (u8)drv_hds; 14958c2ecf20Sopenharmony_ci ha->hdr[hdrive].secs = (u8)drv_secs; 14968c2ecf20Sopenharmony_ci /* round size */ 14978c2ecf20Sopenharmony_ci ha->hdr[hdrive].size = drv_cyls * drv_hds * drv_secs; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci if (ha->cache_feat & GDT_64BIT) { 15008c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INFO, hdrive, 0, 0) 15018c2ecf20Sopenharmony_ci && ha->info2 != 0) { 15028c2ecf20Sopenharmony_ci ha->hdr[hdrive].size = ((u64)ha->info2 << 32) | ha->info; 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n", 15068c2ecf20Sopenharmony_ci hdrive,ha->hdr[hdrive].size,drv_hds,drv_secs)); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci /* get informations about device */ 15098c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_DEVTYPE, hdrive, 0, 0)) { 15108c2ecf20Sopenharmony_ci TRACE2(("gdth_search_dr() cache drive %d devtype %d\n", 15118c2ecf20Sopenharmony_ci hdrive,ha->info)); 15128c2ecf20Sopenharmony_ci ha->hdr[hdrive].devtype = (u16)ha->info; 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci /* cluster info */ 15168c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_CLUST_INFO, hdrive, 0, 0)) { 15178c2ecf20Sopenharmony_ci TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n", 15188c2ecf20Sopenharmony_ci hdrive,ha->info)); 15198c2ecf20Sopenharmony_ci if (!shared_access) 15208c2ecf20Sopenharmony_ci ha->hdr[hdrive].cluster_type = (u8)ha->info; 15218c2ecf20Sopenharmony_ci } 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci /* R/W attributes */ 15248c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, GDT_RW_ATTRIBS, hdrive, 0, 0)) { 15258c2ecf20Sopenharmony_ci TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n", 15268c2ecf20Sopenharmony_ci hdrive,ha->info)); 15278c2ecf20Sopenharmony_ci ha->hdr[hdrive].rw_attribs = (u8)ha->info; 15288c2ecf20Sopenharmony_ci } 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci return 1; 15318c2ecf20Sopenharmony_ci} 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci/* command queueing/sending functions */ 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_cistatic void gdth_putq(gdth_ha_str *ha, struct scsi_cmnd *scp, u8 priority) 15378c2ecf20Sopenharmony_ci{ 15388c2ecf20Sopenharmony_ci struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); 15398c2ecf20Sopenharmony_ci register struct scsi_cmnd *pscp; 15408c2ecf20Sopenharmony_ci register struct scsi_cmnd *nscp; 15418c2ecf20Sopenharmony_ci unsigned long flags; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci TRACE(("gdth_putq() priority %d\n",priority)); 15448c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci if (!cmndinfo->internal_command) 15478c2ecf20Sopenharmony_ci cmndinfo->priority = priority; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (ha->req_first==NULL) { 15508c2ecf20Sopenharmony_ci ha->req_first = scp; /* queue was empty */ 15518c2ecf20Sopenharmony_ci scp->SCp.ptr = NULL; 15528c2ecf20Sopenharmony_ci } else { /* queue not empty */ 15538c2ecf20Sopenharmony_ci pscp = ha->req_first; 15548c2ecf20Sopenharmony_ci nscp = (struct scsi_cmnd *)pscp->SCp.ptr; 15558c2ecf20Sopenharmony_ci /* priority: 0-highest,..,0xff-lowest */ 15568c2ecf20Sopenharmony_ci while (nscp && gdth_cmnd_priv(nscp)->priority <= priority) { 15578c2ecf20Sopenharmony_ci pscp = nscp; 15588c2ecf20Sopenharmony_ci nscp = (struct scsi_cmnd *)pscp->SCp.ptr; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci pscp->SCp.ptr = (char *)scp; 15618c2ecf20Sopenharmony_ci scp->SCp.ptr = (char *)nscp; 15628c2ecf20Sopenharmony_ci } 15638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci#ifdef GDTH_STATISTICS 15668c2ecf20Sopenharmony_ci flags = 0; 15678c2ecf20Sopenharmony_ci for (nscp=ha->req_first; nscp; nscp=(struct scsi_cmnd*)nscp->SCp.ptr) 15688c2ecf20Sopenharmony_ci ++flags; 15698c2ecf20Sopenharmony_ci if (max_rq < flags) { 15708c2ecf20Sopenharmony_ci max_rq = flags; 15718c2ecf20Sopenharmony_ci TRACE3(("GDT: max_rq = %d\n",(u16)max_rq)); 15728c2ecf20Sopenharmony_ci } 15738c2ecf20Sopenharmony_ci#endif 15748c2ecf20Sopenharmony_ci} 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_cistatic void gdth_next(gdth_ha_str *ha) 15778c2ecf20Sopenharmony_ci{ 15788c2ecf20Sopenharmony_ci register struct scsi_cmnd *pscp; 15798c2ecf20Sopenharmony_ci register struct scsi_cmnd *nscp; 15808c2ecf20Sopenharmony_ci u8 b, t, l, firsttime; 15818c2ecf20Sopenharmony_ci u8 this_cmd, next_cmd; 15828c2ecf20Sopenharmony_ci unsigned long flags = 0; 15838c2ecf20Sopenharmony_ci int cmd_index; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci TRACE(("gdth_next() hanum %d\n", ha->hanum)); 15868c2ecf20Sopenharmony_ci if (!gdth_polling) 15878c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci ha->cmd_cnt = ha->cmd_offs_dpmem = 0; 15908c2ecf20Sopenharmony_ci this_cmd = firsttime = TRUE; 15918c2ecf20Sopenharmony_ci next_cmd = gdth_polling ? FALSE:TRUE; 15928c2ecf20Sopenharmony_ci cmd_index = 0; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci for (nscp = pscp = ha->req_first; nscp; nscp = (struct scsi_cmnd *)nscp->SCp.ptr) { 15958c2ecf20Sopenharmony_ci struct gdth_cmndinfo *nscp_cmndinfo = gdth_cmnd_priv(nscp); 15968c2ecf20Sopenharmony_ci if (nscp != pscp && nscp != (struct scsi_cmnd *)pscp->SCp.ptr) 15978c2ecf20Sopenharmony_ci pscp = (struct scsi_cmnd *)pscp->SCp.ptr; 15988c2ecf20Sopenharmony_ci if (!nscp_cmndinfo->internal_command) { 15998c2ecf20Sopenharmony_ci b = nscp->device->channel; 16008c2ecf20Sopenharmony_ci t = nscp->device->id; 16018c2ecf20Sopenharmony_ci l = nscp->device->lun; 16028c2ecf20Sopenharmony_ci if (nscp_cmndinfo->priority >= DEFAULT_PRI) { 16038c2ecf20Sopenharmony_ci if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) || 16048c2ecf20Sopenharmony_ci (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) 16058c2ecf20Sopenharmony_ci continue; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci } else 16088c2ecf20Sopenharmony_ci b = t = l = 0; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci if (firsttime) { 16118c2ecf20Sopenharmony_ci if (gdth_test_busy(ha)) { /* controller busy ? */ 16128c2ecf20Sopenharmony_ci TRACE(("gdth_next() controller %d busy !\n", ha->hanum)); 16138c2ecf20Sopenharmony_ci if (!gdth_polling) { 16148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 16158c2ecf20Sopenharmony_ci return; 16168c2ecf20Sopenharmony_ci } 16178c2ecf20Sopenharmony_ci while (gdth_test_busy(ha)) 16188c2ecf20Sopenharmony_ci gdth_delay(1); 16198c2ecf20Sopenharmony_ci } 16208c2ecf20Sopenharmony_ci firsttime = FALSE; 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci if (!nscp_cmndinfo->internal_command) { 16248c2ecf20Sopenharmony_ci if (nscp_cmndinfo->phase == -1) { 16258c2ecf20Sopenharmony_ci nscp_cmndinfo->phase = CACHESERVICE; /* default: cache svc. */ 16268c2ecf20Sopenharmony_ci if (nscp->cmnd[0] == TEST_UNIT_READY) { 16278c2ecf20Sopenharmony_ci TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", 16288c2ecf20Sopenharmony_ci b, t, l)); 16298c2ecf20Sopenharmony_ci /* TEST_UNIT_READY -> set scan mode */ 16308c2ecf20Sopenharmony_ci if ((ha->scan_mode & 0x0f) == 0) { 16318c2ecf20Sopenharmony_ci if (b == 0 && t == 0 && l == 0) { 16328c2ecf20Sopenharmony_ci ha->scan_mode |= 1; 16338c2ecf20Sopenharmony_ci TRACE2(("Scan mode: 0x%x\n", ha->scan_mode)); 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci } else if ((ha->scan_mode & 0x0f) == 1) { 16368c2ecf20Sopenharmony_ci if (b == 0 && ((t == 0 && l == 1) || 16378c2ecf20Sopenharmony_ci (t == 1 && l == 0))) { 16388c2ecf20Sopenharmony_ci nscp_cmndinfo->OpCode = GDT_SCAN_START; 16398c2ecf20Sopenharmony_ci nscp_cmndinfo->phase = ((ha->scan_mode & 0x10 ? 1:0) << 8) 16408c2ecf20Sopenharmony_ci | SCSIRAWSERVICE; 16418c2ecf20Sopenharmony_ci ha->scan_mode = 0x12; 16428c2ecf20Sopenharmony_ci TRACE2(("Scan mode: 0x%x (SCAN_START)\n", 16438c2ecf20Sopenharmony_ci ha->scan_mode)); 16448c2ecf20Sopenharmony_ci } else { 16458c2ecf20Sopenharmony_ci ha->scan_mode &= 0x10; 16468c2ecf20Sopenharmony_ci TRACE2(("Scan mode: 0x%x\n", ha->scan_mode)); 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci } else if (ha->scan_mode == 0x12) { 16498c2ecf20Sopenharmony_ci if (b == ha->bus_cnt && t == ha->tid_cnt-1) { 16508c2ecf20Sopenharmony_ci nscp_cmndinfo->phase = SCSIRAWSERVICE; 16518c2ecf20Sopenharmony_ci nscp_cmndinfo->OpCode = GDT_SCAN_END; 16528c2ecf20Sopenharmony_ci ha->scan_mode &= 0x10; 16538c2ecf20Sopenharmony_ci TRACE2(("Scan mode: 0x%x (SCAN_END)\n", 16548c2ecf20Sopenharmony_ci ha->scan_mode)); 16558c2ecf20Sopenharmony_ci } 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci if (b == ha->virt_bus && nscp->cmnd[0] != INQUIRY && 16598c2ecf20Sopenharmony_ci nscp->cmnd[0] != READ_CAPACITY && nscp->cmnd[0] != MODE_SENSE && 16608c2ecf20Sopenharmony_ci (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) { 16618c2ecf20Sopenharmony_ci /* always GDT_CLUST_INFO! */ 16628c2ecf20Sopenharmony_ci nscp_cmndinfo->OpCode = GDT_CLUST_INFO; 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci } 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci if (nscp_cmndinfo->OpCode != -1) { 16688c2ecf20Sopenharmony_ci if ((nscp_cmndinfo->phase & 0xff) == CACHESERVICE) { 16698c2ecf20Sopenharmony_ci if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t))) 16708c2ecf20Sopenharmony_ci this_cmd = FALSE; 16718c2ecf20Sopenharmony_ci next_cmd = FALSE; 16728c2ecf20Sopenharmony_ci } else if ((nscp_cmndinfo->phase & 0xff) == SCSIRAWSERVICE) { 16738c2ecf20Sopenharmony_ci if (!(cmd_index=gdth_fill_raw_cmd(ha, nscp, BUS_L2P(ha, b)))) 16748c2ecf20Sopenharmony_ci this_cmd = FALSE; 16758c2ecf20Sopenharmony_ci next_cmd = FALSE; 16768c2ecf20Sopenharmony_ci } else { 16778c2ecf20Sopenharmony_ci memset((char*)nscp->sense_buffer,0,16); 16788c2ecf20Sopenharmony_ci nscp->sense_buffer[0] = 0x70; 16798c2ecf20Sopenharmony_ci nscp->sense_buffer[2] = NOT_READY; 16808c2ecf20Sopenharmony_ci nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); 16818c2ecf20Sopenharmony_ci if (!nscp_cmndinfo->wait_for_completion) 16828c2ecf20Sopenharmony_ci nscp_cmndinfo->wait_for_completion++; 16838c2ecf20Sopenharmony_ci else 16848c2ecf20Sopenharmony_ci gdth_scsi_done(nscp); 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci } else if (gdth_cmnd_priv(nscp)->internal_command) { 16878c2ecf20Sopenharmony_ci if (!(cmd_index=gdth_special_cmd(ha, nscp))) 16888c2ecf20Sopenharmony_ci this_cmd = FALSE; 16898c2ecf20Sopenharmony_ci next_cmd = FALSE; 16908c2ecf20Sopenharmony_ci } else if (b != ha->virt_bus) { 16918c2ecf20Sopenharmony_ci if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW || 16928c2ecf20Sopenharmony_ci !(cmd_index=gdth_fill_raw_cmd(ha, nscp, BUS_L2P(ha, b)))) 16938c2ecf20Sopenharmony_ci this_cmd = FALSE; 16948c2ecf20Sopenharmony_ci else 16958c2ecf20Sopenharmony_ci ha->raw[BUS_L2P(ha,b)].io_cnt[t]++; 16968c2ecf20Sopenharmony_ci } else if (t >= MAX_HDRIVES || !ha->hdr[t].present || l != 0) { 16978c2ecf20Sopenharmony_ci TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n", 16988c2ecf20Sopenharmony_ci nscp->cmnd[0], b, t, l)); 16998c2ecf20Sopenharmony_ci nscp->result = DID_BAD_TARGET << 16; 17008c2ecf20Sopenharmony_ci if (!nscp_cmndinfo->wait_for_completion) 17018c2ecf20Sopenharmony_ci nscp_cmndinfo->wait_for_completion++; 17028c2ecf20Sopenharmony_ci else 17038c2ecf20Sopenharmony_ci gdth_scsi_done(nscp); 17048c2ecf20Sopenharmony_ci } else { 17058c2ecf20Sopenharmony_ci switch (nscp->cmnd[0]) { 17068c2ecf20Sopenharmony_ci case TEST_UNIT_READY: 17078c2ecf20Sopenharmony_ci case INQUIRY: 17088c2ecf20Sopenharmony_ci case REQUEST_SENSE: 17098c2ecf20Sopenharmony_ci case READ_CAPACITY: 17108c2ecf20Sopenharmony_ci case VERIFY: 17118c2ecf20Sopenharmony_ci case START_STOP: 17128c2ecf20Sopenharmony_ci case MODE_SENSE: 17138c2ecf20Sopenharmony_ci case SERVICE_ACTION_IN_16: 17148c2ecf20Sopenharmony_ci TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0], 17158c2ecf20Sopenharmony_ci nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3], 17168c2ecf20Sopenharmony_ci nscp->cmnd[4],nscp->cmnd[5])); 17178c2ecf20Sopenharmony_ci if (ha->hdr[t].media_changed && nscp->cmnd[0] != INQUIRY) { 17188c2ecf20Sopenharmony_ci /* return UNIT_ATTENTION */ 17198c2ecf20Sopenharmony_ci TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n", 17208c2ecf20Sopenharmony_ci nscp->cmnd[0], t)); 17218c2ecf20Sopenharmony_ci ha->hdr[t].media_changed = FALSE; 17228c2ecf20Sopenharmony_ci memset((char*)nscp->sense_buffer,0,16); 17238c2ecf20Sopenharmony_ci nscp->sense_buffer[0] = 0x70; 17248c2ecf20Sopenharmony_ci nscp->sense_buffer[2] = UNIT_ATTENTION; 17258c2ecf20Sopenharmony_ci nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); 17268c2ecf20Sopenharmony_ci if (!nscp_cmndinfo->wait_for_completion) 17278c2ecf20Sopenharmony_ci nscp_cmndinfo->wait_for_completion++; 17288c2ecf20Sopenharmony_ci else 17298c2ecf20Sopenharmony_ci gdth_scsi_done(nscp); 17308c2ecf20Sopenharmony_ci } else if (gdth_internal_cache_cmd(ha, nscp)) 17318c2ecf20Sopenharmony_ci gdth_scsi_done(nscp); 17328c2ecf20Sopenharmony_ci break; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci case ALLOW_MEDIUM_REMOVAL: 17358c2ecf20Sopenharmony_ci TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0], 17368c2ecf20Sopenharmony_ci nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3], 17378c2ecf20Sopenharmony_ci nscp->cmnd[4],nscp->cmnd[5])); 17388c2ecf20Sopenharmony_ci if ( (nscp->cmnd[4]&1) && !(ha->hdr[t].devtype&1) ) { 17398c2ecf20Sopenharmony_ci TRACE(("Prevent r. nonremov. drive->do nothing\n")); 17408c2ecf20Sopenharmony_ci nscp->result = DID_OK << 16; 17418c2ecf20Sopenharmony_ci nscp->sense_buffer[0] = 0; 17428c2ecf20Sopenharmony_ci if (!nscp_cmndinfo->wait_for_completion) 17438c2ecf20Sopenharmony_ci nscp_cmndinfo->wait_for_completion++; 17448c2ecf20Sopenharmony_ci else 17458c2ecf20Sopenharmony_ci gdth_scsi_done(nscp); 17468c2ecf20Sopenharmony_ci } else { 17478c2ecf20Sopenharmony_ci nscp->cmnd[3] = (ha->hdr[t].devtype&1) ? 1:0; 17488c2ecf20Sopenharmony_ci TRACE(("Prevent/allow r. %d rem. drive %d\n", 17498c2ecf20Sopenharmony_ci nscp->cmnd[4],nscp->cmnd[3])); 17508c2ecf20Sopenharmony_ci if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t))) 17518c2ecf20Sopenharmony_ci this_cmd = FALSE; 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci break; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci case RESERVE: 17568c2ecf20Sopenharmony_ci case RELEASE: 17578c2ecf20Sopenharmony_ci TRACE2(("cache cmd %s\n",nscp->cmnd[0] == RESERVE ? 17588c2ecf20Sopenharmony_ci "RESERVE" : "RELEASE")); 17598c2ecf20Sopenharmony_ci if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t))) 17608c2ecf20Sopenharmony_ci this_cmd = FALSE; 17618c2ecf20Sopenharmony_ci break; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci case READ_6: 17648c2ecf20Sopenharmony_ci case WRITE_6: 17658c2ecf20Sopenharmony_ci case READ_10: 17668c2ecf20Sopenharmony_ci case WRITE_10: 17678c2ecf20Sopenharmony_ci case READ_16: 17688c2ecf20Sopenharmony_ci case WRITE_16: 17698c2ecf20Sopenharmony_ci if (ha->hdr[t].media_changed) { 17708c2ecf20Sopenharmony_ci /* return UNIT_ATTENTION */ 17718c2ecf20Sopenharmony_ci TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n", 17728c2ecf20Sopenharmony_ci nscp->cmnd[0], t)); 17738c2ecf20Sopenharmony_ci ha->hdr[t].media_changed = FALSE; 17748c2ecf20Sopenharmony_ci memset((char*)nscp->sense_buffer,0,16); 17758c2ecf20Sopenharmony_ci nscp->sense_buffer[0] = 0x70; 17768c2ecf20Sopenharmony_ci nscp->sense_buffer[2] = UNIT_ATTENTION; 17778c2ecf20Sopenharmony_ci nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); 17788c2ecf20Sopenharmony_ci if (!nscp_cmndinfo->wait_for_completion) 17798c2ecf20Sopenharmony_ci nscp_cmndinfo->wait_for_completion++; 17808c2ecf20Sopenharmony_ci else 17818c2ecf20Sopenharmony_ci gdth_scsi_done(nscp); 17828c2ecf20Sopenharmony_ci } else if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t))) 17838c2ecf20Sopenharmony_ci this_cmd = FALSE; 17848c2ecf20Sopenharmony_ci break; 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci default: 17878c2ecf20Sopenharmony_ci TRACE2(("cache cmd %x/%x/%x/%x/%x/%x unknown\n",nscp->cmnd[0], 17888c2ecf20Sopenharmony_ci nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3], 17898c2ecf20Sopenharmony_ci nscp->cmnd[4],nscp->cmnd[5])); 17908c2ecf20Sopenharmony_ci printk("GDT-HA %d: Unknown SCSI command 0x%x to cache service !\n", 17918c2ecf20Sopenharmony_ci ha->hanum, nscp->cmnd[0]); 17928c2ecf20Sopenharmony_ci nscp->result = DID_ABORT << 16; 17938c2ecf20Sopenharmony_ci if (!nscp_cmndinfo->wait_for_completion) 17948c2ecf20Sopenharmony_ci nscp_cmndinfo->wait_for_completion++; 17958c2ecf20Sopenharmony_ci else 17968c2ecf20Sopenharmony_ci gdth_scsi_done(nscp); 17978c2ecf20Sopenharmony_ci break; 17988c2ecf20Sopenharmony_ci } 17998c2ecf20Sopenharmony_ci } 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci if (!this_cmd) 18028c2ecf20Sopenharmony_ci break; 18038c2ecf20Sopenharmony_ci if (nscp == ha->req_first) 18048c2ecf20Sopenharmony_ci ha->req_first = pscp = (struct scsi_cmnd *)nscp->SCp.ptr; 18058c2ecf20Sopenharmony_ci else 18068c2ecf20Sopenharmony_ci pscp->SCp.ptr = nscp->SCp.ptr; 18078c2ecf20Sopenharmony_ci if (!next_cmd) 18088c2ecf20Sopenharmony_ci break; 18098c2ecf20Sopenharmony_ci } 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci if (ha->cmd_cnt > 0) { 18128c2ecf20Sopenharmony_ci gdth_release_event(ha); 18138c2ecf20Sopenharmony_ci } 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci if (!gdth_polling) 18168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci if (gdth_polling && ha->cmd_cnt > 0) { 18198c2ecf20Sopenharmony_ci if (!gdth_wait(ha, cmd_index, POLL_TIMEOUT)) 18208c2ecf20Sopenharmony_ci printk("GDT-HA %d: Command %d timed out !\n", 18218c2ecf20Sopenharmony_ci ha->hanum, cmd_index); 18228c2ecf20Sopenharmony_ci } 18238c2ecf20Sopenharmony_ci} 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci/* 18268c2ecf20Sopenharmony_ci * gdth_copy_internal_data() - copy to/from a buffer onto a scsi_cmnd's 18278c2ecf20Sopenharmony_ci * buffers, kmap_atomic() as needed. 18288c2ecf20Sopenharmony_ci */ 18298c2ecf20Sopenharmony_cistatic void gdth_copy_internal_data(gdth_ha_str *ha, struct scsi_cmnd *scp, 18308c2ecf20Sopenharmony_ci char *buffer, u16 count) 18318c2ecf20Sopenharmony_ci{ 18328c2ecf20Sopenharmony_ci u16 cpcount,i, max_sg = scsi_sg_count(scp); 18338c2ecf20Sopenharmony_ci u16 cpsum,cpnow; 18348c2ecf20Sopenharmony_ci struct scatterlist *sl; 18358c2ecf20Sopenharmony_ci char *address; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci cpcount = min_t(u16, count, scsi_bufflen(scp)); 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci if (cpcount) { 18408c2ecf20Sopenharmony_ci cpsum=0; 18418c2ecf20Sopenharmony_ci scsi_for_each_sg(scp, sl, max_sg, i) { 18428c2ecf20Sopenharmony_ci unsigned long flags; 18438c2ecf20Sopenharmony_ci cpnow = (u16)sl->length; 18448c2ecf20Sopenharmony_ci TRACE(("copy_internal() now %d sum %d count %d %d\n", 18458c2ecf20Sopenharmony_ci cpnow, cpsum, cpcount, scsi_bufflen(scp))); 18468c2ecf20Sopenharmony_ci if (cpsum+cpnow > cpcount) 18478c2ecf20Sopenharmony_ci cpnow = cpcount - cpsum; 18488c2ecf20Sopenharmony_ci cpsum += cpnow; 18498c2ecf20Sopenharmony_ci if (!sg_page(sl)) { 18508c2ecf20Sopenharmony_ci printk("GDT-HA %d: invalid sc/gt element in gdth_copy_internal_data()\n", 18518c2ecf20Sopenharmony_ci ha->hanum); 18528c2ecf20Sopenharmony_ci return; 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci local_irq_save(flags); 18558c2ecf20Sopenharmony_ci address = kmap_atomic(sg_page(sl)) + sl->offset; 18568c2ecf20Sopenharmony_ci memcpy(address, buffer, cpnow); 18578c2ecf20Sopenharmony_ci flush_dcache_page(sg_page(sl)); 18588c2ecf20Sopenharmony_ci kunmap_atomic(address); 18598c2ecf20Sopenharmony_ci local_irq_restore(flags); 18608c2ecf20Sopenharmony_ci if (cpsum == cpcount) 18618c2ecf20Sopenharmony_ci break; 18628c2ecf20Sopenharmony_ci buffer += cpnow; 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci } else if (count) { 18658c2ecf20Sopenharmony_ci printk("GDT-HA %d: SCSI command with no buffers but data transfer expected!\n", 18668c2ecf20Sopenharmony_ci ha->hanum); 18678c2ecf20Sopenharmony_ci WARN_ON(1); 18688c2ecf20Sopenharmony_ci } 18698c2ecf20Sopenharmony_ci} 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_cistatic int gdth_internal_cache_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp) 18728c2ecf20Sopenharmony_ci{ 18738c2ecf20Sopenharmony_ci u8 t; 18748c2ecf20Sopenharmony_ci gdth_inq_data inq; 18758c2ecf20Sopenharmony_ci gdth_rdcap_data rdc; 18768c2ecf20Sopenharmony_ci gdth_sense_data sd; 18778c2ecf20Sopenharmony_ci gdth_modep_data mpd; 18788c2ecf20Sopenharmony_ci struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci t = scp->device->id; 18818c2ecf20Sopenharmony_ci TRACE(("gdth_internal_cache_cmd() cmd 0x%x hdrive %d\n", 18828c2ecf20Sopenharmony_ci scp->cmnd[0],t)); 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci scp->result = DID_OK << 16; 18858c2ecf20Sopenharmony_ci scp->sense_buffer[0] = 0; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci switch (scp->cmnd[0]) { 18888c2ecf20Sopenharmony_ci case TEST_UNIT_READY: 18898c2ecf20Sopenharmony_ci case VERIFY: 18908c2ecf20Sopenharmony_ci case START_STOP: 18918c2ecf20Sopenharmony_ci TRACE2(("Test/Verify/Start hdrive %d\n",t)); 18928c2ecf20Sopenharmony_ci break; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci case INQUIRY: 18958c2ecf20Sopenharmony_ci TRACE2(("Inquiry hdrive %d devtype %d\n", 18968c2ecf20Sopenharmony_ci t,ha->hdr[t].devtype)); 18978c2ecf20Sopenharmony_ci inq.type_qual = (ha->hdr[t].devtype&4) ? TYPE_ROM:TYPE_DISK; 18988c2ecf20Sopenharmony_ci /* you can here set all disks to removable, if you want to do 18998c2ecf20Sopenharmony_ci a flush using the ALLOW_MEDIUM_REMOVAL command */ 19008c2ecf20Sopenharmony_ci inq.modif_rmb = 0x00; 19018c2ecf20Sopenharmony_ci if ((ha->hdr[t].devtype & 1) || 19028c2ecf20Sopenharmony_ci (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) 19038c2ecf20Sopenharmony_ci inq.modif_rmb = 0x80; 19048c2ecf20Sopenharmony_ci inq.version = 2; 19058c2ecf20Sopenharmony_ci inq.resp_aenc = 2; 19068c2ecf20Sopenharmony_ci inq.add_length= 32; 19078c2ecf20Sopenharmony_ci strcpy(inq.vendor,ha->oem_name); 19088c2ecf20Sopenharmony_ci snprintf(inq.product, sizeof(inq.product), "Host Drive #%02d",t); 19098c2ecf20Sopenharmony_ci strcpy(inq.revision," "); 19108c2ecf20Sopenharmony_ci gdth_copy_internal_data(ha, scp, (char*)&inq, sizeof(gdth_inq_data)); 19118c2ecf20Sopenharmony_ci break; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci case REQUEST_SENSE: 19148c2ecf20Sopenharmony_ci TRACE2(("Request sense hdrive %d\n",t)); 19158c2ecf20Sopenharmony_ci sd.errorcode = 0x70; 19168c2ecf20Sopenharmony_ci sd.segno = 0x00; 19178c2ecf20Sopenharmony_ci sd.key = NO_SENSE; 19188c2ecf20Sopenharmony_ci sd.info = 0; 19198c2ecf20Sopenharmony_ci sd.add_length= 0; 19208c2ecf20Sopenharmony_ci gdth_copy_internal_data(ha, scp, (char*)&sd, sizeof(gdth_sense_data)); 19218c2ecf20Sopenharmony_ci break; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci case MODE_SENSE: 19248c2ecf20Sopenharmony_ci TRACE2(("Mode sense hdrive %d\n",t)); 19258c2ecf20Sopenharmony_ci memset((char*)&mpd,0,sizeof(gdth_modep_data)); 19268c2ecf20Sopenharmony_ci mpd.hd.data_length = sizeof(gdth_modep_data); 19278c2ecf20Sopenharmony_ci mpd.hd.dev_par = (ha->hdr[t].devtype&2) ? 0x80:0; 19288c2ecf20Sopenharmony_ci mpd.hd.bd_length = sizeof(mpd.bd); 19298c2ecf20Sopenharmony_ci mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16; 19308c2ecf20Sopenharmony_ci mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8; 19318c2ecf20Sopenharmony_ci mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff); 19328c2ecf20Sopenharmony_ci gdth_copy_internal_data(ha, scp, (char*)&mpd, sizeof(gdth_modep_data)); 19338c2ecf20Sopenharmony_ci break; 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci case READ_CAPACITY: 19368c2ecf20Sopenharmony_ci TRACE2(("Read capacity hdrive %d\n",t)); 19378c2ecf20Sopenharmony_ci if (ha->hdr[t].size > (u64)0xffffffff) 19388c2ecf20Sopenharmony_ci rdc.last_block_no = 0xffffffff; 19398c2ecf20Sopenharmony_ci else 19408c2ecf20Sopenharmony_ci rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1); 19418c2ecf20Sopenharmony_ci rdc.block_length = cpu_to_be32(SECTOR_SIZE); 19428c2ecf20Sopenharmony_ci gdth_copy_internal_data(ha, scp, (char*)&rdc, sizeof(gdth_rdcap_data)); 19438c2ecf20Sopenharmony_ci break; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci case SERVICE_ACTION_IN_16: 19468c2ecf20Sopenharmony_ci if ((scp->cmnd[1] & 0x1f) == SAI_READ_CAPACITY_16 && 19478c2ecf20Sopenharmony_ci (ha->cache_feat & GDT_64BIT)) { 19488c2ecf20Sopenharmony_ci gdth_rdcap16_data rdc16; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci TRACE2(("Read capacity (16) hdrive %d\n",t)); 19518c2ecf20Sopenharmony_ci rdc16.last_block_no = cpu_to_be64(ha->hdr[t].size-1); 19528c2ecf20Sopenharmony_ci rdc16.block_length = cpu_to_be32(SECTOR_SIZE); 19538c2ecf20Sopenharmony_ci gdth_copy_internal_data(ha, scp, (char*)&rdc16, 19548c2ecf20Sopenharmony_ci sizeof(gdth_rdcap16_data)); 19558c2ecf20Sopenharmony_ci } else { 19568c2ecf20Sopenharmony_ci scp->result = DID_ABORT << 16; 19578c2ecf20Sopenharmony_ci } 19588c2ecf20Sopenharmony_ci break; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci default: 19618c2ecf20Sopenharmony_ci TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0])); 19628c2ecf20Sopenharmony_ci break; 19638c2ecf20Sopenharmony_ci } 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci if (!cmndinfo->wait_for_completion) 19668c2ecf20Sopenharmony_ci cmndinfo->wait_for_completion++; 19678c2ecf20Sopenharmony_ci else 19688c2ecf20Sopenharmony_ci return 1; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci return 0; 19718c2ecf20Sopenharmony_ci} 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_cistatic int gdth_fill_cache_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, 19748c2ecf20Sopenharmony_ci u16 hdrive) 19758c2ecf20Sopenharmony_ci{ 19768c2ecf20Sopenharmony_ci register gdth_cmd_str *cmdp; 19778c2ecf20Sopenharmony_ci struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); 19788c2ecf20Sopenharmony_ci u32 cnt, blockcnt; 19798c2ecf20Sopenharmony_ci u64 no, blockno; 19808c2ecf20Sopenharmony_ci int i, cmd_index, read_write, sgcnt, mode64; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci cmdp = ha->pccb; 19838c2ecf20Sopenharmony_ci TRACE(("gdth_fill_cache_cmd() cmd 0x%x cmdsize %d hdrive %d\n", 19848c2ecf20Sopenharmony_ci scp->cmnd[0],scp->cmd_len,hdrive)); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci mode64 = (ha->cache_feat & GDT_64BIT) ? TRUE : FALSE; 19878c2ecf20Sopenharmony_ci /* test for READ_16, WRITE_16 if !mode64 ? --- 19888c2ecf20Sopenharmony_ci not required, should not occur due to error return on 19898c2ecf20Sopenharmony_ci READ_CAPACITY_16 */ 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci cmdp->Service = CACHESERVICE; 19928c2ecf20Sopenharmony_ci cmdp->RequestBuffer = scp; 19938c2ecf20Sopenharmony_ci /* search free command index */ 19948c2ecf20Sopenharmony_ci if (!(cmd_index=gdth_get_cmd_index(ha))) { 19958c2ecf20Sopenharmony_ci TRACE(("GDT: No free command index found\n")); 19968c2ecf20Sopenharmony_ci return 0; 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci /* if it's the first command, set command semaphore */ 19998c2ecf20Sopenharmony_ci if (ha->cmd_cnt == 0) 20008c2ecf20Sopenharmony_ci gdth_set_sema0(ha); 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci /* fill command */ 20038c2ecf20Sopenharmony_ci read_write = 0; 20048c2ecf20Sopenharmony_ci if (cmndinfo->OpCode != -1) 20058c2ecf20Sopenharmony_ci cmdp->OpCode = cmndinfo->OpCode; /* special cache cmd. */ 20068c2ecf20Sopenharmony_ci else if (scp->cmnd[0] == RESERVE) 20078c2ecf20Sopenharmony_ci cmdp->OpCode = GDT_RESERVE_DRV; 20088c2ecf20Sopenharmony_ci else if (scp->cmnd[0] == RELEASE) 20098c2ecf20Sopenharmony_ci cmdp->OpCode = GDT_RELEASE_DRV; 20108c2ecf20Sopenharmony_ci else if (scp->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { 20118c2ecf20Sopenharmony_ci if (scp->cmnd[4] & 1) /* prevent ? */ 20128c2ecf20Sopenharmony_ci cmdp->OpCode = GDT_MOUNT; 20138c2ecf20Sopenharmony_ci else if (scp->cmnd[3] & 1) /* removable drive ? */ 20148c2ecf20Sopenharmony_ci cmdp->OpCode = GDT_UNMOUNT; 20158c2ecf20Sopenharmony_ci else 20168c2ecf20Sopenharmony_ci cmdp->OpCode = GDT_FLUSH; 20178c2ecf20Sopenharmony_ci } else if (scp->cmnd[0] == WRITE_6 || scp->cmnd[0] == WRITE_10 || 20188c2ecf20Sopenharmony_ci scp->cmnd[0] == WRITE_12 || scp->cmnd[0] == WRITE_16 20198c2ecf20Sopenharmony_ci ) { 20208c2ecf20Sopenharmony_ci read_write = 1; 20218c2ecf20Sopenharmony_ci if (gdth_write_through || ((ha->hdr[hdrive].rw_attribs & 1) && 20228c2ecf20Sopenharmony_ci (ha->cache_feat & GDT_WR_THROUGH))) 20238c2ecf20Sopenharmony_ci cmdp->OpCode = GDT_WRITE_THR; 20248c2ecf20Sopenharmony_ci else 20258c2ecf20Sopenharmony_ci cmdp->OpCode = GDT_WRITE; 20268c2ecf20Sopenharmony_ci } else { 20278c2ecf20Sopenharmony_ci read_write = 2; 20288c2ecf20Sopenharmony_ci cmdp->OpCode = GDT_READ; 20298c2ecf20Sopenharmony_ci } 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci cmdp->BoardNode = LOCALBOARD; 20328c2ecf20Sopenharmony_ci if (mode64) { 20338c2ecf20Sopenharmony_ci cmdp->u.cache64.DeviceNo = hdrive; 20348c2ecf20Sopenharmony_ci cmdp->u.cache64.BlockNo = 1; 20358c2ecf20Sopenharmony_ci cmdp->u.cache64.sg_canz = 0; 20368c2ecf20Sopenharmony_ci } else { 20378c2ecf20Sopenharmony_ci cmdp->u.cache.DeviceNo = hdrive; 20388c2ecf20Sopenharmony_ci cmdp->u.cache.BlockNo = 1; 20398c2ecf20Sopenharmony_ci cmdp->u.cache.sg_canz = 0; 20408c2ecf20Sopenharmony_ci } 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci if (read_write) { 20438c2ecf20Sopenharmony_ci if (scp->cmd_len == 16) { 20448c2ecf20Sopenharmony_ci memcpy(&no, &scp->cmnd[2], sizeof(u64)); 20458c2ecf20Sopenharmony_ci blockno = be64_to_cpu(no); 20468c2ecf20Sopenharmony_ci memcpy(&cnt, &scp->cmnd[10], sizeof(u32)); 20478c2ecf20Sopenharmony_ci blockcnt = be32_to_cpu(cnt); 20488c2ecf20Sopenharmony_ci } else if (scp->cmd_len == 10) { 20498c2ecf20Sopenharmony_ci memcpy(&no, &scp->cmnd[2], sizeof(u32)); 20508c2ecf20Sopenharmony_ci blockno = be32_to_cpu(no); 20518c2ecf20Sopenharmony_ci memcpy(&cnt, &scp->cmnd[7], sizeof(u16)); 20528c2ecf20Sopenharmony_ci blockcnt = be16_to_cpu(cnt); 20538c2ecf20Sopenharmony_ci } else { 20548c2ecf20Sopenharmony_ci memcpy(&no, &scp->cmnd[0], sizeof(u32)); 20558c2ecf20Sopenharmony_ci blockno = be32_to_cpu(no) & 0x001fffffUL; 20568c2ecf20Sopenharmony_ci blockcnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4]; 20578c2ecf20Sopenharmony_ci } 20588c2ecf20Sopenharmony_ci if (mode64) { 20598c2ecf20Sopenharmony_ci cmdp->u.cache64.BlockNo = blockno; 20608c2ecf20Sopenharmony_ci cmdp->u.cache64.BlockCnt = blockcnt; 20618c2ecf20Sopenharmony_ci } else { 20628c2ecf20Sopenharmony_ci cmdp->u.cache.BlockNo = (u32)blockno; 20638c2ecf20Sopenharmony_ci cmdp->u.cache.BlockCnt = blockcnt; 20648c2ecf20Sopenharmony_ci } 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci if (scsi_bufflen(scp)) { 20678c2ecf20Sopenharmony_ci cmndinfo->dma_dir = (read_write == 1 ? 20688c2ecf20Sopenharmony_ci DMA_TO_DEVICE : DMA_FROM_DEVICE); 20698c2ecf20Sopenharmony_ci sgcnt = dma_map_sg(&ha->pdev->dev, scsi_sglist(scp), 20708c2ecf20Sopenharmony_ci scsi_sg_count(scp), cmndinfo->dma_dir); 20718c2ecf20Sopenharmony_ci if (mode64) { 20728c2ecf20Sopenharmony_ci struct scatterlist *sl; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci cmdp->u.cache64.DestAddr= (u64)-1; 20758c2ecf20Sopenharmony_ci cmdp->u.cache64.sg_canz = sgcnt; 20768c2ecf20Sopenharmony_ci scsi_for_each_sg(scp, sl, sgcnt, i) { 20778c2ecf20Sopenharmony_ci cmdp->u.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl); 20788c2ecf20Sopenharmony_ci cmdp->u.cache64.sg_lst[i].sg_len = sg_dma_len(sl); 20798c2ecf20Sopenharmony_ci } 20808c2ecf20Sopenharmony_ci } else { 20818c2ecf20Sopenharmony_ci struct scatterlist *sl; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci cmdp->u.cache.DestAddr= 0xffffffff; 20848c2ecf20Sopenharmony_ci cmdp->u.cache.sg_canz = sgcnt; 20858c2ecf20Sopenharmony_ci scsi_for_each_sg(scp, sl, sgcnt, i) { 20868c2ecf20Sopenharmony_ci cmdp->u.cache.sg_lst[i].sg_ptr = sg_dma_address(sl); 20878c2ecf20Sopenharmony_ci cmdp->u.cache.sg_lst[i].sg_len = sg_dma_len(sl); 20888c2ecf20Sopenharmony_ci } 20898c2ecf20Sopenharmony_ci } 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci#ifdef GDTH_STATISTICS 20928c2ecf20Sopenharmony_ci if (max_sg < (u32)sgcnt) { 20938c2ecf20Sopenharmony_ci max_sg = (u32)sgcnt; 20948c2ecf20Sopenharmony_ci TRACE3(("GDT: max_sg = %d\n",max_sg)); 20958c2ecf20Sopenharmony_ci } 20968c2ecf20Sopenharmony_ci#endif 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci } 20998c2ecf20Sopenharmony_ci } 21008c2ecf20Sopenharmony_ci /* evaluate command size, check space */ 21018c2ecf20Sopenharmony_ci if (mode64) { 21028c2ecf20Sopenharmony_ci TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", 21038c2ecf20Sopenharmony_ci cmdp->u.cache64.DestAddr,cmdp->u.cache64.sg_canz, 21048c2ecf20Sopenharmony_ci cmdp->u.cache64.sg_lst[0].sg_ptr, 21058c2ecf20Sopenharmony_ci cmdp->u.cache64.sg_lst[0].sg_len)); 21068c2ecf20Sopenharmony_ci TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n", 21078c2ecf20Sopenharmony_ci cmdp->OpCode,cmdp->u.cache64.BlockNo,cmdp->u.cache64.BlockCnt)); 21088c2ecf20Sopenharmony_ci ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) + 21098c2ecf20Sopenharmony_ci (u16)cmdp->u.cache64.sg_canz * sizeof(gdth_sg64_str); 21108c2ecf20Sopenharmony_ci } else { 21118c2ecf20Sopenharmony_ci TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", 21128c2ecf20Sopenharmony_ci cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz, 21138c2ecf20Sopenharmony_ci cmdp->u.cache.sg_lst[0].sg_ptr, 21148c2ecf20Sopenharmony_ci cmdp->u.cache.sg_lst[0].sg_len)); 21158c2ecf20Sopenharmony_ci TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n", 21168c2ecf20Sopenharmony_ci cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt)); 21178c2ecf20Sopenharmony_ci ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + 21188c2ecf20Sopenharmony_ci (u16)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str); 21198c2ecf20Sopenharmony_ci } 21208c2ecf20Sopenharmony_ci if (ha->cmd_len & 3) 21218c2ecf20Sopenharmony_ci ha->cmd_len += (4 - (ha->cmd_len & 3)); 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci if (ha->cmd_cnt > 0) { 21248c2ecf20Sopenharmony_ci if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) > 21258c2ecf20Sopenharmony_ci ha->ic_all_size) { 21268c2ecf20Sopenharmony_ci TRACE2(("gdth_fill_cache() DPMEM overflow\n")); 21278c2ecf20Sopenharmony_ci ha->cmd_tab[cmd_index-2].cmnd = UNUSED_CMND; 21288c2ecf20Sopenharmony_ci return 0; 21298c2ecf20Sopenharmony_ci } 21308c2ecf20Sopenharmony_ci } 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci /* copy command */ 21338c2ecf20Sopenharmony_ci gdth_copy_command(ha); 21348c2ecf20Sopenharmony_ci return cmd_index; 21358c2ecf20Sopenharmony_ci} 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_cistatic int gdth_fill_raw_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp, u8 b) 21388c2ecf20Sopenharmony_ci{ 21398c2ecf20Sopenharmony_ci register gdth_cmd_str *cmdp; 21408c2ecf20Sopenharmony_ci u16 i; 21418c2ecf20Sopenharmony_ci dma_addr_t sense_paddr; 21428c2ecf20Sopenharmony_ci int cmd_index, sgcnt, mode64; 21438c2ecf20Sopenharmony_ci u8 t,l; 21448c2ecf20Sopenharmony_ci struct gdth_cmndinfo *cmndinfo; 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci t = scp->device->id; 21478c2ecf20Sopenharmony_ci l = scp->device->lun; 21488c2ecf20Sopenharmony_ci cmdp = ha->pccb; 21498c2ecf20Sopenharmony_ci TRACE(("gdth_fill_raw_cmd() cmd 0x%x bus %d ID %d LUN %d\n", 21508c2ecf20Sopenharmony_ci scp->cmnd[0],b,t,l)); 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci mode64 = (ha->raw_feat & GDT_64BIT) ? TRUE : FALSE; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci cmdp->Service = SCSIRAWSERVICE; 21558c2ecf20Sopenharmony_ci cmdp->RequestBuffer = scp; 21568c2ecf20Sopenharmony_ci /* search free command index */ 21578c2ecf20Sopenharmony_ci if (!(cmd_index=gdth_get_cmd_index(ha))) { 21588c2ecf20Sopenharmony_ci TRACE(("GDT: No free command index found\n")); 21598c2ecf20Sopenharmony_ci return 0; 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci /* if it's the first command, set command semaphore */ 21628c2ecf20Sopenharmony_ci if (ha->cmd_cnt == 0) 21638c2ecf20Sopenharmony_ci gdth_set_sema0(ha); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci cmndinfo = gdth_cmnd_priv(scp); 21668c2ecf20Sopenharmony_ci /* fill command */ 21678c2ecf20Sopenharmony_ci if (cmndinfo->OpCode != -1) { 21688c2ecf20Sopenharmony_ci cmdp->OpCode = cmndinfo->OpCode; /* special raw cmd. */ 21698c2ecf20Sopenharmony_ci cmdp->BoardNode = LOCALBOARD; 21708c2ecf20Sopenharmony_ci if (mode64) { 21718c2ecf20Sopenharmony_ci cmdp->u.raw64.direction = (cmndinfo->phase >> 8); 21728c2ecf20Sopenharmony_ci TRACE2(("special raw cmd 0x%x param 0x%x\n", 21738c2ecf20Sopenharmony_ci cmdp->OpCode, cmdp->u.raw64.direction)); 21748c2ecf20Sopenharmony_ci /* evaluate command size */ 21758c2ecf20Sopenharmony_ci ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst); 21768c2ecf20Sopenharmony_ci } else { 21778c2ecf20Sopenharmony_ci cmdp->u.raw.direction = (cmndinfo->phase >> 8); 21788c2ecf20Sopenharmony_ci TRACE2(("special raw cmd 0x%x param 0x%x\n", 21798c2ecf20Sopenharmony_ci cmdp->OpCode, cmdp->u.raw.direction)); 21808c2ecf20Sopenharmony_ci /* evaluate command size */ 21818c2ecf20Sopenharmony_ci ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst); 21828c2ecf20Sopenharmony_ci } 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci } else { 21858c2ecf20Sopenharmony_ci sense_paddr = dma_map_single(&ha->pdev->dev, scp->sense_buffer, 16, 21868c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci cmndinfo->sense_paddr = sense_paddr; 21898c2ecf20Sopenharmony_ci cmdp->OpCode = GDT_WRITE; /* always */ 21908c2ecf20Sopenharmony_ci cmdp->BoardNode = LOCALBOARD; 21918c2ecf20Sopenharmony_ci if (mode64) { 21928c2ecf20Sopenharmony_ci cmdp->u.raw64.reserved = 0; 21938c2ecf20Sopenharmony_ci cmdp->u.raw64.mdisc_time = 0; 21948c2ecf20Sopenharmony_ci cmdp->u.raw64.mcon_time = 0; 21958c2ecf20Sopenharmony_ci cmdp->u.raw64.clen = scp->cmd_len; 21968c2ecf20Sopenharmony_ci cmdp->u.raw64.target = t; 21978c2ecf20Sopenharmony_ci cmdp->u.raw64.lun = l; 21988c2ecf20Sopenharmony_ci cmdp->u.raw64.bus = b; 21998c2ecf20Sopenharmony_ci cmdp->u.raw64.priority = 0; 22008c2ecf20Sopenharmony_ci cmdp->u.raw64.sdlen = scsi_bufflen(scp); 22018c2ecf20Sopenharmony_ci cmdp->u.raw64.sense_len = 16; 22028c2ecf20Sopenharmony_ci cmdp->u.raw64.sense_data = sense_paddr; 22038c2ecf20Sopenharmony_ci cmdp->u.raw64.direction = 22048c2ecf20Sopenharmony_ci gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN; 22058c2ecf20Sopenharmony_ci memcpy(cmdp->u.raw64.cmd,scp->cmnd,16); 22068c2ecf20Sopenharmony_ci cmdp->u.raw64.sg_ranz = 0; 22078c2ecf20Sopenharmony_ci } else { 22088c2ecf20Sopenharmony_ci cmdp->u.raw.reserved = 0; 22098c2ecf20Sopenharmony_ci cmdp->u.raw.mdisc_time = 0; 22108c2ecf20Sopenharmony_ci cmdp->u.raw.mcon_time = 0; 22118c2ecf20Sopenharmony_ci cmdp->u.raw.clen = scp->cmd_len; 22128c2ecf20Sopenharmony_ci cmdp->u.raw.target = t; 22138c2ecf20Sopenharmony_ci cmdp->u.raw.lun = l; 22148c2ecf20Sopenharmony_ci cmdp->u.raw.bus = b; 22158c2ecf20Sopenharmony_ci cmdp->u.raw.priority = 0; 22168c2ecf20Sopenharmony_ci cmdp->u.raw.link_p = 0; 22178c2ecf20Sopenharmony_ci cmdp->u.raw.sdlen = scsi_bufflen(scp); 22188c2ecf20Sopenharmony_ci cmdp->u.raw.sense_len = 16; 22198c2ecf20Sopenharmony_ci cmdp->u.raw.sense_data = sense_paddr; 22208c2ecf20Sopenharmony_ci cmdp->u.raw.direction = 22218c2ecf20Sopenharmony_ci gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN; 22228c2ecf20Sopenharmony_ci memcpy(cmdp->u.raw.cmd,scp->cmnd,12); 22238c2ecf20Sopenharmony_ci cmdp->u.raw.sg_ranz = 0; 22248c2ecf20Sopenharmony_ci } 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci if (scsi_bufflen(scp)) { 22278c2ecf20Sopenharmony_ci cmndinfo->dma_dir = DMA_BIDIRECTIONAL; 22288c2ecf20Sopenharmony_ci sgcnt = dma_map_sg(&ha->pdev->dev, scsi_sglist(scp), 22298c2ecf20Sopenharmony_ci scsi_sg_count(scp), cmndinfo->dma_dir); 22308c2ecf20Sopenharmony_ci if (mode64) { 22318c2ecf20Sopenharmony_ci struct scatterlist *sl; 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci cmdp->u.raw64.sdata = (u64)-1; 22348c2ecf20Sopenharmony_ci cmdp->u.raw64.sg_ranz = sgcnt; 22358c2ecf20Sopenharmony_ci scsi_for_each_sg(scp, sl, sgcnt, i) { 22368c2ecf20Sopenharmony_ci cmdp->u.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl); 22378c2ecf20Sopenharmony_ci cmdp->u.raw64.sg_lst[i].sg_len = sg_dma_len(sl); 22388c2ecf20Sopenharmony_ci } 22398c2ecf20Sopenharmony_ci } else { 22408c2ecf20Sopenharmony_ci struct scatterlist *sl; 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci cmdp->u.raw.sdata = 0xffffffff; 22438c2ecf20Sopenharmony_ci cmdp->u.raw.sg_ranz = sgcnt; 22448c2ecf20Sopenharmony_ci scsi_for_each_sg(scp, sl, sgcnt, i) { 22458c2ecf20Sopenharmony_ci cmdp->u.raw.sg_lst[i].sg_ptr = sg_dma_address(sl); 22468c2ecf20Sopenharmony_ci cmdp->u.raw.sg_lst[i].sg_len = sg_dma_len(sl); 22478c2ecf20Sopenharmony_ci } 22488c2ecf20Sopenharmony_ci } 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci#ifdef GDTH_STATISTICS 22518c2ecf20Sopenharmony_ci if (max_sg < sgcnt) { 22528c2ecf20Sopenharmony_ci max_sg = sgcnt; 22538c2ecf20Sopenharmony_ci TRACE3(("GDT: max_sg = %d\n",sgcnt)); 22548c2ecf20Sopenharmony_ci } 22558c2ecf20Sopenharmony_ci#endif 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci } 22588c2ecf20Sopenharmony_ci if (mode64) { 22598c2ecf20Sopenharmony_ci TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", 22608c2ecf20Sopenharmony_ci cmdp->u.raw64.sdata,cmdp->u.raw64.sg_ranz, 22618c2ecf20Sopenharmony_ci cmdp->u.raw64.sg_lst[0].sg_ptr, 22628c2ecf20Sopenharmony_ci cmdp->u.raw64.sg_lst[0].sg_len)); 22638c2ecf20Sopenharmony_ci /* evaluate command size */ 22648c2ecf20Sopenharmony_ci ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) + 22658c2ecf20Sopenharmony_ci (u16)cmdp->u.raw64.sg_ranz * sizeof(gdth_sg64_str); 22668c2ecf20Sopenharmony_ci } else { 22678c2ecf20Sopenharmony_ci TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", 22688c2ecf20Sopenharmony_ci cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz, 22698c2ecf20Sopenharmony_ci cmdp->u.raw.sg_lst[0].sg_ptr, 22708c2ecf20Sopenharmony_ci cmdp->u.raw.sg_lst[0].sg_len)); 22718c2ecf20Sopenharmony_ci /* evaluate command size */ 22728c2ecf20Sopenharmony_ci ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + 22738c2ecf20Sopenharmony_ci (u16)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str); 22748c2ecf20Sopenharmony_ci } 22758c2ecf20Sopenharmony_ci } 22768c2ecf20Sopenharmony_ci /* check space */ 22778c2ecf20Sopenharmony_ci if (ha->cmd_len & 3) 22788c2ecf20Sopenharmony_ci ha->cmd_len += (4 - (ha->cmd_len & 3)); 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci if (ha->cmd_cnt > 0) { 22818c2ecf20Sopenharmony_ci if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) > 22828c2ecf20Sopenharmony_ci ha->ic_all_size) { 22838c2ecf20Sopenharmony_ci TRACE2(("gdth_fill_raw() DPMEM overflow\n")); 22848c2ecf20Sopenharmony_ci ha->cmd_tab[cmd_index-2].cmnd = UNUSED_CMND; 22858c2ecf20Sopenharmony_ci return 0; 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci } 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci /* copy command */ 22908c2ecf20Sopenharmony_ci gdth_copy_command(ha); 22918c2ecf20Sopenharmony_ci return cmd_index; 22928c2ecf20Sopenharmony_ci} 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_cistatic int gdth_special_cmd(gdth_ha_str *ha, struct scsi_cmnd *scp) 22958c2ecf20Sopenharmony_ci{ 22968c2ecf20Sopenharmony_ci register gdth_cmd_str *cmdp; 22978c2ecf20Sopenharmony_ci struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); 22988c2ecf20Sopenharmony_ci int cmd_index; 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci cmdp= ha->pccb; 23018c2ecf20Sopenharmony_ci TRACE2(("gdth_special_cmd(): ")); 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci *cmdp = *cmndinfo->internal_cmd_str; 23048c2ecf20Sopenharmony_ci cmdp->RequestBuffer = scp; 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci /* search free command index */ 23078c2ecf20Sopenharmony_ci if (!(cmd_index=gdth_get_cmd_index(ha))) { 23088c2ecf20Sopenharmony_ci TRACE(("GDT: No free command index found\n")); 23098c2ecf20Sopenharmony_ci return 0; 23108c2ecf20Sopenharmony_ci } 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci /* if it's the first command, set command semaphore */ 23138c2ecf20Sopenharmony_ci if (ha->cmd_cnt == 0) 23148c2ecf20Sopenharmony_ci gdth_set_sema0(ha); 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci /* evaluate command size, check space */ 23178c2ecf20Sopenharmony_ci if (cmdp->OpCode == GDT_IOCTL) { 23188c2ecf20Sopenharmony_ci TRACE2(("IOCTL\n")); 23198c2ecf20Sopenharmony_ci ha->cmd_len = 23208c2ecf20Sopenharmony_ci GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(u64); 23218c2ecf20Sopenharmony_ci } else if (cmdp->Service == CACHESERVICE) { 23228c2ecf20Sopenharmony_ci TRACE2(("cache command %d\n",cmdp->OpCode)); 23238c2ecf20Sopenharmony_ci if (ha->cache_feat & GDT_64BIT) 23248c2ecf20Sopenharmony_ci ha->cmd_len = 23258c2ecf20Sopenharmony_ci GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) + sizeof(gdth_sg64_str); 23268c2ecf20Sopenharmony_ci else 23278c2ecf20Sopenharmony_ci ha->cmd_len = 23288c2ecf20Sopenharmony_ci GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + sizeof(gdth_sg_str); 23298c2ecf20Sopenharmony_ci } else if (cmdp->Service == SCSIRAWSERVICE) { 23308c2ecf20Sopenharmony_ci TRACE2(("raw command %d\n",cmdp->OpCode)); 23318c2ecf20Sopenharmony_ci if (ha->raw_feat & GDT_64BIT) 23328c2ecf20Sopenharmony_ci ha->cmd_len = 23338c2ecf20Sopenharmony_ci GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) + sizeof(gdth_sg64_str); 23348c2ecf20Sopenharmony_ci else 23358c2ecf20Sopenharmony_ci ha->cmd_len = 23368c2ecf20Sopenharmony_ci GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + sizeof(gdth_sg_str); 23378c2ecf20Sopenharmony_ci } 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci if (ha->cmd_len & 3) 23408c2ecf20Sopenharmony_ci ha->cmd_len += (4 - (ha->cmd_len & 3)); 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci if (ha->cmd_cnt > 0) { 23438c2ecf20Sopenharmony_ci if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) > 23448c2ecf20Sopenharmony_ci ha->ic_all_size) { 23458c2ecf20Sopenharmony_ci TRACE2(("gdth_special_cmd() DPMEM overflow\n")); 23468c2ecf20Sopenharmony_ci ha->cmd_tab[cmd_index-2].cmnd = UNUSED_CMND; 23478c2ecf20Sopenharmony_ci return 0; 23488c2ecf20Sopenharmony_ci } 23498c2ecf20Sopenharmony_ci } 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci /* copy command */ 23528c2ecf20Sopenharmony_ci gdth_copy_command(ha); 23538c2ecf20Sopenharmony_ci return cmd_index; 23548c2ecf20Sopenharmony_ci} 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci/* Controller event handling functions */ 23588c2ecf20Sopenharmony_cistatic gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source, 23598c2ecf20Sopenharmony_ci u16 idx, gdth_evt_data *evt) 23608c2ecf20Sopenharmony_ci{ 23618c2ecf20Sopenharmony_ci gdth_evt_str *e; 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci /* no GDTH_LOCK_HA() ! */ 23648c2ecf20Sopenharmony_ci TRACE2(("gdth_store_event() source %d idx %d\n", source, idx)); 23658c2ecf20Sopenharmony_ci if (source == 0) /* no source -> no event */ 23668c2ecf20Sopenharmony_ci return NULL; 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci if (ebuffer[elastidx].event_source == source && 23698c2ecf20Sopenharmony_ci ebuffer[elastidx].event_idx == idx && 23708c2ecf20Sopenharmony_ci ((evt->size != 0 && ebuffer[elastidx].event_data.size != 0 && 23718c2ecf20Sopenharmony_ci !memcmp((char *)&ebuffer[elastidx].event_data.eu, 23728c2ecf20Sopenharmony_ci (char *)&evt->eu, evt->size)) || 23738c2ecf20Sopenharmony_ci (evt->size == 0 && ebuffer[elastidx].event_data.size == 0 && 23748c2ecf20Sopenharmony_ci !strcmp((char *)&ebuffer[elastidx].event_data.event_string, 23758c2ecf20Sopenharmony_ci (char *)&evt->event_string)))) { 23768c2ecf20Sopenharmony_ci e = &ebuffer[elastidx]; 23778c2ecf20Sopenharmony_ci e->last_stamp = (u32)ktime_get_real_seconds(); 23788c2ecf20Sopenharmony_ci ++e->same_count; 23798c2ecf20Sopenharmony_ci } else { 23808c2ecf20Sopenharmony_ci if (ebuffer[elastidx].event_source != 0) { /* entry not free ? */ 23818c2ecf20Sopenharmony_ci ++elastidx; 23828c2ecf20Sopenharmony_ci if (elastidx == MAX_EVENTS) 23838c2ecf20Sopenharmony_ci elastidx = 0; 23848c2ecf20Sopenharmony_ci if (elastidx == eoldidx) { /* reached mark ? */ 23858c2ecf20Sopenharmony_ci ++eoldidx; 23868c2ecf20Sopenharmony_ci if (eoldidx == MAX_EVENTS) 23878c2ecf20Sopenharmony_ci eoldidx = 0; 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci } 23908c2ecf20Sopenharmony_ci e = &ebuffer[elastidx]; 23918c2ecf20Sopenharmony_ci e->event_source = source; 23928c2ecf20Sopenharmony_ci e->event_idx = idx; 23938c2ecf20Sopenharmony_ci e->first_stamp = e->last_stamp = (u32)ktime_get_real_seconds(); 23948c2ecf20Sopenharmony_ci e->same_count = 1; 23958c2ecf20Sopenharmony_ci e->event_data = *evt; 23968c2ecf20Sopenharmony_ci e->application = 0; 23978c2ecf20Sopenharmony_ci } 23988c2ecf20Sopenharmony_ci return e; 23998c2ecf20Sopenharmony_ci} 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_cistatic int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr) 24028c2ecf20Sopenharmony_ci{ 24038c2ecf20Sopenharmony_ci gdth_evt_str *e; 24048c2ecf20Sopenharmony_ci int eindex; 24058c2ecf20Sopenharmony_ci unsigned long flags; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci TRACE2(("gdth_read_event() handle %d\n", handle)); 24088c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 24098c2ecf20Sopenharmony_ci if (handle == -1) 24108c2ecf20Sopenharmony_ci eindex = eoldidx; 24118c2ecf20Sopenharmony_ci else 24128c2ecf20Sopenharmony_ci eindex = handle; 24138c2ecf20Sopenharmony_ci estr->event_source = 0; 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci if (eindex < 0 || eindex >= MAX_EVENTS) { 24168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 24178c2ecf20Sopenharmony_ci return eindex; 24188c2ecf20Sopenharmony_ci } 24198c2ecf20Sopenharmony_ci e = &ebuffer[eindex]; 24208c2ecf20Sopenharmony_ci if (e->event_source != 0) { 24218c2ecf20Sopenharmony_ci if (eindex != elastidx) { 24228c2ecf20Sopenharmony_ci if (++eindex == MAX_EVENTS) 24238c2ecf20Sopenharmony_ci eindex = 0; 24248c2ecf20Sopenharmony_ci } else { 24258c2ecf20Sopenharmony_ci eindex = -1; 24268c2ecf20Sopenharmony_ci } 24278c2ecf20Sopenharmony_ci memcpy(estr, e, sizeof(gdth_evt_str)); 24288c2ecf20Sopenharmony_ci } 24298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 24308c2ecf20Sopenharmony_ci return eindex; 24318c2ecf20Sopenharmony_ci} 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_cistatic void gdth_readapp_event(gdth_ha_str *ha, 24348c2ecf20Sopenharmony_ci u8 application, gdth_evt_str *estr) 24358c2ecf20Sopenharmony_ci{ 24368c2ecf20Sopenharmony_ci gdth_evt_str *e; 24378c2ecf20Sopenharmony_ci int eindex; 24388c2ecf20Sopenharmony_ci unsigned long flags; 24398c2ecf20Sopenharmony_ci u8 found = FALSE; 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci TRACE2(("gdth_readapp_event() app. %d\n", application)); 24428c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 24438c2ecf20Sopenharmony_ci eindex = eoldidx; 24448c2ecf20Sopenharmony_ci for (;;) { 24458c2ecf20Sopenharmony_ci e = &ebuffer[eindex]; 24468c2ecf20Sopenharmony_ci if (e->event_source == 0) 24478c2ecf20Sopenharmony_ci break; 24488c2ecf20Sopenharmony_ci if ((e->application & application) == 0) { 24498c2ecf20Sopenharmony_ci e->application |= application; 24508c2ecf20Sopenharmony_ci found = TRUE; 24518c2ecf20Sopenharmony_ci break; 24528c2ecf20Sopenharmony_ci } 24538c2ecf20Sopenharmony_ci if (eindex == elastidx) 24548c2ecf20Sopenharmony_ci break; 24558c2ecf20Sopenharmony_ci if (++eindex == MAX_EVENTS) 24568c2ecf20Sopenharmony_ci eindex = 0; 24578c2ecf20Sopenharmony_ci } 24588c2ecf20Sopenharmony_ci if (found) 24598c2ecf20Sopenharmony_ci memcpy(estr, e, sizeof(gdth_evt_str)); 24608c2ecf20Sopenharmony_ci else 24618c2ecf20Sopenharmony_ci estr->event_source = 0; 24628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 24638c2ecf20Sopenharmony_ci} 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_cistatic void gdth_clear_events(void) 24668c2ecf20Sopenharmony_ci{ 24678c2ecf20Sopenharmony_ci TRACE(("gdth_clear_events()")); 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci eoldidx = elastidx = 0; 24708c2ecf20Sopenharmony_ci ebuffer[0].event_source = 0; 24718c2ecf20Sopenharmony_ci} 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci/* SCSI interface functions */ 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_cistatic irqreturn_t __gdth_interrupt(gdth_ha_str *ha, 24778c2ecf20Sopenharmony_ci int gdth_from_wait, int* pIndex) 24788c2ecf20Sopenharmony_ci{ 24798c2ecf20Sopenharmony_ci gdt6m_dpram_str __iomem *dp6m_ptr = NULL; 24808c2ecf20Sopenharmony_ci gdt6_dpram_str __iomem *dp6_ptr; 24818c2ecf20Sopenharmony_ci struct scsi_cmnd *scp; 24828c2ecf20Sopenharmony_ci int rval, i; 24838c2ecf20Sopenharmony_ci u8 IStatus; 24848c2ecf20Sopenharmony_ci u16 Service; 24858c2ecf20Sopenharmony_ci unsigned long flags = 0; 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci TRACE(("gdth_interrupt() IRQ %d\n", ha->irq)); 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci /* if polling and not from gdth_wait() -> return */ 24908c2ecf20Sopenharmony_ci if (gdth_polling) { 24918c2ecf20Sopenharmony_ci if (!gdth_from_wait) { 24928c2ecf20Sopenharmony_ci return IRQ_HANDLED; 24938c2ecf20Sopenharmony_ci } 24948c2ecf20Sopenharmony_ci } 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci if (!gdth_polling) 24978c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci /* search controller */ 25008c2ecf20Sopenharmony_ci IStatus = gdth_get_status(ha); 25018c2ecf20Sopenharmony_ci if (IStatus == 0) { 25028c2ecf20Sopenharmony_ci /* spurious interrupt */ 25038c2ecf20Sopenharmony_ci if (!gdth_polling) 25048c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 25058c2ecf20Sopenharmony_ci return IRQ_HANDLED; 25068c2ecf20Sopenharmony_ci } 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci#ifdef GDTH_STATISTICS 25098c2ecf20Sopenharmony_ci ++act_ints; 25108c2ecf20Sopenharmony_ci#endif 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci if (ha->type == GDT_PCI) { 25138c2ecf20Sopenharmony_ci dp6_ptr = ha->brd; 25148c2ecf20Sopenharmony_ci if (IStatus & 0x80) { /* error flag */ 25158c2ecf20Sopenharmony_ci IStatus &= ~0x80; 25168c2ecf20Sopenharmony_ci ha->status = readw(&dp6_ptr->u.ic.Status); 25178c2ecf20Sopenharmony_ci TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); 25188c2ecf20Sopenharmony_ci } else /* no error */ 25198c2ecf20Sopenharmony_ci ha->status = S_OK; 25208c2ecf20Sopenharmony_ci ha->info = readl(&dp6_ptr->u.ic.Info[0]); 25218c2ecf20Sopenharmony_ci ha->service = readw(&dp6_ptr->u.ic.Service); 25228c2ecf20Sopenharmony_ci ha->info2 = readl(&dp6_ptr->u.ic.Info[1]); 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */ 25258c2ecf20Sopenharmony_ci writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */ 25268c2ecf20Sopenharmony_ci writeb(0, &dp6_ptr->io.Sema1); /* reset status semaphore */ 25278c2ecf20Sopenharmony_ci } else if (ha->type == GDT_PCINEW) { 25288c2ecf20Sopenharmony_ci if (IStatus & 0x80) { /* error flag */ 25298c2ecf20Sopenharmony_ci IStatus &= ~0x80; 25308c2ecf20Sopenharmony_ci ha->status = inw(PTR2USHORT(&ha->plx->status)); 25318c2ecf20Sopenharmony_ci TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); 25328c2ecf20Sopenharmony_ci } else 25338c2ecf20Sopenharmony_ci ha->status = S_OK; 25348c2ecf20Sopenharmony_ci ha->info = inl(PTR2USHORT(&ha->plx->info[0])); 25358c2ecf20Sopenharmony_ci ha->service = inw(PTR2USHORT(&ha->plx->service)); 25368c2ecf20Sopenharmony_ci ha->info2 = inl(PTR2USHORT(&ha->plx->info[1])); 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); 25398c2ecf20Sopenharmony_ci outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); 25408c2ecf20Sopenharmony_ci } else if (ha->type == GDT_PCIMPR) { 25418c2ecf20Sopenharmony_ci dp6m_ptr = ha->brd; 25428c2ecf20Sopenharmony_ci if (IStatus & 0x80) { /* error flag */ 25438c2ecf20Sopenharmony_ci IStatus &= ~0x80; 25448c2ecf20Sopenharmony_ci ha->status = readw(&dp6m_ptr->i960r.status); 25458c2ecf20Sopenharmony_ci TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); 25468c2ecf20Sopenharmony_ci } else /* no error */ 25478c2ecf20Sopenharmony_ci ha->status = S_OK; 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci ha->info = readl(&dp6m_ptr->i960r.info[0]); 25508c2ecf20Sopenharmony_ci ha->service = readw(&dp6m_ptr->i960r.service); 25518c2ecf20Sopenharmony_ci ha->info2 = readl(&dp6m_ptr->i960r.info[1]); 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci /* event string */ 25548c2ecf20Sopenharmony_ci if (IStatus == ASYNCINDEX) { 25558c2ecf20Sopenharmony_ci if (ha->service != SCREENSERVICE && 25568c2ecf20Sopenharmony_ci (ha->fw_vers & 0xff) >= 0x1a) { 25578c2ecf20Sopenharmony_ci ha->dvr.severity = readb 25588c2ecf20Sopenharmony_ci (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.severity); 25598c2ecf20Sopenharmony_ci for (i = 0; i < 256; ++i) { 25608c2ecf20Sopenharmony_ci ha->dvr.event_string[i] = readb 25618c2ecf20Sopenharmony_ci (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.evt_str[i]); 25628c2ecf20Sopenharmony_ci if (ha->dvr.event_string[i] == 0) 25638c2ecf20Sopenharmony_ci break; 25648c2ecf20Sopenharmony_ci } 25658c2ecf20Sopenharmony_ci } 25668c2ecf20Sopenharmony_ci } 25678c2ecf20Sopenharmony_ci writeb(0xff, &dp6m_ptr->i960r.edoor_reg); 25688c2ecf20Sopenharmony_ci writeb(0, &dp6m_ptr->i960r.sema1_reg); 25698c2ecf20Sopenharmony_ci } else { 25708c2ecf20Sopenharmony_ci TRACE2(("gdth_interrupt() unknown controller type\n")); 25718c2ecf20Sopenharmony_ci if (!gdth_polling) 25728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 25738c2ecf20Sopenharmony_ci return IRQ_HANDLED; 25748c2ecf20Sopenharmony_ci } 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci TRACE(("gdth_interrupt() index %d stat %d info %d\n", 25778c2ecf20Sopenharmony_ci IStatus,ha->status,ha->info)); 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci if (gdth_from_wait) { 25808c2ecf20Sopenharmony_ci *pIndex = (int)IStatus; 25818c2ecf20Sopenharmony_ci } 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci if (IStatus == ASYNCINDEX) { 25848c2ecf20Sopenharmony_ci TRACE2(("gdth_interrupt() async. event\n")); 25858c2ecf20Sopenharmony_ci gdth_async_event(ha); 25868c2ecf20Sopenharmony_ci if (!gdth_polling) 25878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 25888c2ecf20Sopenharmony_ci gdth_next(ha); 25898c2ecf20Sopenharmony_ci return IRQ_HANDLED; 25908c2ecf20Sopenharmony_ci } 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci if (IStatus == SPEZINDEX) { 25938c2ecf20Sopenharmony_ci TRACE2(("Service unknown or not initialized !\n")); 25948c2ecf20Sopenharmony_ci ha->dvr.size = sizeof(ha->dvr.eu.driver); 25958c2ecf20Sopenharmony_ci ha->dvr.eu.driver.ionode = ha->hanum; 25968c2ecf20Sopenharmony_ci gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr); 25978c2ecf20Sopenharmony_ci if (!gdth_polling) 25988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 25998c2ecf20Sopenharmony_ci return IRQ_HANDLED; 26008c2ecf20Sopenharmony_ci } 26018c2ecf20Sopenharmony_ci scp = ha->cmd_tab[IStatus-2].cmnd; 26028c2ecf20Sopenharmony_ci Service = ha->cmd_tab[IStatus-2].service; 26038c2ecf20Sopenharmony_ci ha->cmd_tab[IStatus-2].cmnd = UNUSED_CMND; 26048c2ecf20Sopenharmony_ci if (scp == UNUSED_CMND) { 26058c2ecf20Sopenharmony_ci TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus)); 26068c2ecf20Sopenharmony_ci ha->dvr.size = sizeof(ha->dvr.eu.driver); 26078c2ecf20Sopenharmony_ci ha->dvr.eu.driver.ionode = ha->hanum; 26088c2ecf20Sopenharmony_ci ha->dvr.eu.driver.index = IStatus; 26098c2ecf20Sopenharmony_ci gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr); 26108c2ecf20Sopenharmony_ci if (!gdth_polling) 26118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 26128c2ecf20Sopenharmony_ci return IRQ_HANDLED; 26138c2ecf20Sopenharmony_ci } 26148c2ecf20Sopenharmony_ci if (scp == INTERNAL_CMND) { 26158c2ecf20Sopenharmony_ci TRACE(("gdth_interrupt() answer to internal command\n")); 26168c2ecf20Sopenharmony_ci if (!gdth_polling) 26178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 26188c2ecf20Sopenharmony_ci return IRQ_HANDLED; 26198c2ecf20Sopenharmony_ci } 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci TRACE(("gdth_interrupt() sync. status\n")); 26228c2ecf20Sopenharmony_ci rval = gdth_sync_event(ha,Service,IStatus,scp); 26238c2ecf20Sopenharmony_ci if (!gdth_polling) 26248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 26258c2ecf20Sopenharmony_ci if (rval == 2) { 26268c2ecf20Sopenharmony_ci gdth_putq(ha, scp, gdth_cmnd_priv(scp)->priority); 26278c2ecf20Sopenharmony_ci } else if (rval == 1) { 26288c2ecf20Sopenharmony_ci gdth_scsi_done(scp); 26298c2ecf20Sopenharmony_ci } 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci gdth_next(ha); 26328c2ecf20Sopenharmony_ci return IRQ_HANDLED; 26338c2ecf20Sopenharmony_ci} 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_cistatic irqreturn_t gdth_interrupt(int irq, void *dev_id) 26368c2ecf20Sopenharmony_ci{ 26378c2ecf20Sopenharmony_ci gdth_ha_str *ha = dev_id; 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci return __gdth_interrupt(ha, false, NULL); 26408c2ecf20Sopenharmony_ci} 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_cistatic int gdth_sync_event(gdth_ha_str *ha, int service, u8 index, 26438c2ecf20Sopenharmony_ci struct scsi_cmnd *scp) 26448c2ecf20Sopenharmony_ci{ 26458c2ecf20Sopenharmony_ci gdth_msg_str *msg; 26468c2ecf20Sopenharmony_ci gdth_cmd_str *cmdp; 26478c2ecf20Sopenharmony_ci u8 b, t; 26488c2ecf20Sopenharmony_ci struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci cmdp = ha->pccb; 26518c2ecf20Sopenharmony_ci TRACE(("gdth_sync_event() serv %d status %d\n", 26528c2ecf20Sopenharmony_ci service,ha->status)); 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci if (service == SCREENSERVICE) { 26558c2ecf20Sopenharmony_ci msg = ha->pmsg; 26568c2ecf20Sopenharmony_ci TRACE(("len: %d, answer: %d, ext: %d, alen: %d\n", 26578c2ecf20Sopenharmony_ci msg->msg_len,msg->msg_answer,msg->msg_ext,msg->msg_alen)); 26588c2ecf20Sopenharmony_ci if (msg->msg_len > MSGLEN+1) 26598c2ecf20Sopenharmony_ci msg->msg_len = MSGLEN+1; 26608c2ecf20Sopenharmony_ci if (msg->msg_len) 26618c2ecf20Sopenharmony_ci if (!(msg->msg_answer && msg->msg_ext)) { 26628c2ecf20Sopenharmony_ci msg->msg_text[msg->msg_len] = '\0'; 26638c2ecf20Sopenharmony_ci printk("%s",msg->msg_text); 26648c2ecf20Sopenharmony_ci } 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci if (msg->msg_ext && !msg->msg_answer) { 26678c2ecf20Sopenharmony_ci while (gdth_test_busy(ha)) 26688c2ecf20Sopenharmony_ci gdth_delay(0); 26698c2ecf20Sopenharmony_ci cmdp->Service = SCREENSERVICE; 26708c2ecf20Sopenharmony_ci cmdp->RequestBuffer = SCREEN_CMND; 26718c2ecf20Sopenharmony_ci gdth_get_cmd_index(ha); 26728c2ecf20Sopenharmony_ci gdth_set_sema0(ha); 26738c2ecf20Sopenharmony_ci cmdp->OpCode = GDT_READ; 26748c2ecf20Sopenharmony_ci cmdp->BoardNode = LOCALBOARD; 26758c2ecf20Sopenharmony_ci cmdp->u.screen.reserved = 0; 26768c2ecf20Sopenharmony_ci cmdp->u.screen.su.msg.msg_handle= msg->msg_handle; 26778c2ecf20Sopenharmony_ci cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; 26788c2ecf20Sopenharmony_ci ha->cmd_offs_dpmem = 0; 26798c2ecf20Sopenharmony_ci ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 26808c2ecf20Sopenharmony_ci + sizeof(u64); 26818c2ecf20Sopenharmony_ci ha->cmd_cnt = 0; 26828c2ecf20Sopenharmony_ci gdth_copy_command(ha); 26838c2ecf20Sopenharmony_ci gdth_release_event(ha); 26848c2ecf20Sopenharmony_ci return 0; 26858c2ecf20Sopenharmony_ci } 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci if (msg->msg_answer && msg->msg_alen) { 26888c2ecf20Sopenharmony_ci /* default answers (getchar() not possible) */ 26898c2ecf20Sopenharmony_ci if (msg->msg_alen == 1) { 26908c2ecf20Sopenharmony_ci msg->msg_alen = 0; 26918c2ecf20Sopenharmony_ci msg->msg_len = 1; 26928c2ecf20Sopenharmony_ci msg->msg_text[0] = 0; 26938c2ecf20Sopenharmony_ci } else { 26948c2ecf20Sopenharmony_ci msg->msg_alen -= 2; 26958c2ecf20Sopenharmony_ci msg->msg_len = 2; 26968c2ecf20Sopenharmony_ci msg->msg_text[0] = 1; 26978c2ecf20Sopenharmony_ci msg->msg_text[1] = 0; 26988c2ecf20Sopenharmony_ci } 26998c2ecf20Sopenharmony_ci msg->msg_ext = 0; 27008c2ecf20Sopenharmony_ci msg->msg_answer = 0; 27018c2ecf20Sopenharmony_ci while (gdth_test_busy(ha)) 27028c2ecf20Sopenharmony_ci gdth_delay(0); 27038c2ecf20Sopenharmony_ci cmdp->Service = SCREENSERVICE; 27048c2ecf20Sopenharmony_ci cmdp->RequestBuffer = SCREEN_CMND; 27058c2ecf20Sopenharmony_ci gdth_get_cmd_index(ha); 27068c2ecf20Sopenharmony_ci gdth_set_sema0(ha); 27078c2ecf20Sopenharmony_ci cmdp->OpCode = GDT_WRITE; 27088c2ecf20Sopenharmony_ci cmdp->BoardNode = LOCALBOARD; 27098c2ecf20Sopenharmony_ci cmdp->u.screen.reserved = 0; 27108c2ecf20Sopenharmony_ci cmdp->u.screen.su.msg.msg_handle= msg->msg_handle; 27118c2ecf20Sopenharmony_ci cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; 27128c2ecf20Sopenharmony_ci ha->cmd_offs_dpmem = 0; 27138c2ecf20Sopenharmony_ci ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 27148c2ecf20Sopenharmony_ci + sizeof(u64); 27158c2ecf20Sopenharmony_ci ha->cmd_cnt = 0; 27168c2ecf20Sopenharmony_ci gdth_copy_command(ha); 27178c2ecf20Sopenharmony_ci gdth_release_event(ha); 27188c2ecf20Sopenharmony_ci return 0; 27198c2ecf20Sopenharmony_ci } 27208c2ecf20Sopenharmony_ci printk("\n"); 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci } else { 27238c2ecf20Sopenharmony_ci b = scp->device->channel; 27248c2ecf20Sopenharmony_ci t = scp->device->id; 27258c2ecf20Sopenharmony_ci if (cmndinfo->OpCode == -1 && b != ha->virt_bus) { 27268c2ecf20Sopenharmony_ci ha->raw[BUS_L2P(ha,b)].io_cnt[t]--; 27278c2ecf20Sopenharmony_ci } 27288c2ecf20Sopenharmony_ci /* cache or raw service */ 27298c2ecf20Sopenharmony_ci if (ha->status == S_BSY) { 27308c2ecf20Sopenharmony_ci TRACE2(("Controller busy -> retry !\n")); 27318c2ecf20Sopenharmony_ci if (cmndinfo->OpCode == GDT_MOUNT) 27328c2ecf20Sopenharmony_ci cmndinfo->OpCode = GDT_CLUST_INFO; 27338c2ecf20Sopenharmony_ci /* retry */ 27348c2ecf20Sopenharmony_ci return 2; 27358c2ecf20Sopenharmony_ci } 27368c2ecf20Sopenharmony_ci if (scsi_bufflen(scp)) 27378c2ecf20Sopenharmony_ci dma_unmap_sg(&ha->pdev->dev, scsi_sglist(scp), scsi_sg_count(scp), 27388c2ecf20Sopenharmony_ci cmndinfo->dma_dir); 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci if (cmndinfo->sense_paddr) 27418c2ecf20Sopenharmony_ci dma_unmap_page(&ha->pdev->dev, cmndinfo->sense_paddr, 16, 27428c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci if (ha->status == S_OK) { 27458c2ecf20Sopenharmony_ci cmndinfo->status = S_OK; 27468c2ecf20Sopenharmony_ci cmndinfo->info = ha->info; 27478c2ecf20Sopenharmony_ci if (cmndinfo->OpCode != -1) { 27488c2ecf20Sopenharmony_ci TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n", 27498c2ecf20Sopenharmony_ci cmndinfo->OpCode)); 27508c2ecf20Sopenharmony_ci /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */ 27518c2ecf20Sopenharmony_ci if (cmndinfo->OpCode == GDT_CLUST_INFO) { 27528c2ecf20Sopenharmony_ci ha->hdr[t].cluster_type = (u8)ha->info; 27538c2ecf20Sopenharmony_ci if (!(ha->hdr[t].cluster_type & 27548c2ecf20Sopenharmony_ci CLUSTER_MOUNTED)) { 27558c2ecf20Sopenharmony_ci /* NOT MOUNTED -> MOUNT */ 27568c2ecf20Sopenharmony_ci cmndinfo->OpCode = GDT_MOUNT; 27578c2ecf20Sopenharmony_ci if (ha->hdr[t].cluster_type & 27588c2ecf20Sopenharmony_ci CLUSTER_RESERVED) { 27598c2ecf20Sopenharmony_ci /* cluster drive RESERVED (on the other node) */ 27608c2ecf20Sopenharmony_ci cmndinfo->phase = -2; /* reservation conflict */ 27618c2ecf20Sopenharmony_ci } 27628c2ecf20Sopenharmony_ci } else { 27638c2ecf20Sopenharmony_ci cmndinfo->OpCode = -1; 27648c2ecf20Sopenharmony_ci } 27658c2ecf20Sopenharmony_ci } else { 27668c2ecf20Sopenharmony_ci if (cmndinfo->OpCode == GDT_MOUNT) { 27678c2ecf20Sopenharmony_ci ha->hdr[t].cluster_type |= CLUSTER_MOUNTED; 27688c2ecf20Sopenharmony_ci ha->hdr[t].media_changed = TRUE; 27698c2ecf20Sopenharmony_ci } else if (cmndinfo->OpCode == GDT_UNMOUNT) { 27708c2ecf20Sopenharmony_ci ha->hdr[t].cluster_type &= ~CLUSTER_MOUNTED; 27718c2ecf20Sopenharmony_ci ha->hdr[t].media_changed = TRUE; 27728c2ecf20Sopenharmony_ci } 27738c2ecf20Sopenharmony_ci cmndinfo->OpCode = -1; 27748c2ecf20Sopenharmony_ci } 27758c2ecf20Sopenharmony_ci /* retry */ 27768c2ecf20Sopenharmony_ci cmndinfo->priority = HIGH_PRI; 27778c2ecf20Sopenharmony_ci return 2; 27788c2ecf20Sopenharmony_ci } else { 27798c2ecf20Sopenharmony_ci /* RESERVE/RELEASE ? */ 27808c2ecf20Sopenharmony_ci if (scp->cmnd[0] == RESERVE) { 27818c2ecf20Sopenharmony_ci ha->hdr[t].cluster_type |= CLUSTER_RESERVED; 27828c2ecf20Sopenharmony_ci } else if (scp->cmnd[0] == RELEASE) { 27838c2ecf20Sopenharmony_ci ha->hdr[t].cluster_type &= ~CLUSTER_RESERVED; 27848c2ecf20Sopenharmony_ci } 27858c2ecf20Sopenharmony_ci scp->result = DID_OK << 16; 27868c2ecf20Sopenharmony_ci scp->sense_buffer[0] = 0; 27878c2ecf20Sopenharmony_ci } 27888c2ecf20Sopenharmony_ci } else { 27898c2ecf20Sopenharmony_ci cmndinfo->status = ha->status; 27908c2ecf20Sopenharmony_ci cmndinfo->info = ha->info; 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci if (cmndinfo->OpCode != -1) { 27938c2ecf20Sopenharmony_ci TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n", 27948c2ecf20Sopenharmony_ci cmndinfo->OpCode, ha->status)); 27958c2ecf20Sopenharmony_ci if (cmndinfo->OpCode == GDT_SCAN_START || 27968c2ecf20Sopenharmony_ci cmndinfo->OpCode == GDT_SCAN_END) { 27978c2ecf20Sopenharmony_ci cmndinfo->OpCode = -1; 27988c2ecf20Sopenharmony_ci /* retry */ 27998c2ecf20Sopenharmony_ci cmndinfo->priority = HIGH_PRI; 28008c2ecf20Sopenharmony_ci return 2; 28018c2ecf20Sopenharmony_ci } 28028c2ecf20Sopenharmony_ci memset((char*)scp->sense_buffer,0,16); 28038c2ecf20Sopenharmony_ci scp->sense_buffer[0] = 0x70; 28048c2ecf20Sopenharmony_ci scp->sense_buffer[2] = NOT_READY; 28058c2ecf20Sopenharmony_ci scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); 28068c2ecf20Sopenharmony_ci } else if (service == CACHESERVICE) { 28078c2ecf20Sopenharmony_ci if (ha->status == S_CACHE_UNKNOWN && 28088c2ecf20Sopenharmony_ci (ha->hdr[t].cluster_type & 28098c2ecf20Sopenharmony_ci CLUSTER_RESERVE_STATE) == CLUSTER_RESERVE_STATE) { 28108c2ecf20Sopenharmony_ci /* bus reset -> force GDT_CLUST_INFO */ 28118c2ecf20Sopenharmony_ci ha->hdr[t].cluster_type &= ~CLUSTER_RESERVED; 28128c2ecf20Sopenharmony_ci } 28138c2ecf20Sopenharmony_ci memset((char*)scp->sense_buffer,0,16); 28148c2ecf20Sopenharmony_ci if (ha->status == (u16)S_CACHE_RESERV) { 28158c2ecf20Sopenharmony_ci scp->result = (DID_OK << 16) | (RESERVATION_CONFLICT << 1); 28168c2ecf20Sopenharmony_ci } else { 28178c2ecf20Sopenharmony_ci scp->sense_buffer[0] = 0x70; 28188c2ecf20Sopenharmony_ci scp->sense_buffer[2] = NOT_READY; 28198c2ecf20Sopenharmony_ci scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); 28208c2ecf20Sopenharmony_ci } 28218c2ecf20Sopenharmony_ci if (!cmndinfo->internal_command) { 28228c2ecf20Sopenharmony_ci ha->dvr.size = sizeof(ha->dvr.eu.sync); 28238c2ecf20Sopenharmony_ci ha->dvr.eu.sync.ionode = ha->hanum; 28248c2ecf20Sopenharmony_ci ha->dvr.eu.sync.service = service; 28258c2ecf20Sopenharmony_ci ha->dvr.eu.sync.status = ha->status; 28268c2ecf20Sopenharmony_ci ha->dvr.eu.sync.info = ha->info; 28278c2ecf20Sopenharmony_ci ha->dvr.eu.sync.hostdrive = t; 28288c2ecf20Sopenharmony_ci if (ha->status >= 0x8000) 28298c2ecf20Sopenharmony_ci gdth_store_event(ha, ES_SYNC, 0, &ha->dvr); 28308c2ecf20Sopenharmony_ci else 28318c2ecf20Sopenharmony_ci gdth_store_event(ha, ES_SYNC, service, &ha->dvr); 28328c2ecf20Sopenharmony_ci } 28338c2ecf20Sopenharmony_ci } else { 28348c2ecf20Sopenharmony_ci /* sense buffer filled from controller firmware (DMA) */ 28358c2ecf20Sopenharmony_ci if (ha->status != S_RAW_SCSI || ha->info >= 0x100) { 28368c2ecf20Sopenharmony_ci scp->result = DID_BAD_TARGET << 16; 28378c2ecf20Sopenharmony_ci } else { 28388c2ecf20Sopenharmony_ci scp->result = (DID_OK << 16) | ha->info; 28398c2ecf20Sopenharmony_ci } 28408c2ecf20Sopenharmony_ci } 28418c2ecf20Sopenharmony_ci } 28428c2ecf20Sopenharmony_ci if (!cmndinfo->wait_for_completion) 28438c2ecf20Sopenharmony_ci cmndinfo->wait_for_completion++; 28448c2ecf20Sopenharmony_ci else 28458c2ecf20Sopenharmony_ci return 1; 28468c2ecf20Sopenharmony_ci } 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci return 0; 28498c2ecf20Sopenharmony_ci} 28508c2ecf20Sopenharmony_ci 28518c2ecf20Sopenharmony_cistatic char *async_cache_tab[] = { 28528c2ecf20Sopenharmony_ci/* 0*/ "\011\000\002\002\002\004\002\006\004" 28538c2ecf20Sopenharmony_ci "GDT HA %u, service %u, async. status %u/%lu unknown", 28548c2ecf20Sopenharmony_ci/* 1*/ "\011\000\002\002\002\004\002\006\004" 28558c2ecf20Sopenharmony_ci "GDT HA %u, service %u, async. status %u/%lu unknown", 28568c2ecf20Sopenharmony_ci/* 2*/ "\005\000\002\006\004" 28578c2ecf20Sopenharmony_ci "GDT HA %u, Host Drive %lu not ready", 28588c2ecf20Sopenharmony_ci/* 3*/ "\005\000\002\006\004" 28598c2ecf20Sopenharmony_ci "GDT HA %u, Host Drive %lu: REASSIGN not successful and/or data error on reassigned blocks. Drive may crash in the future and should be replaced", 28608c2ecf20Sopenharmony_ci/* 4*/ "\005\000\002\006\004" 28618c2ecf20Sopenharmony_ci "GDT HA %u, mirror update on Host Drive %lu failed", 28628c2ecf20Sopenharmony_ci/* 5*/ "\005\000\002\006\004" 28638c2ecf20Sopenharmony_ci "GDT HA %u, Mirror Drive %lu failed", 28648c2ecf20Sopenharmony_ci/* 6*/ "\005\000\002\006\004" 28658c2ecf20Sopenharmony_ci "GDT HA %u, Mirror Drive %lu: REASSIGN not successful and/or data error on reassigned blocks. Drive may crash in the future and should be replaced", 28668c2ecf20Sopenharmony_ci/* 7*/ "\005\000\002\006\004" 28678c2ecf20Sopenharmony_ci "GDT HA %u, Host Drive %lu write protected", 28688c2ecf20Sopenharmony_ci/* 8*/ "\005\000\002\006\004" 28698c2ecf20Sopenharmony_ci "GDT HA %u, media changed in Host Drive %lu", 28708c2ecf20Sopenharmony_ci/* 9*/ "\005\000\002\006\004" 28718c2ecf20Sopenharmony_ci "GDT HA %u, Host Drive %lu is offline", 28728c2ecf20Sopenharmony_ci/*10*/ "\005\000\002\006\004" 28738c2ecf20Sopenharmony_ci "GDT HA %u, media change of Mirror Drive %lu", 28748c2ecf20Sopenharmony_ci/*11*/ "\005\000\002\006\004" 28758c2ecf20Sopenharmony_ci "GDT HA %u, Mirror Drive %lu is write protected", 28768c2ecf20Sopenharmony_ci/*12*/ "\005\000\002\006\004" 28778c2ecf20Sopenharmony_ci "GDT HA %u, general error on Host Drive %lu. Please check the devices of this drive!", 28788c2ecf20Sopenharmony_ci/*13*/ "\007\000\002\006\002\010\002" 28798c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: Cache Drive %u failed", 28808c2ecf20Sopenharmony_ci/*14*/ "\005\000\002\006\002" 28818c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: FAIL state entered", 28828c2ecf20Sopenharmony_ci/*15*/ "\005\000\002\006\002" 28838c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: error", 28848c2ecf20Sopenharmony_ci/*16*/ "\007\000\002\006\002\010\002" 28858c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: failed drive replaced by Cache Drive %u", 28868c2ecf20Sopenharmony_ci/*17*/ "\005\000\002\006\002" 28878c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: parity build failed", 28888c2ecf20Sopenharmony_ci/*18*/ "\005\000\002\006\002" 28898c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: drive rebuild failed", 28908c2ecf20Sopenharmony_ci/*19*/ "\005\000\002\010\002" 28918c2ecf20Sopenharmony_ci "GDT HA %u, Test of Hot Fix %u failed", 28928c2ecf20Sopenharmony_ci/*20*/ "\005\000\002\006\002" 28938c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: drive build finished successfully", 28948c2ecf20Sopenharmony_ci/*21*/ "\005\000\002\006\002" 28958c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: drive rebuild finished successfully", 28968c2ecf20Sopenharmony_ci/*22*/ "\007\000\002\006\002\010\002" 28978c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: Hot Fix %u activated", 28988c2ecf20Sopenharmony_ci/*23*/ "\005\000\002\006\002" 28998c2ecf20Sopenharmony_ci "GDT HA %u, Host Drive %u: processing of i/o aborted due to serious drive error", 29008c2ecf20Sopenharmony_ci/*24*/ "\005\000\002\010\002" 29018c2ecf20Sopenharmony_ci "GDT HA %u, mirror update on Cache Drive %u completed", 29028c2ecf20Sopenharmony_ci/*25*/ "\005\000\002\010\002" 29038c2ecf20Sopenharmony_ci "GDT HA %u, mirror update on Cache Drive %lu failed", 29048c2ecf20Sopenharmony_ci/*26*/ "\005\000\002\006\002" 29058c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: drive rebuild started", 29068c2ecf20Sopenharmony_ci/*27*/ "\005\000\002\012\001" 29078c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u: SHELF OK detected", 29088c2ecf20Sopenharmony_ci/*28*/ "\005\000\002\012\001" 29098c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u: SHELF not OK detected", 29108c2ecf20Sopenharmony_ci/*29*/ "\007\000\002\012\001\013\001" 29118c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug started", 29128c2ecf20Sopenharmony_ci/*30*/ "\007\000\002\012\001\013\001" 29138c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u, ID %u: new disk detected", 29148c2ecf20Sopenharmony_ci/*31*/ "\007\000\002\012\001\013\001" 29158c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u, ID %u: old disk detected", 29168c2ecf20Sopenharmony_ci/*32*/ "\007\000\002\012\001\013\001" 29178c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u, ID %u: plugging an active disk is invalid", 29188c2ecf20Sopenharmony_ci/*33*/ "\007\000\002\012\001\013\001" 29198c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u, ID %u: invalid device detected", 29208c2ecf20Sopenharmony_ci/*34*/ "\011\000\002\012\001\013\001\006\004" 29218c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u, ID %u: insufficient disk capacity (%lu MB required)", 29228c2ecf20Sopenharmony_ci/*35*/ "\007\000\002\012\001\013\001" 29238c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u, ID %u: disk write protected", 29248c2ecf20Sopenharmony_ci/*36*/ "\007\000\002\012\001\013\001" 29258c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u, ID %u: disk not available", 29268c2ecf20Sopenharmony_ci/*37*/ "\007\000\002\012\001\006\004" 29278c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u: swap detected (%lu)", 29288c2ecf20Sopenharmony_ci/*38*/ "\007\000\002\012\001\013\001" 29298c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug finished successfully", 29308c2ecf20Sopenharmony_ci/*39*/ "\007\000\002\012\001\013\001" 29318c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug aborted due to user Hot Plug", 29328c2ecf20Sopenharmony_ci/*40*/ "\007\000\002\012\001\013\001" 29338c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug aborted", 29348c2ecf20Sopenharmony_ci/*41*/ "\007\000\002\012\001\013\001" 29358c2ecf20Sopenharmony_ci "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug for Hot Fix started", 29368c2ecf20Sopenharmony_ci/*42*/ "\005\000\002\006\002" 29378c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: drive build started", 29388c2ecf20Sopenharmony_ci/*43*/ "\003\000\002" 29398c2ecf20Sopenharmony_ci "GDT HA %u, DRAM parity error detected", 29408c2ecf20Sopenharmony_ci/*44*/ "\005\000\002\006\002" 29418c2ecf20Sopenharmony_ci "GDT HA %u, Mirror Drive %u: update started", 29428c2ecf20Sopenharmony_ci/*45*/ "\007\000\002\006\002\010\002" 29438c2ecf20Sopenharmony_ci "GDT HA %u, Mirror Drive %u: Hot Fix %u activated", 29448c2ecf20Sopenharmony_ci/*46*/ "\005\000\002\006\002" 29458c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: no matching Pool Hot Fix Drive available", 29468c2ecf20Sopenharmony_ci/*47*/ "\005\000\002\006\002" 29478c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: Pool Hot Fix Drive available", 29488c2ecf20Sopenharmony_ci/*48*/ "\005\000\002\006\002" 29498c2ecf20Sopenharmony_ci "GDT HA %u, Mirror Drive %u: no matching Pool Hot Fix Drive available", 29508c2ecf20Sopenharmony_ci/*49*/ "\005\000\002\006\002" 29518c2ecf20Sopenharmony_ci "GDT HA %u, Mirror Drive %u: Pool Hot Fix Drive available", 29528c2ecf20Sopenharmony_ci/*50*/ "\007\000\002\012\001\013\001" 29538c2ecf20Sopenharmony_ci "GDT HA %u, SCSI bus %u, ID %u: IGNORE_WIDE_RESIDUE message received", 29548c2ecf20Sopenharmony_ci/*51*/ "\005\000\002\006\002" 29558c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: expand started", 29568c2ecf20Sopenharmony_ci/*52*/ "\005\000\002\006\002" 29578c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: expand finished successfully", 29588c2ecf20Sopenharmony_ci/*53*/ "\005\000\002\006\002" 29598c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: expand failed", 29608c2ecf20Sopenharmony_ci/*54*/ "\003\000\002" 29618c2ecf20Sopenharmony_ci "GDT HA %u, CPU temperature critical", 29628c2ecf20Sopenharmony_ci/*55*/ "\003\000\002" 29638c2ecf20Sopenharmony_ci "GDT HA %u, CPU temperature OK", 29648c2ecf20Sopenharmony_ci/*56*/ "\005\000\002\006\004" 29658c2ecf20Sopenharmony_ci "GDT HA %u, Host drive %lu created", 29668c2ecf20Sopenharmony_ci/*57*/ "\005\000\002\006\002" 29678c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: expand restarted", 29688c2ecf20Sopenharmony_ci/*58*/ "\005\000\002\006\002" 29698c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: expand stopped", 29708c2ecf20Sopenharmony_ci/*59*/ "\005\000\002\010\002" 29718c2ecf20Sopenharmony_ci "GDT HA %u, Mirror Drive %u: drive build quited", 29728c2ecf20Sopenharmony_ci/*60*/ "\005\000\002\006\002" 29738c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: parity build quited", 29748c2ecf20Sopenharmony_ci/*61*/ "\005\000\002\006\002" 29758c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: drive rebuild quited", 29768c2ecf20Sopenharmony_ci/*62*/ "\005\000\002\006\002" 29778c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: parity verify started", 29788c2ecf20Sopenharmony_ci/*63*/ "\005\000\002\006\002" 29798c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: parity verify done", 29808c2ecf20Sopenharmony_ci/*64*/ "\005\000\002\006\002" 29818c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: parity verify failed", 29828c2ecf20Sopenharmony_ci/*65*/ "\005\000\002\006\002" 29838c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: parity error detected", 29848c2ecf20Sopenharmony_ci/*66*/ "\005\000\002\006\002" 29858c2ecf20Sopenharmony_ci "GDT HA %u, Array Drive %u: parity verify quited", 29868c2ecf20Sopenharmony_ci/*67*/ "\005\000\002\006\002" 29878c2ecf20Sopenharmony_ci "GDT HA %u, Host Drive %u reserved", 29888c2ecf20Sopenharmony_ci/*68*/ "\005\000\002\006\002" 29898c2ecf20Sopenharmony_ci "GDT HA %u, Host Drive %u mounted and released", 29908c2ecf20Sopenharmony_ci/*69*/ "\005\000\002\006\002" 29918c2ecf20Sopenharmony_ci "GDT HA %u, Host Drive %u released", 29928c2ecf20Sopenharmony_ci/*70*/ "\003\000\002" 29938c2ecf20Sopenharmony_ci "GDT HA %u, DRAM error detected and corrected with ECC", 29948c2ecf20Sopenharmony_ci/*71*/ "\003\000\002" 29958c2ecf20Sopenharmony_ci "GDT HA %u, Uncorrectable DRAM error detected with ECC", 29968c2ecf20Sopenharmony_ci/*72*/ "\011\000\002\012\001\013\001\014\001" 29978c2ecf20Sopenharmony_ci "GDT HA %u, SCSI bus %u, ID %u, LUN %u: reassigning block", 29988c2ecf20Sopenharmony_ci/*73*/ "\005\000\002\006\002" 29998c2ecf20Sopenharmony_ci "GDT HA %u, Host drive %u resetted locally", 30008c2ecf20Sopenharmony_ci/*74*/ "\005\000\002\006\002" 30018c2ecf20Sopenharmony_ci "GDT HA %u, Host drive %u resetted remotely", 30028c2ecf20Sopenharmony_ci/*75*/ "\003\000\002" 30038c2ecf20Sopenharmony_ci "GDT HA %u, async. status 75 unknown", 30048c2ecf20Sopenharmony_ci}; 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci 30078c2ecf20Sopenharmony_cistatic int gdth_async_event(gdth_ha_str *ha) 30088c2ecf20Sopenharmony_ci{ 30098c2ecf20Sopenharmony_ci gdth_cmd_str *cmdp; 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_ci cmdp= ha->pccb; 30128c2ecf20Sopenharmony_ci TRACE2(("gdth_async_event() ha %d serv %d\n", 30138c2ecf20Sopenharmony_ci ha->hanum, ha->service)); 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci if (ha->service == SCREENSERVICE) { 30168c2ecf20Sopenharmony_ci if (ha->status == MSG_REQUEST) { 30178c2ecf20Sopenharmony_ci while (gdth_test_busy(ha)) 30188c2ecf20Sopenharmony_ci gdth_delay(0); 30198c2ecf20Sopenharmony_ci cmdp->Service = SCREENSERVICE; 30208c2ecf20Sopenharmony_ci cmdp->RequestBuffer = SCREEN_CMND; 30218c2ecf20Sopenharmony_ci gdth_set_sema0(ha); 30228c2ecf20Sopenharmony_ci cmdp->OpCode = GDT_READ; 30238c2ecf20Sopenharmony_ci cmdp->BoardNode = LOCALBOARD; 30248c2ecf20Sopenharmony_ci cmdp->u.screen.reserved = 0; 30258c2ecf20Sopenharmony_ci cmdp->u.screen.su.msg.msg_handle= MSG_INV_HANDLE; 30268c2ecf20Sopenharmony_ci cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; 30278c2ecf20Sopenharmony_ci ha->cmd_offs_dpmem = 0; 30288c2ecf20Sopenharmony_ci ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 30298c2ecf20Sopenharmony_ci + sizeof(u64); 30308c2ecf20Sopenharmony_ci ha->cmd_cnt = 0; 30318c2ecf20Sopenharmony_ci gdth_copy_command(ha); 30328c2ecf20Sopenharmony_ci printk("[PCI %d/%d] ",(u16)(ha->brd_phys>>8), 30338c2ecf20Sopenharmony_ci (u16)((ha->brd_phys>>3)&0x1f)); 30348c2ecf20Sopenharmony_ci gdth_release_event(ha); 30358c2ecf20Sopenharmony_ci } 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci } else { 30388c2ecf20Sopenharmony_ci if (ha->type == GDT_PCIMPR && 30398c2ecf20Sopenharmony_ci (ha->fw_vers & 0xff) >= 0x1a) { 30408c2ecf20Sopenharmony_ci ha->dvr.size = 0; 30418c2ecf20Sopenharmony_ci ha->dvr.eu.async.ionode = ha->hanum; 30428c2ecf20Sopenharmony_ci ha->dvr.eu.async.status = ha->status; 30438c2ecf20Sopenharmony_ci /* severity and event_string already set! */ 30448c2ecf20Sopenharmony_ci } else { 30458c2ecf20Sopenharmony_ci ha->dvr.size = sizeof(ha->dvr.eu.async); 30468c2ecf20Sopenharmony_ci ha->dvr.eu.async.ionode = ha->hanum; 30478c2ecf20Sopenharmony_ci ha->dvr.eu.async.service = ha->service; 30488c2ecf20Sopenharmony_ci ha->dvr.eu.async.status = ha->status; 30498c2ecf20Sopenharmony_ci ha->dvr.eu.async.info = ha->info; 30508c2ecf20Sopenharmony_ci *(u32 *)ha->dvr.eu.async.scsi_coord = ha->info2; 30518c2ecf20Sopenharmony_ci } 30528c2ecf20Sopenharmony_ci gdth_store_event( ha, ES_ASYNC, ha->service, &ha->dvr ); 30538c2ecf20Sopenharmony_ci gdth_log_event( &ha->dvr, NULL ); 30548c2ecf20Sopenharmony_ci 30558c2ecf20Sopenharmony_ci /* new host drive from expand? */ 30568c2ecf20Sopenharmony_ci if (ha->service == CACHESERVICE && ha->status == 56) { 30578c2ecf20Sopenharmony_ci TRACE2(("gdth_async_event(): new host drive %d created\n", 30588c2ecf20Sopenharmony_ci (u16)ha->info)); 30598c2ecf20Sopenharmony_ci /* gdth_analyse_hdrive(hanum, (u16)ha->info); */ 30608c2ecf20Sopenharmony_ci } 30618c2ecf20Sopenharmony_ci } 30628c2ecf20Sopenharmony_ci return 1; 30638c2ecf20Sopenharmony_ci} 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_cistatic void gdth_log_event(gdth_evt_data *dvr, char *buffer) 30668c2ecf20Sopenharmony_ci{ 30678c2ecf20Sopenharmony_ci gdth_stackframe stack; 30688c2ecf20Sopenharmony_ci char *f = NULL; 30698c2ecf20Sopenharmony_ci int i,j; 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_ci TRACE2(("gdth_log_event()\n")); 30728c2ecf20Sopenharmony_ci if (dvr->size == 0) { 30738c2ecf20Sopenharmony_ci if (buffer == NULL) { 30748c2ecf20Sopenharmony_ci printk("Adapter %d: %s\n",dvr->eu.async.ionode,dvr->event_string); 30758c2ecf20Sopenharmony_ci } else { 30768c2ecf20Sopenharmony_ci sprintf(buffer,"Adapter %d: %s\n", 30778c2ecf20Sopenharmony_ci dvr->eu.async.ionode,dvr->event_string); 30788c2ecf20Sopenharmony_ci } 30798c2ecf20Sopenharmony_ci } else if (dvr->eu.async.service == CACHESERVICE && 30808c2ecf20Sopenharmony_ci INDEX_OK(dvr->eu.async.status, async_cache_tab)) { 30818c2ecf20Sopenharmony_ci TRACE2(("GDT: Async. event cache service, event no.: %d\n", 30828c2ecf20Sopenharmony_ci dvr->eu.async.status)); 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ci f = async_cache_tab[dvr->eu.async.status]; 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci /* i: parameter to push, j: stack element to fill */ 30878c2ecf20Sopenharmony_ci for (j=0,i=1; i < f[0]; i+=2) { 30888c2ecf20Sopenharmony_ci switch (f[i+1]) { 30898c2ecf20Sopenharmony_ci case 4: 30908c2ecf20Sopenharmony_ci stack.b[j++] = *(u32*)&dvr->eu.stream[(int)f[i]]; 30918c2ecf20Sopenharmony_ci break; 30928c2ecf20Sopenharmony_ci case 2: 30938c2ecf20Sopenharmony_ci stack.b[j++] = *(u16*)&dvr->eu.stream[(int)f[i]]; 30948c2ecf20Sopenharmony_ci break; 30958c2ecf20Sopenharmony_ci case 1: 30968c2ecf20Sopenharmony_ci stack.b[j++] = *(u8*)&dvr->eu.stream[(int)f[i]]; 30978c2ecf20Sopenharmony_ci break; 30988c2ecf20Sopenharmony_ci default: 30998c2ecf20Sopenharmony_ci break; 31008c2ecf20Sopenharmony_ci } 31018c2ecf20Sopenharmony_ci } 31028c2ecf20Sopenharmony_ci 31038c2ecf20Sopenharmony_ci if (buffer == NULL) { 31048c2ecf20Sopenharmony_ci printk(&f[(int)f[0]],stack); 31058c2ecf20Sopenharmony_ci printk("\n"); 31068c2ecf20Sopenharmony_ci } else { 31078c2ecf20Sopenharmony_ci sprintf(buffer,&f[(int)f[0]],stack); 31088c2ecf20Sopenharmony_ci } 31098c2ecf20Sopenharmony_ci 31108c2ecf20Sopenharmony_ci } else { 31118c2ecf20Sopenharmony_ci if (buffer == NULL) { 31128c2ecf20Sopenharmony_ci printk("GDT HA %u, Unknown async. event service %d event no. %d\n", 31138c2ecf20Sopenharmony_ci dvr->eu.async.ionode,dvr->eu.async.service,dvr->eu.async.status); 31148c2ecf20Sopenharmony_ci } else { 31158c2ecf20Sopenharmony_ci sprintf(buffer,"GDT HA %u, Unknown async. event service %d event no. %d", 31168c2ecf20Sopenharmony_ci dvr->eu.async.ionode,dvr->eu.async.service,dvr->eu.async.status); 31178c2ecf20Sopenharmony_ci } 31188c2ecf20Sopenharmony_ci } 31198c2ecf20Sopenharmony_ci} 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci#ifdef GDTH_STATISTICS 31228c2ecf20Sopenharmony_cistatic u8 gdth_timer_running; 31238c2ecf20Sopenharmony_ci 31248c2ecf20Sopenharmony_cistatic void gdth_timeout(struct timer_list *unused) 31258c2ecf20Sopenharmony_ci{ 31268c2ecf20Sopenharmony_ci u32 i; 31278c2ecf20Sopenharmony_ci struct scsi_cmnd *nscp; 31288c2ecf20Sopenharmony_ci gdth_ha_str *ha; 31298c2ecf20Sopenharmony_ci unsigned long flags; 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci if(unlikely(list_empty(&gdth_instances))) { 31328c2ecf20Sopenharmony_ci gdth_timer_running = 0; 31338c2ecf20Sopenharmony_ci return; 31348c2ecf20Sopenharmony_ci } 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci ha = list_first_entry(&gdth_instances, gdth_ha_str, list); 31378c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci for (act_stats=0,i=0; i<GDTH_MAXCMDS; ++i) 31408c2ecf20Sopenharmony_ci if (ha->cmd_tab[i].cmnd != UNUSED_CMND) 31418c2ecf20Sopenharmony_ci ++act_stats; 31428c2ecf20Sopenharmony_ci 31438c2ecf20Sopenharmony_ci for (act_rq=0, 31448c2ecf20Sopenharmony_ci nscp=ha->req_first; nscp; nscp=(struct scsi_cmnd*)nscp->SCp.ptr) 31458c2ecf20Sopenharmony_ci ++act_rq; 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci TRACE2(("gdth_to(): ints %d, ios %d, act_stats %d, act_rq %d\n", 31488c2ecf20Sopenharmony_ci act_ints, act_ios, act_stats, act_rq)); 31498c2ecf20Sopenharmony_ci act_ints = act_ios = 0; 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci gdth_timer.expires = jiffies + 30 * HZ; 31528c2ecf20Sopenharmony_ci add_timer(&gdth_timer); 31538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 31548c2ecf20Sopenharmony_ci} 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_cistatic void gdth_timer_init(void) 31578c2ecf20Sopenharmony_ci{ 31588c2ecf20Sopenharmony_ci if (gdth_timer_running) 31598c2ecf20Sopenharmony_ci return; 31608c2ecf20Sopenharmony_ci gdth_timer_running = 1; 31618c2ecf20Sopenharmony_ci TRACE2(("gdth_detect(): Initializing timer !\n")); 31628c2ecf20Sopenharmony_ci gdth_timer.expires = jiffies + HZ; 31638c2ecf20Sopenharmony_ci add_timer(&gdth_timer); 31648c2ecf20Sopenharmony_ci} 31658c2ecf20Sopenharmony_ci#else 31668c2ecf20Sopenharmony_cistatic inline void gdth_timer_init(void) 31678c2ecf20Sopenharmony_ci{ 31688c2ecf20Sopenharmony_ci} 31698c2ecf20Sopenharmony_ci#endif 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci 31728c2ecf20Sopenharmony_cistatic const char *gdth_ctr_name(gdth_ha_str *ha) 31738c2ecf20Sopenharmony_ci{ 31748c2ecf20Sopenharmony_ci TRACE2(("gdth_ctr_name()\n")); 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci if (ha->type == GDT_PCI) { 31778c2ecf20Sopenharmony_ci switch (ha->pdev->device) { 31788c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_VORTEX_GDT60x0: 31798c2ecf20Sopenharmony_ci return("GDT6000/6020/6050"); 31808c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_VORTEX_GDT6000B: 31818c2ecf20Sopenharmony_ci return("GDT6000B/6010"); 31828c2ecf20Sopenharmony_ci } 31838c2ecf20Sopenharmony_ci } 31848c2ecf20Sopenharmony_ci /* new controllers (GDT_PCINEW, GDT_PCIMPR, ..) use board_info IOCTL! */ 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_ci return(""); 31878c2ecf20Sopenharmony_ci} 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_cistatic const char *gdth_info(struct Scsi_Host *shp) 31908c2ecf20Sopenharmony_ci{ 31918c2ecf20Sopenharmony_ci gdth_ha_str *ha = shost_priv(shp); 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci TRACE2(("gdth_info()\n")); 31948c2ecf20Sopenharmony_ci return ((const char *)ha->binfo.type_string); 31958c2ecf20Sopenharmony_ci} 31968c2ecf20Sopenharmony_ci 31978c2ecf20Sopenharmony_cistatic enum blk_eh_timer_return gdth_timed_out(struct scsi_cmnd *scp) 31988c2ecf20Sopenharmony_ci{ 31998c2ecf20Sopenharmony_ci gdth_ha_str *ha = shost_priv(scp->device->host); 32008c2ecf20Sopenharmony_ci struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); 32018c2ecf20Sopenharmony_ci u8 b, t; 32028c2ecf20Sopenharmony_ci unsigned long flags; 32038c2ecf20Sopenharmony_ci enum blk_eh_timer_return retval = BLK_EH_DONE; 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci TRACE(("%s() cmd 0x%x\n", scp->cmnd[0], __func__)); 32068c2ecf20Sopenharmony_ci b = scp->device->channel; 32078c2ecf20Sopenharmony_ci t = scp->device->id; 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci /* 32108c2ecf20Sopenharmony_ci * We don't really honor the command timeout, but we try to 32118c2ecf20Sopenharmony_ci * honor 6 times of the actual command timeout! So reset the 32128c2ecf20Sopenharmony_ci * timer if this is less than 6th timeout on this command! 32138c2ecf20Sopenharmony_ci */ 32148c2ecf20Sopenharmony_ci if (++cmndinfo->timeout_count < 6) 32158c2ecf20Sopenharmony_ci retval = BLK_EH_RESET_TIMER; 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci /* Reset the timeout if it is locked IO */ 32188c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 32198c2ecf20Sopenharmony_ci if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha, b)].lock) || 32208c2ecf20Sopenharmony_ci (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) { 32218c2ecf20Sopenharmony_ci TRACE2(("%s(): locked IO, reset timeout\n", __func__)); 32228c2ecf20Sopenharmony_ci retval = BLK_EH_RESET_TIMER; 32238c2ecf20Sopenharmony_ci } 32248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 32258c2ecf20Sopenharmony_ci 32268c2ecf20Sopenharmony_ci return retval; 32278c2ecf20Sopenharmony_ci} 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci 32308c2ecf20Sopenharmony_cistatic int gdth_eh_bus_reset(struct scsi_cmnd *scp) 32318c2ecf20Sopenharmony_ci{ 32328c2ecf20Sopenharmony_ci gdth_ha_str *ha = shost_priv(scp->device->host); 32338c2ecf20Sopenharmony_ci int i; 32348c2ecf20Sopenharmony_ci unsigned long flags; 32358c2ecf20Sopenharmony_ci struct scsi_cmnd *cmnd; 32368c2ecf20Sopenharmony_ci u8 b; 32378c2ecf20Sopenharmony_ci 32388c2ecf20Sopenharmony_ci TRACE2(("gdth_eh_bus_reset()\n")); 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci b = scp->device->channel; 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci /* clear command tab */ 32438c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 32448c2ecf20Sopenharmony_ci for (i = 0; i < GDTH_MAXCMDS; ++i) { 32458c2ecf20Sopenharmony_ci cmnd = ha->cmd_tab[i].cmnd; 32468c2ecf20Sopenharmony_ci if (!SPECIAL_SCP(cmnd) && cmnd->device->channel == b) 32478c2ecf20Sopenharmony_ci ha->cmd_tab[i].cmnd = UNUSED_CMND; 32488c2ecf20Sopenharmony_ci } 32498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci if (b == ha->virt_bus) { 32528c2ecf20Sopenharmony_ci /* host drives */ 32538c2ecf20Sopenharmony_ci for (i = 0; i < MAX_HDRIVES; ++i) { 32548c2ecf20Sopenharmony_ci if (ha->hdr[i].present) { 32558c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 32568c2ecf20Sopenharmony_ci gdth_polling = TRUE; 32578c2ecf20Sopenharmony_ci while (gdth_test_busy(ha)) 32588c2ecf20Sopenharmony_ci gdth_delay(0); 32598c2ecf20Sopenharmony_ci if (gdth_internal_cmd(ha, CACHESERVICE, 32608c2ecf20Sopenharmony_ci GDT_CLUST_RESET, i, 0, 0)) 32618c2ecf20Sopenharmony_ci ha->hdr[i].cluster_type &= ~CLUSTER_RESERVED; 32628c2ecf20Sopenharmony_ci gdth_polling = FALSE; 32638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 32648c2ecf20Sopenharmony_ci } 32658c2ecf20Sopenharmony_ci } 32668c2ecf20Sopenharmony_ci } else { 32678c2ecf20Sopenharmony_ci /* raw devices */ 32688c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 32698c2ecf20Sopenharmony_ci for (i = 0; i < MAXID; ++i) 32708c2ecf20Sopenharmony_ci ha->raw[BUS_L2P(ha,b)].io_cnt[i] = 0; 32718c2ecf20Sopenharmony_ci gdth_polling = TRUE; 32728c2ecf20Sopenharmony_ci while (gdth_test_busy(ha)) 32738c2ecf20Sopenharmony_ci gdth_delay(0); 32748c2ecf20Sopenharmony_ci gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESET_BUS, 32758c2ecf20Sopenharmony_ci BUS_L2P(ha,b), 0, 0); 32768c2ecf20Sopenharmony_ci gdth_polling = FALSE; 32778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 32788c2ecf20Sopenharmony_ci } 32798c2ecf20Sopenharmony_ci return SUCCESS; 32808c2ecf20Sopenharmony_ci} 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_cistatic int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip) 32838c2ecf20Sopenharmony_ci{ 32848c2ecf20Sopenharmony_ci u8 b, t; 32858c2ecf20Sopenharmony_ci gdth_ha_str *ha = shost_priv(sdev->host); 32868c2ecf20Sopenharmony_ci struct scsi_device *sd; 32878c2ecf20Sopenharmony_ci unsigned capacity; 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_ci sd = sdev; 32908c2ecf20Sopenharmony_ci capacity = cap; 32918c2ecf20Sopenharmony_ci b = sd->channel; 32928c2ecf20Sopenharmony_ci t = sd->id; 32938c2ecf20Sopenharmony_ci TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", ha->hanum, b, t)); 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_ci if (b != ha->virt_bus || ha->hdr[t].heads == 0) { 32968c2ecf20Sopenharmony_ci /* raw device or host drive without mapping information */ 32978c2ecf20Sopenharmony_ci TRACE2(("Evaluate mapping\n")); 32988c2ecf20Sopenharmony_ci gdth_eval_mapping(capacity,&ip[2],&ip[0],&ip[1]); 32998c2ecf20Sopenharmony_ci } else { 33008c2ecf20Sopenharmony_ci ip[0] = ha->hdr[t].heads; 33018c2ecf20Sopenharmony_ci ip[1] = ha->hdr[t].secs; 33028c2ecf20Sopenharmony_ci ip[2] = capacity / ip[0] / ip[1]; 33038c2ecf20Sopenharmony_ci } 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ci TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n", 33068c2ecf20Sopenharmony_ci ip[0],ip[1],ip[2])); 33078c2ecf20Sopenharmony_ci return 0; 33088c2ecf20Sopenharmony_ci} 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_cistatic int gdth_queuecommand_lck(struct scsi_cmnd *scp, 33128c2ecf20Sopenharmony_ci void (*done)(struct scsi_cmnd *)) 33138c2ecf20Sopenharmony_ci{ 33148c2ecf20Sopenharmony_ci gdth_ha_str *ha = shost_priv(scp->device->host); 33158c2ecf20Sopenharmony_ci struct gdth_cmndinfo *cmndinfo; 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci TRACE(("gdth_queuecommand() cmd 0x%x\n", scp->cmnd[0])); 33188c2ecf20Sopenharmony_ci 33198c2ecf20Sopenharmony_ci cmndinfo = gdth_get_cmndinfo(ha); 33208c2ecf20Sopenharmony_ci BUG_ON(!cmndinfo); 33218c2ecf20Sopenharmony_ci 33228c2ecf20Sopenharmony_ci scp->scsi_done = done; 33238c2ecf20Sopenharmony_ci cmndinfo->timeout_count = 0; 33248c2ecf20Sopenharmony_ci cmndinfo->priority = DEFAULT_PRI; 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci return __gdth_queuecommand(ha, scp, cmndinfo); 33278c2ecf20Sopenharmony_ci} 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(gdth_queuecommand) 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_cistatic int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp, 33328c2ecf20Sopenharmony_ci struct gdth_cmndinfo *cmndinfo) 33338c2ecf20Sopenharmony_ci{ 33348c2ecf20Sopenharmony_ci scp->host_scribble = (unsigned char *)cmndinfo; 33358c2ecf20Sopenharmony_ci cmndinfo->wait_for_completion = 1; 33368c2ecf20Sopenharmony_ci cmndinfo->phase = -1; 33378c2ecf20Sopenharmony_ci cmndinfo->OpCode = -1; 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci#ifdef GDTH_STATISTICS 33408c2ecf20Sopenharmony_ci ++act_ios; 33418c2ecf20Sopenharmony_ci#endif 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci gdth_putq(ha, scp, cmndinfo->priority); 33448c2ecf20Sopenharmony_ci gdth_next(ha); 33458c2ecf20Sopenharmony_ci return 0; 33468c2ecf20Sopenharmony_ci} 33478c2ecf20Sopenharmony_ci 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_cistatic int gdth_open(struct inode *inode, struct file *filep) 33508c2ecf20Sopenharmony_ci{ 33518c2ecf20Sopenharmony_ci gdth_ha_str *ha; 33528c2ecf20Sopenharmony_ci 33538c2ecf20Sopenharmony_ci mutex_lock(&gdth_mutex); 33548c2ecf20Sopenharmony_ci list_for_each_entry(ha, &gdth_instances, list) { 33558c2ecf20Sopenharmony_ci if (!ha->sdev) 33568c2ecf20Sopenharmony_ci ha->sdev = scsi_get_host_dev(ha->shost); 33578c2ecf20Sopenharmony_ci } 33588c2ecf20Sopenharmony_ci mutex_unlock(&gdth_mutex); 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci TRACE(("gdth_open()\n")); 33618c2ecf20Sopenharmony_ci return 0; 33628c2ecf20Sopenharmony_ci} 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_cistatic int gdth_close(struct inode *inode, struct file *filep) 33658c2ecf20Sopenharmony_ci{ 33668c2ecf20Sopenharmony_ci TRACE(("gdth_close()\n")); 33678c2ecf20Sopenharmony_ci return 0; 33688c2ecf20Sopenharmony_ci} 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_cistatic int ioc_event(void __user *arg) 33718c2ecf20Sopenharmony_ci{ 33728c2ecf20Sopenharmony_ci gdth_ioctl_event evt; 33738c2ecf20Sopenharmony_ci gdth_ha_str *ha; 33748c2ecf20Sopenharmony_ci unsigned long flags; 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_ci if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event))) 33778c2ecf20Sopenharmony_ci return -EFAULT; 33788c2ecf20Sopenharmony_ci ha = gdth_find_ha(evt.ionode); 33798c2ecf20Sopenharmony_ci if (!ha) 33808c2ecf20Sopenharmony_ci return -EFAULT; 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_ci if (evt.erase == 0xff) { 33838c2ecf20Sopenharmony_ci if (evt.event.event_source == ES_TEST) 33848c2ecf20Sopenharmony_ci evt.event.event_data.size=sizeof(evt.event.event_data.eu.test); 33858c2ecf20Sopenharmony_ci else if (evt.event.event_source == ES_DRIVER) 33868c2ecf20Sopenharmony_ci evt.event.event_data.size=sizeof(evt.event.event_data.eu.driver); 33878c2ecf20Sopenharmony_ci else if (evt.event.event_source == ES_SYNC) 33888c2ecf20Sopenharmony_ci evt.event.event_data.size=sizeof(evt.event.event_data.eu.sync); 33898c2ecf20Sopenharmony_ci else 33908c2ecf20Sopenharmony_ci evt.event.event_data.size=sizeof(evt.event.event_data.eu.async); 33918c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 33928c2ecf20Sopenharmony_ci gdth_store_event(ha, evt.event.event_source, evt.event.event_idx, 33938c2ecf20Sopenharmony_ci &evt.event.event_data); 33948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 33958c2ecf20Sopenharmony_ci } else if (evt.erase == 0xfe) { 33968c2ecf20Sopenharmony_ci gdth_clear_events(); 33978c2ecf20Sopenharmony_ci } else if (evt.erase == 0) { 33988c2ecf20Sopenharmony_ci evt.handle = gdth_read_event(ha, evt.handle, &evt.event); 33998c2ecf20Sopenharmony_ci } else { 34008c2ecf20Sopenharmony_ci gdth_readapp_event(ha, evt.erase, &evt.event); 34018c2ecf20Sopenharmony_ci } 34028c2ecf20Sopenharmony_ci if (copy_to_user(arg, &evt, sizeof(gdth_ioctl_event))) 34038c2ecf20Sopenharmony_ci return -EFAULT; 34048c2ecf20Sopenharmony_ci return 0; 34058c2ecf20Sopenharmony_ci} 34068c2ecf20Sopenharmony_ci 34078c2ecf20Sopenharmony_cistatic int ioc_lockdrv(void __user *arg) 34088c2ecf20Sopenharmony_ci{ 34098c2ecf20Sopenharmony_ci gdth_ioctl_lockdrv ldrv; 34108c2ecf20Sopenharmony_ci u8 i, j; 34118c2ecf20Sopenharmony_ci unsigned long flags; 34128c2ecf20Sopenharmony_ci gdth_ha_str *ha; 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv))) 34158c2ecf20Sopenharmony_ci return -EFAULT; 34168c2ecf20Sopenharmony_ci ha = gdth_find_ha(ldrv.ionode); 34178c2ecf20Sopenharmony_ci if (!ha) 34188c2ecf20Sopenharmony_ci return -EFAULT; 34198c2ecf20Sopenharmony_ci 34208c2ecf20Sopenharmony_ci for (i = 0; i < ldrv.drive_cnt && i < MAX_HDRIVES; ++i) { 34218c2ecf20Sopenharmony_ci j = ldrv.drives[i]; 34228c2ecf20Sopenharmony_ci if (j >= MAX_HDRIVES || !ha->hdr[j].present) 34238c2ecf20Sopenharmony_ci continue; 34248c2ecf20Sopenharmony_ci if (ldrv.lock) { 34258c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 34268c2ecf20Sopenharmony_ci ha->hdr[j].lock = 1; 34278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 34288c2ecf20Sopenharmony_ci gdth_wait_completion(ha, ha->bus_cnt, j); 34298c2ecf20Sopenharmony_ci } else { 34308c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 34318c2ecf20Sopenharmony_ci ha->hdr[j].lock = 0; 34328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 34338c2ecf20Sopenharmony_ci gdth_next(ha); 34348c2ecf20Sopenharmony_ci } 34358c2ecf20Sopenharmony_ci } 34368c2ecf20Sopenharmony_ci return 0; 34378c2ecf20Sopenharmony_ci} 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_cistatic int ioc_resetdrv(void __user *arg, char *cmnd) 34408c2ecf20Sopenharmony_ci{ 34418c2ecf20Sopenharmony_ci gdth_ioctl_reset res; 34428c2ecf20Sopenharmony_ci gdth_cmd_str cmd; 34438c2ecf20Sopenharmony_ci gdth_ha_str *ha; 34448c2ecf20Sopenharmony_ci int rval; 34458c2ecf20Sopenharmony_ci 34468c2ecf20Sopenharmony_ci if (copy_from_user(&res, arg, sizeof(gdth_ioctl_reset)) || 34478c2ecf20Sopenharmony_ci res.number >= MAX_HDRIVES) 34488c2ecf20Sopenharmony_ci return -EFAULT; 34498c2ecf20Sopenharmony_ci ha = gdth_find_ha(res.ionode); 34508c2ecf20Sopenharmony_ci if (!ha) 34518c2ecf20Sopenharmony_ci return -EFAULT; 34528c2ecf20Sopenharmony_ci 34538c2ecf20Sopenharmony_ci if (!ha->hdr[res.number].present) 34548c2ecf20Sopenharmony_ci return 0; 34558c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(gdth_cmd_str)); 34568c2ecf20Sopenharmony_ci cmd.Service = CACHESERVICE; 34578c2ecf20Sopenharmony_ci cmd.OpCode = GDT_CLUST_RESET; 34588c2ecf20Sopenharmony_ci if (ha->cache_feat & GDT_64BIT) 34598c2ecf20Sopenharmony_ci cmd.u.cache64.DeviceNo = res.number; 34608c2ecf20Sopenharmony_ci else 34618c2ecf20Sopenharmony_ci cmd.u.cache.DeviceNo = res.number; 34628c2ecf20Sopenharmony_ci 34638c2ecf20Sopenharmony_ci rval = __gdth_execute(ha->sdev, &cmd, cmnd, 30, NULL); 34648c2ecf20Sopenharmony_ci if (rval < 0) 34658c2ecf20Sopenharmony_ci return rval; 34668c2ecf20Sopenharmony_ci res.status = rval; 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci if (copy_to_user(arg, &res, sizeof(gdth_ioctl_reset))) 34698c2ecf20Sopenharmony_ci return -EFAULT; 34708c2ecf20Sopenharmony_ci return 0; 34718c2ecf20Sopenharmony_ci} 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_cistatic void gdth_ioc_cacheservice(gdth_ha_str *ha, gdth_ioctl_general *gen, 34748c2ecf20Sopenharmony_ci u64 paddr) 34758c2ecf20Sopenharmony_ci{ 34768c2ecf20Sopenharmony_ci if (ha->cache_feat & GDT_64BIT) { 34778c2ecf20Sopenharmony_ci /* copy elements from 32-bit IOCTL structure */ 34788c2ecf20Sopenharmony_ci gen->command.u.cache64.BlockCnt = gen->command.u.cache.BlockCnt; 34798c2ecf20Sopenharmony_ci gen->command.u.cache64.BlockNo = gen->command.u.cache.BlockNo; 34808c2ecf20Sopenharmony_ci gen->command.u.cache64.DeviceNo = gen->command.u.cache.DeviceNo; 34818c2ecf20Sopenharmony_ci 34828c2ecf20Sopenharmony_ci if (ha->cache_feat & SCATTER_GATHER) { 34838c2ecf20Sopenharmony_ci gen->command.u.cache64.DestAddr = (u64)-1; 34848c2ecf20Sopenharmony_ci gen->command.u.cache64.sg_canz = 1; 34858c2ecf20Sopenharmony_ci gen->command.u.cache64.sg_lst[0].sg_ptr = paddr; 34868c2ecf20Sopenharmony_ci gen->command.u.cache64.sg_lst[0].sg_len = gen->data_len; 34878c2ecf20Sopenharmony_ci gen->command.u.cache64.sg_lst[1].sg_len = 0; 34888c2ecf20Sopenharmony_ci } else { 34898c2ecf20Sopenharmony_ci gen->command.u.cache64.DestAddr = paddr; 34908c2ecf20Sopenharmony_ci gen->command.u.cache64.sg_canz = 0; 34918c2ecf20Sopenharmony_ci } 34928c2ecf20Sopenharmony_ci } else { 34938c2ecf20Sopenharmony_ci if (ha->cache_feat & SCATTER_GATHER) { 34948c2ecf20Sopenharmony_ci gen->command.u.cache.DestAddr = 0xffffffff; 34958c2ecf20Sopenharmony_ci gen->command.u.cache.sg_canz = 1; 34968c2ecf20Sopenharmony_ci gen->command.u.cache.sg_lst[0].sg_ptr = (u32)paddr; 34978c2ecf20Sopenharmony_ci gen->command.u.cache.sg_lst[0].sg_len = gen->data_len; 34988c2ecf20Sopenharmony_ci gen->command.u.cache.sg_lst[1].sg_len = 0; 34998c2ecf20Sopenharmony_ci } else { 35008c2ecf20Sopenharmony_ci gen->command.u.cache.DestAddr = paddr; 35018c2ecf20Sopenharmony_ci gen->command.u.cache.sg_canz = 0; 35028c2ecf20Sopenharmony_ci } 35038c2ecf20Sopenharmony_ci } 35048c2ecf20Sopenharmony_ci} 35058c2ecf20Sopenharmony_ci 35068c2ecf20Sopenharmony_cistatic void gdth_ioc_scsiraw(gdth_ha_str *ha, gdth_ioctl_general *gen, 35078c2ecf20Sopenharmony_ci u64 paddr) 35088c2ecf20Sopenharmony_ci{ 35098c2ecf20Sopenharmony_ci if (ha->raw_feat & GDT_64BIT) { 35108c2ecf20Sopenharmony_ci /* copy elements from 32-bit IOCTL structure */ 35118c2ecf20Sopenharmony_ci char cmd[16]; 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_ci gen->command.u.raw64.sense_len = gen->command.u.raw.sense_len; 35148c2ecf20Sopenharmony_ci gen->command.u.raw64.bus = gen->command.u.raw.bus; 35158c2ecf20Sopenharmony_ci gen->command.u.raw64.lun = gen->command.u.raw.lun; 35168c2ecf20Sopenharmony_ci gen->command.u.raw64.target = gen->command.u.raw.target; 35178c2ecf20Sopenharmony_ci memcpy(cmd, gen->command.u.raw.cmd, 16); 35188c2ecf20Sopenharmony_ci memcpy(gen->command.u.raw64.cmd, cmd, 16); 35198c2ecf20Sopenharmony_ci gen->command.u.raw64.clen = gen->command.u.raw.clen; 35208c2ecf20Sopenharmony_ci gen->command.u.raw64.sdlen = gen->command.u.raw.sdlen; 35218c2ecf20Sopenharmony_ci gen->command.u.raw64.direction = gen->command.u.raw.direction; 35228c2ecf20Sopenharmony_ci 35238c2ecf20Sopenharmony_ci /* addresses */ 35248c2ecf20Sopenharmony_ci if (ha->raw_feat & SCATTER_GATHER) { 35258c2ecf20Sopenharmony_ci gen->command.u.raw64.sdata = (u64)-1; 35268c2ecf20Sopenharmony_ci gen->command.u.raw64.sg_ranz = 1; 35278c2ecf20Sopenharmony_ci gen->command.u.raw64.sg_lst[0].sg_ptr = paddr; 35288c2ecf20Sopenharmony_ci gen->command.u.raw64.sg_lst[0].sg_len = gen->data_len; 35298c2ecf20Sopenharmony_ci gen->command.u.raw64.sg_lst[1].sg_len = 0; 35308c2ecf20Sopenharmony_ci } else { 35318c2ecf20Sopenharmony_ci gen->command.u.raw64.sdata = paddr; 35328c2ecf20Sopenharmony_ci gen->command.u.raw64.sg_ranz = 0; 35338c2ecf20Sopenharmony_ci } 35348c2ecf20Sopenharmony_ci 35358c2ecf20Sopenharmony_ci gen->command.u.raw64.sense_data = paddr + gen->data_len; 35368c2ecf20Sopenharmony_ci } else { 35378c2ecf20Sopenharmony_ci if (ha->raw_feat & SCATTER_GATHER) { 35388c2ecf20Sopenharmony_ci gen->command.u.raw.sdata = 0xffffffff; 35398c2ecf20Sopenharmony_ci gen->command.u.raw.sg_ranz = 1; 35408c2ecf20Sopenharmony_ci gen->command.u.raw.sg_lst[0].sg_ptr = (u32)paddr; 35418c2ecf20Sopenharmony_ci gen->command.u.raw.sg_lst[0].sg_len = gen->data_len; 35428c2ecf20Sopenharmony_ci gen->command.u.raw.sg_lst[1].sg_len = 0; 35438c2ecf20Sopenharmony_ci } else { 35448c2ecf20Sopenharmony_ci gen->command.u.raw.sdata = paddr; 35458c2ecf20Sopenharmony_ci gen->command.u.raw.sg_ranz = 0; 35468c2ecf20Sopenharmony_ci } 35478c2ecf20Sopenharmony_ci 35488c2ecf20Sopenharmony_ci gen->command.u.raw.sense_data = (u32)paddr + gen->data_len; 35498c2ecf20Sopenharmony_ci } 35508c2ecf20Sopenharmony_ci} 35518c2ecf20Sopenharmony_ci 35528c2ecf20Sopenharmony_cistatic int ioc_general(void __user *arg, char *cmnd) 35538c2ecf20Sopenharmony_ci{ 35548c2ecf20Sopenharmony_ci gdth_ioctl_general gen; 35558c2ecf20Sopenharmony_ci gdth_ha_str *ha; 35568c2ecf20Sopenharmony_ci char *buf = NULL; 35578c2ecf20Sopenharmony_ci dma_addr_t paddr; 35588c2ecf20Sopenharmony_ci int rval; 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_ci if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general))) 35618c2ecf20Sopenharmony_ci return -EFAULT; 35628c2ecf20Sopenharmony_ci ha = gdth_find_ha(gen.ionode); 35638c2ecf20Sopenharmony_ci if (!ha) 35648c2ecf20Sopenharmony_ci return -EFAULT; 35658c2ecf20Sopenharmony_ci 35668c2ecf20Sopenharmony_ci if (gen.data_len > INT_MAX) 35678c2ecf20Sopenharmony_ci return -EINVAL; 35688c2ecf20Sopenharmony_ci if (gen.sense_len > INT_MAX) 35698c2ecf20Sopenharmony_ci return -EINVAL; 35708c2ecf20Sopenharmony_ci if (gen.data_len + gen.sense_len > INT_MAX) 35718c2ecf20Sopenharmony_ci return -EINVAL; 35728c2ecf20Sopenharmony_ci 35738c2ecf20Sopenharmony_ci if (gen.data_len + gen.sense_len > 0) { 35748c2ecf20Sopenharmony_ci buf = dma_alloc_coherent(&ha->pdev->dev, 35758c2ecf20Sopenharmony_ci gen.data_len + gen.sense_len, &paddr, 35768c2ecf20Sopenharmony_ci GFP_KERNEL); 35778c2ecf20Sopenharmony_ci if (!buf) 35788c2ecf20Sopenharmony_ci return -EFAULT; 35798c2ecf20Sopenharmony_ci 35808c2ecf20Sopenharmony_ci rval = -EFAULT; 35818c2ecf20Sopenharmony_ci if (copy_from_user(buf, arg + sizeof(gdth_ioctl_general), 35828c2ecf20Sopenharmony_ci gen.data_len + gen.sense_len)) 35838c2ecf20Sopenharmony_ci goto out_free_buf; 35848c2ecf20Sopenharmony_ci 35858c2ecf20Sopenharmony_ci if (gen.command.OpCode == GDT_IOCTL) 35868c2ecf20Sopenharmony_ci gen.command.u.ioctl.p_param = paddr; 35878c2ecf20Sopenharmony_ci else if (gen.command.Service == CACHESERVICE) 35888c2ecf20Sopenharmony_ci gdth_ioc_cacheservice(ha, &gen, paddr); 35898c2ecf20Sopenharmony_ci else if (gen.command.Service == SCSIRAWSERVICE) 35908c2ecf20Sopenharmony_ci gdth_ioc_scsiraw(ha, &gen, paddr); 35918c2ecf20Sopenharmony_ci else 35928c2ecf20Sopenharmony_ci goto out_free_buf; 35938c2ecf20Sopenharmony_ci } 35948c2ecf20Sopenharmony_ci 35958c2ecf20Sopenharmony_ci rval = __gdth_execute(ha->sdev, &gen.command, cmnd, gen.timeout, 35968c2ecf20Sopenharmony_ci &gen.info); 35978c2ecf20Sopenharmony_ci if (rval < 0) 35988c2ecf20Sopenharmony_ci goto out_free_buf; 35998c2ecf20Sopenharmony_ci gen.status = rval; 36008c2ecf20Sopenharmony_ci 36018c2ecf20Sopenharmony_ci rval = -EFAULT; 36028c2ecf20Sopenharmony_ci if (copy_to_user(arg + sizeof(gdth_ioctl_general), buf, 36038c2ecf20Sopenharmony_ci gen.data_len + gen.sense_len)) 36048c2ecf20Sopenharmony_ci goto out_free_buf; 36058c2ecf20Sopenharmony_ci if (copy_to_user(arg, &gen, 36068c2ecf20Sopenharmony_ci sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) 36078c2ecf20Sopenharmony_ci goto out_free_buf; 36088c2ecf20Sopenharmony_ci 36098c2ecf20Sopenharmony_ci rval = 0; 36108c2ecf20Sopenharmony_ciout_free_buf: 36118c2ecf20Sopenharmony_ci if (buf) 36128c2ecf20Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, gen.data_len + gen.sense_len, 36138c2ecf20Sopenharmony_ci buf, paddr); 36148c2ecf20Sopenharmony_ci return rval; 36158c2ecf20Sopenharmony_ci} 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_cistatic int ioc_hdrlist(void __user *arg, char *cmnd) 36188c2ecf20Sopenharmony_ci{ 36198c2ecf20Sopenharmony_ci gdth_ioctl_rescan *rsc; 36208c2ecf20Sopenharmony_ci gdth_cmd_str *cmd; 36218c2ecf20Sopenharmony_ci gdth_ha_str *ha; 36228c2ecf20Sopenharmony_ci u8 i; 36238c2ecf20Sopenharmony_ci int rc = -ENOMEM; 36248c2ecf20Sopenharmony_ci u32 cluster_type = 0; 36258c2ecf20Sopenharmony_ci 36268c2ecf20Sopenharmony_ci rsc = kmalloc(sizeof(*rsc), GFP_KERNEL); 36278c2ecf20Sopenharmony_ci cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); 36288c2ecf20Sopenharmony_ci if (!rsc || !cmd) 36298c2ecf20Sopenharmony_ci goto free_fail; 36308c2ecf20Sopenharmony_ci 36318c2ecf20Sopenharmony_ci if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) || 36328c2ecf20Sopenharmony_ci (NULL == (ha = gdth_find_ha(rsc->ionode)))) { 36338c2ecf20Sopenharmony_ci rc = -EFAULT; 36348c2ecf20Sopenharmony_ci goto free_fail; 36358c2ecf20Sopenharmony_ci } 36368c2ecf20Sopenharmony_ci memset(cmd, 0, sizeof(gdth_cmd_str)); 36378c2ecf20Sopenharmony_ci 36388c2ecf20Sopenharmony_ci for (i = 0; i < MAX_HDRIVES; ++i) { 36398c2ecf20Sopenharmony_ci if (!ha->hdr[i].present) { 36408c2ecf20Sopenharmony_ci rsc->hdr_list[i].bus = 0xff; 36418c2ecf20Sopenharmony_ci continue; 36428c2ecf20Sopenharmony_ci } 36438c2ecf20Sopenharmony_ci rsc->hdr_list[i].bus = ha->virt_bus; 36448c2ecf20Sopenharmony_ci rsc->hdr_list[i].target = i; 36458c2ecf20Sopenharmony_ci rsc->hdr_list[i].lun = 0; 36468c2ecf20Sopenharmony_ci rsc->hdr_list[i].cluster_type = ha->hdr[i].cluster_type; 36478c2ecf20Sopenharmony_ci if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) { 36488c2ecf20Sopenharmony_ci cmd->Service = CACHESERVICE; 36498c2ecf20Sopenharmony_ci cmd->OpCode = GDT_CLUST_INFO; 36508c2ecf20Sopenharmony_ci if (ha->cache_feat & GDT_64BIT) 36518c2ecf20Sopenharmony_ci cmd->u.cache64.DeviceNo = i; 36528c2ecf20Sopenharmony_ci else 36538c2ecf20Sopenharmony_ci cmd->u.cache.DeviceNo = i; 36548c2ecf20Sopenharmony_ci if (__gdth_execute(ha->sdev, cmd, cmnd, 30, &cluster_type) == S_OK) 36558c2ecf20Sopenharmony_ci rsc->hdr_list[i].cluster_type = cluster_type; 36568c2ecf20Sopenharmony_ci } 36578c2ecf20Sopenharmony_ci } 36588c2ecf20Sopenharmony_ci 36598c2ecf20Sopenharmony_ci if (copy_to_user(arg, rsc, sizeof(gdth_ioctl_rescan))) 36608c2ecf20Sopenharmony_ci rc = -EFAULT; 36618c2ecf20Sopenharmony_ci else 36628c2ecf20Sopenharmony_ci rc = 0; 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_cifree_fail: 36658c2ecf20Sopenharmony_ci kfree(rsc); 36668c2ecf20Sopenharmony_ci kfree(cmd); 36678c2ecf20Sopenharmony_ci return rc; 36688c2ecf20Sopenharmony_ci} 36698c2ecf20Sopenharmony_ci 36708c2ecf20Sopenharmony_cistatic int ioc_rescan(void __user *arg, char *cmnd) 36718c2ecf20Sopenharmony_ci{ 36728c2ecf20Sopenharmony_ci gdth_ioctl_rescan *rsc; 36738c2ecf20Sopenharmony_ci gdth_cmd_str *cmd; 36748c2ecf20Sopenharmony_ci u16 i, status, hdr_cnt; 36758c2ecf20Sopenharmony_ci u32 info; 36768c2ecf20Sopenharmony_ci int cyls, hds, secs; 36778c2ecf20Sopenharmony_ci int rc = -ENOMEM; 36788c2ecf20Sopenharmony_ci unsigned long flags; 36798c2ecf20Sopenharmony_ci gdth_ha_str *ha; 36808c2ecf20Sopenharmony_ci 36818c2ecf20Sopenharmony_ci rsc = kmalloc(sizeof(*rsc), GFP_KERNEL); 36828c2ecf20Sopenharmony_ci cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); 36838c2ecf20Sopenharmony_ci if (!cmd || !rsc) 36848c2ecf20Sopenharmony_ci goto free_fail; 36858c2ecf20Sopenharmony_ci 36868c2ecf20Sopenharmony_ci if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) || 36878c2ecf20Sopenharmony_ci (NULL == (ha = gdth_find_ha(rsc->ionode)))) { 36888c2ecf20Sopenharmony_ci rc = -EFAULT; 36898c2ecf20Sopenharmony_ci goto free_fail; 36908c2ecf20Sopenharmony_ci } 36918c2ecf20Sopenharmony_ci memset(cmd, 0, sizeof(gdth_cmd_str)); 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_ci if (rsc->flag == 0) { 36948c2ecf20Sopenharmony_ci /* old method: re-init. cache service */ 36958c2ecf20Sopenharmony_ci cmd->Service = CACHESERVICE; 36968c2ecf20Sopenharmony_ci if (ha->cache_feat & GDT_64BIT) { 36978c2ecf20Sopenharmony_ci cmd->OpCode = GDT_X_INIT_HOST; 36988c2ecf20Sopenharmony_ci cmd->u.cache64.DeviceNo = LINUX_OS; 36998c2ecf20Sopenharmony_ci } else { 37008c2ecf20Sopenharmony_ci cmd->OpCode = GDT_INIT; 37018c2ecf20Sopenharmony_ci cmd->u.cache.DeviceNo = LINUX_OS; 37028c2ecf20Sopenharmony_ci } 37038c2ecf20Sopenharmony_ci 37048c2ecf20Sopenharmony_ci status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); 37058c2ecf20Sopenharmony_ci i = 0; 37068c2ecf20Sopenharmony_ci hdr_cnt = (status == S_OK ? (u16)info : 0); 37078c2ecf20Sopenharmony_ci } else { 37088c2ecf20Sopenharmony_ci i = rsc->hdr_no; 37098c2ecf20Sopenharmony_ci hdr_cnt = i + 1; 37108c2ecf20Sopenharmony_ci } 37118c2ecf20Sopenharmony_ci 37128c2ecf20Sopenharmony_ci for (; i < hdr_cnt && i < MAX_HDRIVES; ++i) { 37138c2ecf20Sopenharmony_ci cmd->Service = CACHESERVICE; 37148c2ecf20Sopenharmony_ci cmd->OpCode = GDT_INFO; 37158c2ecf20Sopenharmony_ci if (ha->cache_feat & GDT_64BIT) 37168c2ecf20Sopenharmony_ci cmd->u.cache64.DeviceNo = i; 37178c2ecf20Sopenharmony_ci else 37188c2ecf20Sopenharmony_ci cmd->u.cache.DeviceNo = i; 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_ci status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); 37218c2ecf20Sopenharmony_ci 37228c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 37238c2ecf20Sopenharmony_ci rsc->hdr_list[i].bus = ha->virt_bus; 37248c2ecf20Sopenharmony_ci rsc->hdr_list[i].target = i; 37258c2ecf20Sopenharmony_ci rsc->hdr_list[i].lun = 0; 37268c2ecf20Sopenharmony_ci if (status != S_OK) { 37278c2ecf20Sopenharmony_ci ha->hdr[i].present = FALSE; 37288c2ecf20Sopenharmony_ci } else { 37298c2ecf20Sopenharmony_ci ha->hdr[i].present = TRUE; 37308c2ecf20Sopenharmony_ci ha->hdr[i].size = info; 37318c2ecf20Sopenharmony_ci /* evaluate mapping */ 37328c2ecf20Sopenharmony_ci ha->hdr[i].size &= ~SECS32; 37338c2ecf20Sopenharmony_ci gdth_eval_mapping(ha->hdr[i].size,&cyls,&hds,&secs); 37348c2ecf20Sopenharmony_ci ha->hdr[i].heads = hds; 37358c2ecf20Sopenharmony_ci ha->hdr[i].secs = secs; 37368c2ecf20Sopenharmony_ci /* round size */ 37378c2ecf20Sopenharmony_ci ha->hdr[i].size = cyls * hds * secs; 37388c2ecf20Sopenharmony_ci } 37398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 37408c2ecf20Sopenharmony_ci if (status != S_OK) 37418c2ecf20Sopenharmony_ci continue; 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci /* extended info, if GDT_64BIT, for drives > 2 TB */ 37448c2ecf20Sopenharmony_ci /* but we need ha->info2, not yet stored in scp->SCp */ 37458c2ecf20Sopenharmony_ci 37468c2ecf20Sopenharmony_ci /* devtype, cluster info, R/W attribs */ 37478c2ecf20Sopenharmony_ci cmd->Service = CACHESERVICE; 37488c2ecf20Sopenharmony_ci cmd->OpCode = GDT_DEVTYPE; 37498c2ecf20Sopenharmony_ci if (ha->cache_feat & GDT_64BIT) 37508c2ecf20Sopenharmony_ci cmd->u.cache64.DeviceNo = i; 37518c2ecf20Sopenharmony_ci else 37528c2ecf20Sopenharmony_ci cmd->u.cache.DeviceNo = i; 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_ci status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); 37558c2ecf20Sopenharmony_ci 37568c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 37578c2ecf20Sopenharmony_ci ha->hdr[i].devtype = (status == S_OK ? (u16)info : 0); 37588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 37598c2ecf20Sopenharmony_ci 37608c2ecf20Sopenharmony_ci cmd->Service = CACHESERVICE; 37618c2ecf20Sopenharmony_ci cmd->OpCode = GDT_CLUST_INFO; 37628c2ecf20Sopenharmony_ci if (ha->cache_feat & GDT_64BIT) 37638c2ecf20Sopenharmony_ci cmd->u.cache64.DeviceNo = i; 37648c2ecf20Sopenharmony_ci else 37658c2ecf20Sopenharmony_ci cmd->u.cache.DeviceNo = i; 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_ci status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); 37688c2ecf20Sopenharmony_ci 37698c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 37708c2ecf20Sopenharmony_ci ha->hdr[i].cluster_type = 37718c2ecf20Sopenharmony_ci ((status == S_OK && !shared_access) ? (u16)info : 0); 37728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 37738c2ecf20Sopenharmony_ci rsc->hdr_list[i].cluster_type = ha->hdr[i].cluster_type; 37748c2ecf20Sopenharmony_ci 37758c2ecf20Sopenharmony_ci cmd->Service = CACHESERVICE; 37768c2ecf20Sopenharmony_ci cmd->OpCode = GDT_RW_ATTRIBS; 37778c2ecf20Sopenharmony_ci if (ha->cache_feat & GDT_64BIT) 37788c2ecf20Sopenharmony_ci cmd->u.cache64.DeviceNo = i; 37798c2ecf20Sopenharmony_ci else 37808c2ecf20Sopenharmony_ci cmd->u.cache.DeviceNo = i; 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_ci status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 37858c2ecf20Sopenharmony_ci ha->hdr[i].rw_attribs = (status == S_OK ? (u16)info : 0); 37868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 37878c2ecf20Sopenharmony_ci } 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_ci if (copy_to_user(arg, rsc, sizeof(gdth_ioctl_rescan))) 37908c2ecf20Sopenharmony_ci rc = -EFAULT; 37918c2ecf20Sopenharmony_ci else 37928c2ecf20Sopenharmony_ci rc = 0; 37938c2ecf20Sopenharmony_ci 37948c2ecf20Sopenharmony_cifree_fail: 37958c2ecf20Sopenharmony_ci kfree(rsc); 37968c2ecf20Sopenharmony_ci kfree(cmd); 37978c2ecf20Sopenharmony_ci return rc; 37988c2ecf20Sopenharmony_ci} 37998c2ecf20Sopenharmony_ci 38008c2ecf20Sopenharmony_cistatic int gdth_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) 38018c2ecf20Sopenharmony_ci{ 38028c2ecf20Sopenharmony_ci gdth_ha_str *ha; 38038c2ecf20Sopenharmony_ci struct scsi_cmnd *scp; 38048c2ecf20Sopenharmony_ci unsigned long flags; 38058c2ecf20Sopenharmony_ci char cmnd[MAX_COMMAND_SIZE]; 38068c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 38078c2ecf20Sopenharmony_ci 38088c2ecf20Sopenharmony_ci memset(cmnd, 0xff, 12); 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci TRACE(("gdth_ioctl() cmd 0x%x\n", cmd)); 38118c2ecf20Sopenharmony_ci 38128c2ecf20Sopenharmony_ci switch (cmd) { 38138c2ecf20Sopenharmony_ci case GDTIOCTL_CTRCNT: 38148c2ecf20Sopenharmony_ci { 38158c2ecf20Sopenharmony_ci int cnt = gdth_ctr_count; 38168c2ecf20Sopenharmony_ci if (put_user(cnt, (int __user *)argp)) 38178c2ecf20Sopenharmony_ci return -EFAULT; 38188c2ecf20Sopenharmony_ci break; 38198c2ecf20Sopenharmony_ci } 38208c2ecf20Sopenharmony_ci 38218c2ecf20Sopenharmony_ci case GDTIOCTL_DRVERS: 38228c2ecf20Sopenharmony_ci { 38238c2ecf20Sopenharmony_ci int ver = (GDTH_VERSION<<8) | GDTH_SUBVERSION; 38248c2ecf20Sopenharmony_ci if (put_user(ver, (int __user *)argp)) 38258c2ecf20Sopenharmony_ci return -EFAULT; 38268c2ecf20Sopenharmony_ci break; 38278c2ecf20Sopenharmony_ci } 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci case GDTIOCTL_OSVERS: 38308c2ecf20Sopenharmony_ci { 38318c2ecf20Sopenharmony_ci gdth_ioctl_osvers osv; 38328c2ecf20Sopenharmony_ci 38338c2ecf20Sopenharmony_ci osv.version = (u8)(LINUX_VERSION_CODE >> 16); 38348c2ecf20Sopenharmony_ci osv.subversion = (u8)(LINUX_VERSION_CODE >> 8); 38358c2ecf20Sopenharmony_ci osv.revision = (u16)(LINUX_VERSION_CODE & 0xff); 38368c2ecf20Sopenharmony_ci if (copy_to_user(argp, &osv, sizeof(gdth_ioctl_osvers))) 38378c2ecf20Sopenharmony_ci return -EFAULT; 38388c2ecf20Sopenharmony_ci break; 38398c2ecf20Sopenharmony_ci } 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci case GDTIOCTL_CTRTYPE: 38428c2ecf20Sopenharmony_ci { 38438c2ecf20Sopenharmony_ci gdth_ioctl_ctrtype ctrt; 38448c2ecf20Sopenharmony_ci 38458c2ecf20Sopenharmony_ci if (copy_from_user(&ctrt, argp, sizeof(gdth_ioctl_ctrtype)) || 38468c2ecf20Sopenharmony_ci (NULL == (ha = gdth_find_ha(ctrt.ionode)))) 38478c2ecf20Sopenharmony_ci return -EFAULT; 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci if (ha->type != GDT_PCIMPR) { 38508c2ecf20Sopenharmony_ci ctrt.type = (u8)((ha->stype<<4) + 6); 38518c2ecf20Sopenharmony_ci } else { 38528c2ecf20Sopenharmony_ci ctrt.type = (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe); 38538c2ecf20Sopenharmony_ci if (ha->stype >= 0x300) 38548c2ecf20Sopenharmony_ci ctrt.ext_type = 0x6000 | ha->pdev->subsystem_device; 38558c2ecf20Sopenharmony_ci else 38568c2ecf20Sopenharmony_ci ctrt.ext_type = 0x6000 | ha->stype; 38578c2ecf20Sopenharmony_ci } 38588c2ecf20Sopenharmony_ci ctrt.device_id = ha->pdev->device; 38598c2ecf20Sopenharmony_ci ctrt.sub_device_id = ha->pdev->subsystem_device; 38608c2ecf20Sopenharmony_ci ctrt.info = ha->brd_phys; 38618c2ecf20Sopenharmony_ci ctrt.oem_id = ha->oem_id; 38628c2ecf20Sopenharmony_ci if (copy_to_user(argp, &ctrt, sizeof(gdth_ioctl_ctrtype))) 38638c2ecf20Sopenharmony_ci return -EFAULT; 38648c2ecf20Sopenharmony_ci break; 38658c2ecf20Sopenharmony_ci } 38668c2ecf20Sopenharmony_ci 38678c2ecf20Sopenharmony_ci case GDTIOCTL_GENERAL: 38688c2ecf20Sopenharmony_ci return ioc_general(argp, cmnd); 38698c2ecf20Sopenharmony_ci 38708c2ecf20Sopenharmony_ci case GDTIOCTL_EVENT: 38718c2ecf20Sopenharmony_ci return ioc_event(argp); 38728c2ecf20Sopenharmony_ci 38738c2ecf20Sopenharmony_ci case GDTIOCTL_LOCKDRV: 38748c2ecf20Sopenharmony_ci return ioc_lockdrv(argp); 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_ci case GDTIOCTL_LOCKCHN: 38778c2ecf20Sopenharmony_ci { 38788c2ecf20Sopenharmony_ci gdth_ioctl_lockchn lchn; 38798c2ecf20Sopenharmony_ci u8 i, j; 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_ci if (copy_from_user(&lchn, argp, sizeof(gdth_ioctl_lockchn)) || 38828c2ecf20Sopenharmony_ci (NULL == (ha = gdth_find_ha(lchn.ionode)))) 38838c2ecf20Sopenharmony_ci return -EFAULT; 38848c2ecf20Sopenharmony_ci 38858c2ecf20Sopenharmony_ci i = lchn.channel; 38868c2ecf20Sopenharmony_ci if (i < ha->bus_cnt) { 38878c2ecf20Sopenharmony_ci if (lchn.lock) { 38888c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 38898c2ecf20Sopenharmony_ci ha->raw[i].lock = 1; 38908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 38918c2ecf20Sopenharmony_ci for (j = 0; j < ha->tid_cnt; ++j) 38928c2ecf20Sopenharmony_ci gdth_wait_completion(ha, i, j); 38938c2ecf20Sopenharmony_ci } else { 38948c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->smp_lock, flags); 38958c2ecf20Sopenharmony_ci ha->raw[i].lock = 0; 38968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->smp_lock, flags); 38978c2ecf20Sopenharmony_ci for (j = 0; j < ha->tid_cnt; ++j) 38988c2ecf20Sopenharmony_ci gdth_next(ha); 38998c2ecf20Sopenharmony_ci } 39008c2ecf20Sopenharmony_ci } 39018c2ecf20Sopenharmony_ci break; 39028c2ecf20Sopenharmony_ci } 39038c2ecf20Sopenharmony_ci 39048c2ecf20Sopenharmony_ci case GDTIOCTL_RESCAN: 39058c2ecf20Sopenharmony_ci return ioc_rescan(argp, cmnd); 39068c2ecf20Sopenharmony_ci 39078c2ecf20Sopenharmony_ci case GDTIOCTL_HDRLIST: 39088c2ecf20Sopenharmony_ci return ioc_hdrlist(argp, cmnd); 39098c2ecf20Sopenharmony_ci 39108c2ecf20Sopenharmony_ci case GDTIOCTL_RESET_BUS: 39118c2ecf20Sopenharmony_ci { 39128c2ecf20Sopenharmony_ci gdth_ioctl_reset res; 39138c2ecf20Sopenharmony_ci int rval; 39148c2ecf20Sopenharmony_ci 39158c2ecf20Sopenharmony_ci if (copy_from_user(&res, argp, sizeof(gdth_ioctl_reset)) || 39168c2ecf20Sopenharmony_ci (NULL == (ha = gdth_find_ha(res.ionode)))) 39178c2ecf20Sopenharmony_ci return -EFAULT; 39188c2ecf20Sopenharmony_ci 39198c2ecf20Sopenharmony_ci scp = kzalloc(sizeof(*scp), GFP_KERNEL); 39208c2ecf20Sopenharmony_ci if (!scp) 39218c2ecf20Sopenharmony_ci return -ENOMEM; 39228c2ecf20Sopenharmony_ci scp->device = ha->sdev; 39238c2ecf20Sopenharmony_ci scp->cmd_len = 12; 39248c2ecf20Sopenharmony_ci scp->device->channel = res.number; 39258c2ecf20Sopenharmony_ci rval = gdth_eh_bus_reset(scp); 39268c2ecf20Sopenharmony_ci res.status = (rval == SUCCESS ? S_OK : S_GENERR); 39278c2ecf20Sopenharmony_ci kfree(scp); 39288c2ecf20Sopenharmony_ci 39298c2ecf20Sopenharmony_ci if (copy_to_user(argp, &res, sizeof(gdth_ioctl_reset))) 39308c2ecf20Sopenharmony_ci return -EFAULT; 39318c2ecf20Sopenharmony_ci break; 39328c2ecf20Sopenharmony_ci } 39338c2ecf20Sopenharmony_ci 39348c2ecf20Sopenharmony_ci case GDTIOCTL_RESET_DRV: 39358c2ecf20Sopenharmony_ci return ioc_resetdrv(argp, cmnd); 39368c2ecf20Sopenharmony_ci 39378c2ecf20Sopenharmony_ci default: 39388c2ecf20Sopenharmony_ci break; 39398c2ecf20Sopenharmony_ci } 39408c2ecf20Sopenharmony_ci return 0; 39418c2ecf20Sopenharmony_ci} 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_cistatic long gdth_unlocked_ioctl(struct file *file, unsigned int cmd, 39448c2ecf20Sopenharmony_ci unsigned long arg) 39458c2ecf20Sopenharmony_ci{ 39468c2ecf20Sopenharmony_ci int ret; 39478c2ecf20Sopenharmony_ci 39488c2ecf20Sopenharmony_ci mutex_lock(&gdth_mutex); 39498c2ecf20Sopenharmony_ci ret = gdth_ioctl(file, cmd, arg); 39508c2ecf20Sopenharmony_ci mutex_unlock(&gdth_mutex); 39518c2ecf20Sopenharmony_ci 39528c2ecf20Sopenharmony_ci return ret; 39538c2ecf20Sopenharmony_ci} 39548c2ecf20Sopenharmony_ci 39558c2ecf20Sopenharmony_ci/* flush routine */ 39568c2ecf20Sopenharmony_cistatic void gdth_flush(gdth_ha_str *ha) 39578c2ecf20Sopenharmony_ci{ 39588c2ecf20Sopenharmony_ci int i; 39598c2ecf20Sopenharmony_ci gdth_cmd_str gdtcmd; 39608c2ecf20Sopenharmony_ci char cmnd[MAX_COMMAND_SIZE]; 39618c2ecf20Sopenharmony_ci memset(cmnd, 0xff, MAX_COMMAND_SIZE); 39628c2ecf20Sopenharmony_ci 39638c2ecf20Sopenharmony_ci TRACE2(("gdth_flush() hanum %d\n", ha->hanum)); 39648c2ecf20Sopenharmony_ci 39658c2ecf20Sopenharmony_ci for (i = 0; i < MAX_HDRIVES; ++i) { 39668c2ecf20Sopenharmony_ci if (ha->hdr[i].present) { 39678c2ecf20Sopenharmony_ci gdtcmd.BoardNode = LOCALBOARD; 39688c2ecf20Sopenharmony_ci gdtcmd.Service = CACHESERVICE; 39698c2ecf20Sopenharmony_ci gdtcmd.OpCode = GDT_FLUSH; 39708c2ecf20Sopenharmony_ci if (ha->cache_feat & GDT_64BIT) { 39718c2ecf20Sopenharmony_ci gdtcmd.u.cache64.DeviceNo = i; 39728c2ecf20Sopenharmony_ci gdtcmd.u.cache64.BlockNo = 1; 39738c2ecf20Sopenharmony_ci gdtcmd.u.cache64.sg_canz = 0; 39748c2ecf20Sopenharmony_ci } else { 39758c2ecf20Sopenharmony_ci gdtcmd.u.cache.DeviceNo = i; 39768c2ecf20Sopenharmony_ci gdtcmd.u.cache.BlockNo = 1; 39778c2ecf20Sopenharmony_ci gdtcmd.u.cache.sg_canz = 0; 39788c2ecf20Sopenharmony_ci } 39798c2ecf20Sopenharmony_ci TRACE2(("gdth_flush(): flush ha %d drive %d\n", ha->hanum, i)); 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci gdth_execute(ha->shost, &gdtcmd, cmnd, 30, NULL); 39828c2ecf20Sopenharmony_ci } 39838c2ecf20Sopenharmony_ci } 39848c2ecf20Sopenharmony_ci} 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_ci/* configure lun */ 39878c2ecf20Sopenharmony_cistatic int gdth_slave_configure(struct scsi_device *sdev) 39888c2ecf20Sopenharmony_ci{ 39898c2ecf20Sopenharmony_ci sdev->skip_ms_page_3f = 1; 39908c2ecf20Sopenharmony_ci sdev->skip_ms_page_8 = 1; 39918c2ecf20Sopenharmony_ci return 0; 39928c2ecf20Sopenharmony_ci} 39938c2ecf20Sopenharmony_ci 39948c2ecf20Sopenharmony_cistatic struct scsi_host_template gdth_template = { 39958c2ecf20Sopenharmony_ci .name = "GDT SCSI Disk Array Controller", 39968c2ecf20Sopenharmony_ci .info = gdth_info, 39978c2ecf20Sopenharmony_ci .queuecommand = gdth_queuecommand, 39988c2ecf20Sopenharmony_ci .eh_bus_reset_handler = gdth_eh_bus_reset, 39998c2ecf20Sopenharmony_ci .slave_configure = gdth_slave_configure, 40008c2ecf20Sopenharmony_ci .bios_param = gdth_bios_param, 40018c2ecf20Sopenharmony_ci .show_info = gdth_show_info, 40028c2ecf20Sopenharmony_ci .write_info = gdth_set_info, 40038c2ecf20Sopenharmony_ci .eh_timed_out = gdth_timed_out, 40048c2ecf20Sopenharmony_ci .proc_name = "gdth", 40058c2ecf20Sopenharmony_ci .can_queue = GDTH_MAXCMDS, 40068c2ecf20Sopenharmony_ci .this_id = -1, 40078c2ecf20Sopenharmony_ci .sg_tablesize = GDTH_MAXSG, 40088c2ecf20Sopenharmony_ci .cmd_per_lun = GDTH_MAXC_P_L, 40098c2ecf20Sopenharmony_ci .unchecked_isa_dma = 1, 40108c2ecf20Sopenharmony_ci .no_write_same = 1, 40118c2ecf20Sopenharmony_ci}; 40128c2ecf20Sopenharmony_ci 40138c2ecf20Sopenharmony_cistatic int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out) 40148c2ecf20Sopenharmony_ci{ 40158c2ecf20Sopenharmony_ci struct Scsi_Host *shp; 40168c2ecf20Sopenharmony_ci gdth_ha_str *ha; 40178c2ecf20Sopenharmony_ci dma_addr_t scratch_dma_handle = 0; 40188c2ecf20Sopenharmony_ci int error, i; 40198c2ecf20Sopenharmony_ci struct pci_dev *pdev = pcistr->pdev; 40208c2ecf20Sopenharmony_ci 40218c2ecf20Sopenharmony_ci *ha_out = NULL; 40228c2ecf20Sopenharmony_ci 40238c2ecf20Sopenharmony_ci shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str)); 40248c2ecf20Sopenharmony_ci if (!shp) 40258c2ecf20Sopenharmony_ci return -ENOMEM; 40268c2ecf20Sopenharmony_ci ha = shost_priv(shp); 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci error = -ENODEV; 40298c2ecf20Sopenharmony_ci if (!gdth_init_pci(pdev, pcistr, ha)) 40308c2ecf20Sopenharmony_ci goto out_host_put; 40318c2ecf20Sopenharmony_ci 40328c2ecf20Sopenharmony_ci /* controller found and initialized */ 40338c2ecf20Sopenharmony_ci printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n", 40348c2ecf20Sopenharmony_ci pdev->bus->number, 40358c2ecf20Sopenharmony_ci PCI_SLOT(pdev->devfn), 40368c2ecf20Sopenharmony_ci ha->irq); 40378c2ecf20Sopenharmony_ci 40388c2ecf20Sopenharmony_ci error = request_irq(ha->irq, gdth_interrupt, 40398c2ecf20Sopenharmony_ci IRQF_SHARED, "gdth", ha); 40408c2ecf20Sopenharmony_ci if (error) { 40418c2ecf20Sopenharmony_ci printk("GDT-PCI: Unable to allocate IRQ\n"); 40428c2ecf20Sopenharmony_ci goto out_host_put; 40438c2ecf20Sopenharmony_ci } 40448c2ecf20Sopenharmony_ci 40458c2ecf20Sopenharmony_ci shp->unchecked_isa_dma = 0; 40468c2ecf20Sopenharmony_ci shp->irq = ha->irq; 40478c2ecf20Sopenharmony_ci shp->dma_channel = 0xff; 40488c2ecf20Sopenharmony_ci 40498c2ecf20Sopenharmony_ci ha->hanum = gdth_ctr_count++; 40508c2ecf20Sopenharmony_ci ha->shost = shp; 40518c2ecf20Sopenharmony_ci 40528c2ecf20Sopenharmony_ci ha->pccb = &ha->cmdext; 40538c2ecf20Sopenharmony_ci ha->ccb_phys = 0L; 40548c2ecf20Sopenharmony_ci 40558c2ecf20Sopenharmony_ci error = -ENOMEM; 40568c2ecf20Sopenharmony_ci 40578c2ecf20Sopenharmony_ci ha->pscratch = dma_alloc_coherent(&ha->pdev->dev, GDTH_SCRATCH, 40588c2ecf20Sopenharmony_ci &scratch_dma_handle, GFP_KERNEL); 40598c2ecf20Sopenharmony_ci if (!ha->pscratch) 40608c2ecf20Sopenharmony_ci goto out_free_irq; 40618c2ecf20Sopenharmony_ci ha->scratch_phys = scratch_dma_handle; 40628c2ecf20Sopenharmony_ci 40638c2ecf20Sopenharmony_ci ha->pmsg = dma_alloc_coherent(&ha->pdev->dev, sizeof(gdth_msg_str), 40648c2ecf20Sopenharmony_ci &scratch_dma_handle, GFP_KERNEL); 40658c2ecf20Sopenharmony_ci if (!ha->pmsg) 40668c2ecf20Sopenharmony_ci goto out_free_pscratch; 40678c2ecf20Sopenharmony_ci ha->msg_phys = scratch_dma_handle; 40688c2ecf20Sopenharmony_ci 40698c2ecf20Sopenharmony_ci ha->scratch_busy = FALSE; 40708c2ecf20Sopenharmony_ci ha->req_first = NULL; 40718c2ecf20Sopenharmony_ci ha->tid_cnt = pdev->device >= 0x200 ? MAXID : MAX_HDRIVES; 40728c2ecf20Sopenharmony_ci if (max_ids > 0 && max_ids < ha->tid_cnt) 40738c2ecf20Sopenharmony_ci ha->tid_cnt = max_ids; 40748c2ecf20Sopenharmony_ci for (i = 0; i < GDTH_MAXCMDS; ++i) 40758c2ecf20Sopenharmony_ci ha->cmd_tab[i].cmnd = UNUSED_CMND; 40768c2ecf20Sopenharmony_ci ha->scan_mode = rescan ? 0x10 : 0; 40778c2ecf20Sopenharmony_ci 40788c2ecf20Sopenharmony_ci error = -ENODEV; 40798c2ecf20Sopenharmony_ci if (!gdth_search_drives(ha)) { 40808c2ecf20Sopenharmony_ci printk("GDT-PCI %d: Error during device scan\n", ha->hanum); 40818c2ecf20Sopenharmony_ci goto out_free_pmsg; 40828c2ecf20Sopenharmony_ci } 40838c2ecf20Sopenharmony_ci 40848c2ecf20Sopenharmony_ci if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) 40858c2ecf20Sopenharmony_ci hdr_channel = ha->bus_cnt; 40868c2ecf20Sopenharmony_ci ha->virt_bus = hdr_channel; 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci /* 64-bit DMA only supported from FW >= x.43 */ 40898c2ecf20Sopenharmony_ci if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) || 40908c2ecf20Sopenharmony_ci !ha->dma64_support) { 40918c2ecf20Sopenharmony_ci if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { 40928c2ecf20Sopenharmony_ci printk(KERN_WARNING "GDT-PCI %d: " 40938c2ecf20Sopenharmony_ci "Unable to set 32-bit DMA\n", ha->hanum); 40948c2ecf20Sopenharmony_ci goto out_free_pmsg; 40958c2ecf20Sopenharmony_ci } 40968c2ecf20Sopenharmony_ci } else { 40978c2ecf20Sopenharmony_ci shp->max_cmd_len = 16; 40988c2ecf20Sopenharmony_ci if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { 40998c2ecf20Sopenharmony_ci printk("GDT-PCI %d: 64-bit DMA enabled\n", ha->hanum); 41008c2ecf20Sopenharmony_ci } else if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { 41018c2ecf20Sopenharmony_ci printk(KERN_WARNING "GDT-PCI %d: " 41028c2ecf20Sopenharmony_ci "Unable to set 64/32-bit DMA\n", ha->hanum); 41038c2ecf20Sopenharmony_ci goto out_free_pmsg; 41048c2ecf20Sopenharmony_ci } 41058c2ecf20Sopenharmony_ci } 41068c2ecf20Sopenharmony_ci 41078c2ecf20Sopenharmony_ci shp->max_id = ha->tid_cnt; 41088c2ecf20Sopenharmony_ci shp->max_lun = MAXLUN; 41098c2ecf20Sopenharmony_ci shp->max_channel = ha->bus_cnt; 41108c2ecf20Sopenharmony_ci 41118c2ecf20Sopenharmony_ci spin_lock_init(&ha->smp_lock); 41128c2ecf20Sopenharmony_ci gdth_enable_int(ha); 41138c2ecf20Sopenharmony_ci 41148c2ecf20Sopenharmony_ci error = scsi_add_host(shp, &pdev->dev); 41158c2ecf20Sopenharmony_ci if (error) 41168c2ecf20Sopenharmony_ci goto out_free_pmsg; 41178c2ecf20Sopenharmony_ci list_add_tail(&ha->list, &gdth_instances); 41188c2ecf20Sopenharmony_ci 41198c2ecf20Sopenharmony_ci pci_set_drvdata(ha->pdev, ha); 41208c2ecf20Sopenharmony_ci gdth_timer_init(); 41218c2ecf20Sopenharmony_ci 41228c2ecf20Sopenharmony_ci scsi_scan_host(shp); 41238c2ecf20Sopenharmony_ci 41248c2ecf20Sopenharmony_ci *ha_out = ha; 41258c2ecf20Sopenharmony_ci 41268c2ecf20Sopenharmony_ci return 0; 41278c2ecf20Sopenharmony_ci 41288c2ecf20Sopenharmony_ci out_free_pmsg: 41298c2ecf20Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(gdth_msg_str), 41308c2ecf20Sopenharmony_ci ha->pmsg, ha->msg_phys); 41318c2ecf20Sopenharmony_ci out_free_pscratch: 41328c2ecf20Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, GDTH_SCRATCH, 41338c2ecf20Sopenharmony_ci ha->pscratch, ha->scratch_phys); 41348c2ecf20Sopenharmony_ci out_free_irq: 41358c2ecf20Sopenharmony_ci free_irq(ha->irq, ha); 41368c2ecf20Sopenharmony_ci gdth_ctr_count--; 41378c2ecf20Sopenharmony_ci out_host_put: 41388c2ecf20Sopenharmony_ci scsi_host_put(shp); 41398c2ecf20Sopenharmony_ci return error; 41408c2ecf20Sopenharmony_ci} 41418c2ecf20Sopenharmony_ci 41428c2ecf20Sopenharmony_cistatic void gdth_remove_one(gdth_ha_str *ha) 41438c2ecf20Sopenharmony_ci{ 41448c2ecf20Sopenharmony_ci struct Scsi_Host *shp = ha->shost; 41458c2ecf20Sopenharmony_ci 41468c2ecf20Sopenharmony_ci TRACE2(("gdth_remove_one()\n")); 41478c2ecf20Sopenharmony_ci 41488c2ecf20Sopenharmony_ci scsi_remove_host(shp); 41498c2ecf20Sopenharmony_ci 41508c2ecf20Sopenharmony_ci gdth_flush(ha); 41518c2ecf20Sopenharmony_ci 41528c2ecf20Sopenharmony_ci if (ha->sdev) { 41538c2ecf20Sopenharmony_ci scsi_free_host_dev(ha->sdev); 41548c2ecf20Sopenharmony_ci ha->sdev = NULL; 41558c2ecf20Sopenharmony_ci } 41568c2ecf20Sopenharmony_ci 41578c2ecf20Sopenharmony_ci if (shp->irq) 41588c2ecf20Sopenharmony_ci free_irq(shp->irq,ha); 41598c2ecf20Sopenharmony_ci 41608c2ecf20Sopenharmony_ci if (ha->pscratch) 41618c2ecf20Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, GDTH_SCRATCH, 41628c2ecf20Sopenharmony_ci ha->pscratch, ha->scratch_phys); 41638c2ecf20Sopenharmony_ci if (ha->pmsg) 41648c2ecf20Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(gdth_msg_str), 41658c2ecf20Sopenharmony_ci ha->pmsg, ha->msg_phys); 41668c2ecf20Sopenharmony_ci if (ha->ccb_phys) 41678c2ecf20Sopenharmony_ci dma_unmap_single(&ha->pdev->dev, ha->ccb_phys, 41688c2ecf20Sopenharmony_ci sizeof(gdth_cmd_str), DMA_BIDIRECTIONAL); 41698c2ecf20Sopenharmony_ci 41708c2ecf20Sopenharmony_ci scsi_host_put(shp); 41718c2ecf20Sopenharmony_ci} 41728c2ecf20Sopenharmony_ci 41738c2ecf20Sopenharmony_cistatic int gdth_halt(struct notifier_block *nb, unsigned long event, void *buf) 41748c2ecf20Sopenharmony_ci{ 41758c2ecf20Sopenharmony_ci gdth_ha_str *ha; 41768c2ecf20Sopenharmony_ci 41778c2ecf20Sopenharmony_ci TRACE2(("gdth_halt() event %d\n", (int)event)); 41788c2ecf20Sopenharmony_ci if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) 41798c2ecf20Sopenharmony_ci return NOTIFY_DONE; 41808c2ecf20Sopenharmony_ci 41818c2ecf20Sopenharmony_ci list_for_each_entry(ha, &gdth_instances, list) 41828c2ecf20Sopenharmony_ci gdth_flush(ha); 41838c2ecf20Sopenharmony_ci 41848c2ecf20Sopenharmony_ci return NOTIFY_OK; 41858c2ecf20Sopenharmony_ci} 41868c2ecf20Sopenharmony_ci 41878c2ecf20Sopenharmony_cistatic struct notifier_block gdth_notifier = { 41888c2ecf20Sopenharmony_ci gdth_halt, NULL, 0 41898c2ecf20Sopenharmony_ci}; 41908c2ecf20Sopenharmony_ci 41918c2ecf20Sopenharmony_cistatic int __init gdth_init(void) 41928c2ecf20Sopenharmony_ci{ 41938c2ecf20Sopenharmony_ci if (disable) { 41948c2ecf20Sopenharmony_ci printk("GDT-HA: Controller driver disabled from" 41958c2ecf20Sopenharmony_ci " command line !\n"); 41968c2ecf20Sopenharmony_ci return 0; 41978c2ecf20Sopenharmony_ci } 41988c2ecf20Sopenharmony_ci 41998c2ecf20Sopenharmony_ci printk("GDT-HA: Storage RAID Controller Driver. Version: %s\n", 42008c2ecf20Sopenharmony_ci GDTH_VERSION_STR); 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_ci /* initializations */ 42038c2ecf20Sopenharmony_ci gdth_polling = TRUE; 42048c2ecf20Sopenharmony_ci gdth_clear_events(); 42058c2ecf20Sopenharmony_ci timer_setup(&gdth_timer, gdth_timeout, 0); 42068c2ecf20Sopenharmony_ci 42078c2ecf20Sopenharmony_ci /* scanning for PCI controllers */ 42088c2ecf20Sopenharmony_ci if (pci_register_driver(&gdth_pci_driver)) { 42098c2ecf20Sopenharmony_ci gdth_ha_str *ha; 42108c2ecf20Sopenharmony_ci 42118c2ecf20Sopenharmony_ci list_for_each_entry(ha, &gdth_instances, list) 42128c2ecf20Sopenharmony_ci gdth_remove_one(ha); 42138c2ecf20Sopenharmony_ci return -ENODEV; 42148c2ecf20Sopenharmony_ci } 42158c2ecf20Sopenharmony_ci 42168c2ecf20Sopenharmony_ci TRACE2(("gdth_detect() %d controller detected\n", gdth_ctr_count)); 42178c2ecf20Sopenharmony_ci 42188c2ecf20Sopenharmony_ci major = register_chrdev(0,"gdth", &gdth_fops); 42198c2ecf20Sopenharmony_ci register_reboot_notifier(&gdth_notifier); 42208c2ecf20Sopenharmony_ci gdth_polling = FALSE; 42218c2ecf20Sopenharmony_ci return 0; 42228c2ecf20Sopenharmony_ci} 42238c2ecf20Sopenharmony_ci 42248c2ecf20Sopenharmony_cistatic void __exit gdth_exit(void) 42258c2ecf20Sopenharmony_ci{ 42268c2ecf20Sopenharmony_ci gdth_ha_str *ha; 42278c2ecf20Sopenharmony_ci 42288c2ecf20Sopenharmony_ci unregister_chrdev(major, "gdth"); 42298c2ecf20Sopenharmony_ci unregister_reboot_notifier(&gdth_notifier); 42308c2ecf20Sopenharmony_ci 42318c2ecf20Sopenharmony_ci#ifdef GDTH_STATISTICS 42328c2ecf20Sopenharmony_ci del_timer_sync(&gdth_timer); 42338c2ecf20Sopenharmony_ci#endif 42348c2ecf20Sopenharmony_ci 42358c2ecf20Sopenharmony_ci pci_unregister_driver(&gdth_pci_driver); 42368c2ecf20Sopenharmony_ci 42378c2ecf20Sopenharmony_ci list_for_each_entry(ha, &gdth_instances, list) 42388c2ecf20Sopenharmony_ci gdth_remove_one(ha); 42398c2ecf20Sopenharmony_ci} 42408c2ecf20Sopenharmony_ci 42418c2ecf20Sopenharmony_cimodule_init(gdth_init); 42428c2ecf20Sopenharmony_cimodule_exit(gdth_exit); 42438c2ecf20Sopenharmony_ci 42448c2ecf20Sopenharmony_ci#ifndef MODULE 42458c2ecf20Sopenharmony_cistatic void __init internal_setup(char *str,int *ints) 42468c2ecf20Sopenharmony_ci{ 42478c2ecf20Sopenharmony_ci int i; 42488c2ecf20Sopenharmony_ci char *cur_str, *argv; 42498c2ecf20Sopenharmony_ci 42508c2ecf20Sopenharmony_ci TRACE2(("internal_setup() str %s ints[0] %d\n", 42518c2ecf20Sopenharmony_ci str ? str:"NULL", ints ? ints[0]:0)); 42528c2ecf20Sopenharmony_ci 42538c2ecf20Sopenharmony_ci /* analyse string */ 42548c2ecf20Sopenharmony_ci argv = str; 42558c2ecf20Sopenharmony_ci while (argv && (cur_str = strchr(argv, ':'))) { 42568c2ecf20Sopenharmony_ci int val = 0, c = *++cur_str; 42578c2ecf20Sopenharmony_ci 42588c2ecf20Sopenharmony_ci if (c == 'n' || c == 'N') 42598c2ecf20Sopenharmony_ci val = 0; 42608c2ecf20Sopenharmony_ci else if (c == 'y' || c == 'Y') 42618c2ecf20Sopenharmony_ci val = 1; 42628c2ecf20Sopenharmony_ci else 42638c2ecf20Sopenharmony_ci val = (int)simple_strtoul(cur_str, NULL, 0); 42648c2ecf20Sopenharmony_ci 42658c2ecf20Sopenharmony_ci if (!strncmp(argv, "disable:", 8)) 42668c2ecf20Sopenharmony_ci disable = val; 42678c2ecf20Sopenharmony_ci else if (!strncmp(argv, "reserve_mode:", 13)) 42688c2ecf20Sopenharmony_ci reserve_mode = val; 42698c2ecf20Sopenharmony_ci else if (!strncmp(argv, "reverse_scan:", 13)) 42708c2ecf20Sopenharmony_ci reverse_scan = val; 42718c2ecf20Sopenharmony_ci else if (!strncmp(argv, "hdr_channel:", 12)) 42728c2ecf20Sopenharmony_ci hdr_channel = val; 42738c2ecf20Sopenharmony_ci else if (!strncmp(argv, "max_ids:", 8)) 42748c2ecf20Sopenharmony_ci max_ids = val; 42758c2ecf20Sopenharmony_ci else if (!strncmp(argv, "rescan:", 7)) 42768c2ecf20Sopenharmony_ci rescan = val; 42778c2ecf20Sopenharmony_ci else if (!strncmp(argv, "shared_access:", 14)) 42788c2ecf20Sopenharmony_ci shared_access = val; 42798c2ecf20Sopenharmony_ci else if (!strncmp(argv, "reserve_list:", 13)) { 42808c2ecf20Sopenharmony_ci reserve_list[0] = val; 42818c2ecf20Sopenharmony_ci for (i = 1; i < MAX_RES_ARGS; i++) { 42828c2ecf20Sopenharmony_ci cur_str = strchr(cur_str, ','); 42838c2ecf20Sopenharmony_ci if (!cur_str) 42848c2ecf20Sopenharmony_ci break; 42858c2ecf20Sopenharmony_ci if (!isdigit((int)*++cur_str)) { 42868c2ecf20Sopenharmony_ci --cur_str; 42878c2ecf20Sopenharmony_ci break; 42888c2ecf20Sopenharmony_ci } 42898c2ecf20Sopenharmony_ci reserve_list[i] = 42908c2ecf20Sopenharmony_ci (int)simple_strtoul(cur_str, NULL, 0); 42918c2ecf20Sopenharmony_ci } 42928c2ecf20Sopenharmony_ci if (!cur_str) 42938c2ecf20Sopenharmony_ci break; 42948c2ecf20Sopenharmony_ci argv = ++cur_str; 42958c2ecf20Sopenharmony_ci continue; 42968c2ecf20Sopenharmony_ci } 42978c2ecf20Sopenharmony_ci 42988c2ecf20Sopenharmony_ci if ((argv = strchr(argv, ','))) 42998c2ecf20Sopenharmony_ci ++argv; 43008c2ecf20Sopenharmony_ci } 43018c2ecf20Sopenharmony_ci} 43028c2ecf20Sopenharmony_ci 43038c2ecf20Sopenharmony_cistatic int __init option_setup(char *str) 43048c2ecf20Sopenharmony_ci{ 43058c2ecf20Sopenharmony_ci int ints[MAXHA]; 43068c2ecf20Sopenharmony_ci char *cur = str; 43078c2ecf20Sopenharmony_ci int i = 1; 43088c2ecf20Sopenharmony_ci 43098c2ecf20Sopenharmony_ci TRACE2(("option_setup() str %s\n", str ? str:"NULL")); 43108c2ecf20Sopenharmony_ci 43118c2ecf20Sopenharmony_ci while (cur && isdigit(*cur) && i < MAXHA) { 43128c2ecf20Sopenharmony_ci ints[i++] = simple_strtoul(cur, NULL, 0); 43138c2ecf20Sopenharmony_ci if ((cur = strchr(cur, ',')) != NULL) cur++; 43148c2ecf20Sopenharmony_ci } 43158c2ecf20Sopenharmony_ci 43168c2ecf20Sopenharmony_ci ints[0] = i - 1; 43178c2ecf20Sopenharmony_ci internal_setup(cur, ints); 43188c2ecf20Sopenharmony_ci return 1; 43198c2ecf20Sopenharmony_ci} 43208c2ecf20Sopenharmony_ci 43218c2ecf20Sopenharmony_ci__setup("gdth=", option_setup); 43228c2ecf20Sopenharmony_ci#endif 4323