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