gdth.c 174 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6
/************************************************************************
 * Linux driver for                                                     *  
 * ICP vortex GmbH:    GDT ISA/EISA/PCI Disk Array Controllers          *
 * Intel Corporation:  Storage RAID Controllers                         *
 *                                                                      *
 * gdth.c                                                               *
7
 * Copyright (C) 1995-06 ICP vortex GmbH, Achim Leubner                 *
Linus Torvalds's avatar
Linus Torvalds committed
8
 * Copyright (C) 2002-04 Intel Corporation                              *
9
 * Copyright (C) 2003-06 Adaptec Inc.                                   *
Linus Torvalds's avatar
Linus Torvalds committed
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 * <achim_leubner@adaptec.com>                                          *
 *                                                                      *
 * Additions/Fixes:                                                     *
 * Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com>               *
 * Johannes Dinner <johannes_dinner@adaptec.com>                        *
 *                                                                      *
 * This program is free software; you can redistribute it and/or modify *
 * it under the terms of the GNU General Public License as published    *
 * by the Free Software Foundation; either version 2 of the License,    *
 * or (at your option) any later version.                               *
 *                                                                      *
 * This program is distributed in the hope that it will be useful,      *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         *
 * GNU General Public License for more details.                         *
 *                                                                      *
 * You should have received a copy of the GNU General Public License    *
 * along with this kernel; if not, write to the Free Software           *
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
 *                                                                      *
30
 * Linux kernel 2.6.x supported						*
Linus Torvalds's avatar
Linus Torvalds committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
 *                                                                      *
 ************************************************************************/

/* All GDT Disk Array Controllers are fully supported by this driver.
 * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the
 * PCI Fibre Channel Disk Array Controllers. See gdth.h for a complete
 * list of all controller types.
 * 
 * If you have one or more GDT3000/3020 EISA controllers with 
 * controller BIOS disabled, you have to set the IRQ values with the 
 * command line option "gdth=irq1,irq2,...", where the irq1,irq2,... are
 * the IRQ values for the EISA controllers.
 * 
 * After the optional list of IRQ values, other possible 
 * command line options are:
 * disable:Y                    disable driver
 * disable:N                    enable driver
 * reserve_mode:0               reserve no drives for the raw service
 * reserve_mode:1               reserve all not init., removable drives
 * reserve_mode:2               reserve all not init. drives
 * reserve_list:h,b,t,l,h,b,t,l,...     reserve particular drive(s) with 
 *                              h- controller no., b- channel no., 
 *                              t- target ID, l- LUN
 * reverse_scan:Y               reverse scan order for PCI controllers         
 * reverse_scan:N               scan PCI controllers like BIOS
 * max_ids:x                    x - target ID count per channel (1..MAXID)
 * rescan:Y                     rescan all channels/IDs 
 * rescan:N                     use all devices found until now
 * hdr_channel:x                x - number of virtual bus for host drives
 * shared_access:Y              disable driver reserve/release protocol to 
 *                              access a shared resource from several nodes, 
62
 *                              appropriate controller firmware required
Linus Torvalds's avatar
Linus Torvalds committed
63 64 65 66 67 68 69
 * shared_access:N              enable driver reserve/release protocol
 * probe_eisa_isa:Y             scan for EISA/ISA controllers
 * probe_eisa_isa:N             do not scan for EISA/ISA controllers
 * force_dma32:Y                use only 32 bit DMA mode
 * force_dma32:N                use 64 bit DMA mode, if supported
 *
 * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
70
 *                          max_ids:127,rescan:N,hdr_channel:0,
Linus Torvalds's avatar
Linus Torvalds committed
71 72 73 74 75 76 77 78 79 80
 *                          shared_access:Y,probe_eisa_isa:N,force_dma32:N".
 * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y".
 * 
 * When loading the gdth driver as a module, the same options are available. 
 * You can set the IRQs with "IRQ=...". However, the syntax to specify the
 * options changes slightly. You must replace all ',' between options 
 * with ' ' and all ':' with '=' and you must use 
 * '1' in place of 'Y' and '0' in place of 'N'.
 * 
 * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0
81
 *           max_ids=127 rescan=0 hdr_channel=0 shared_access=0
Linus Torvalds's avatar
Linus Torvalds committed
82 83 84 85 86 87
 *           probe_eisa_isa=0 force_dma32=0"
 * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1".
 */

/* The meaning of the Scsi_Pointer members in this driver is as follows:
 * ptr:                     Chaining
88 89
 * this_residual:           unused
 * buffer:                  unused
90
 * dma_handle:              unused
91
 * buffers_residual:        unused
92
 * Status:                  unused
93 94 95 96
 * Message:                 unused
 * have_data_in:            unused
 * sent_command:            unused
 * phase:                   unused
Linus Torvalds's avatar
Linus Torvalds committed
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
 */


/* interrupt coalescing */
/* #define INT_COAL */

/* statistics */
#define GDTH_STATISTICS

#include <linux/module.h>

#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/in.h>
#include <linux/proc_fs.h>
#include <linux/time.h>
#include <linux/timer.h>
121
#include <linux/dma-mapping.h>
122
#include <linux/list.h>
123
#include <linux/mutex.h>
124
#include <linux/slab.h>
125

Linus Torvalds's avatar
Linus Torvalds committed
126 127 128 129 130 131 132 133 134 135
#ifdef GDTH_RTC
#include <linux/mc146818rtc.h>
#endif
#include <linux/reboot.h>

#include <asm/dma.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/spinlock.h>
#include <linux/blkdev.h>
136
#include <linux/scatterlist.h>
Linus Torvalds's avatar
Linus Torvalds committed
137 138 139

#include "scsi.h"
#include <scsi/scsi_host.h>
140
#include "gdth.h"
Linus Torvalds's avatar
Linus Torvalds committed
141

142
static DEFINE_MUTEX(gdth_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
143
static void gdth_delay(int milliseconds);
144
static void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs);
145
static irqreturn_t gdth_interrupt(int irq, void *dev_id);
146
static irqreturn_t __gdth_interrupt(gdth_ha_str *ha,
147
                                    int gdth_from_wait, int* pIndex);
148
static int gdth_sync_event(gdth_ha_str *ha, int service, u8 index,
149 150
                                                               Scsi_Cmnd *scp);
static int gdth_async_event(gdth_ha_str *ha);
Linus Torvalds's avatar
Linus Torvalds committed
151 152
static void gdth_log_event(gdth_evt_data *dvr, char *buffer);

153
static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 priority);
154
static void gdth_next(gdth_ha_str *ha);
155
static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 b);
156
static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
157 158
static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source,
                                      u16 idx, gdth_evt_data *evt);
Linus Torvalds's avatar
Linus Torvalds committed
159
static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr);
160
static void gdth_readapp_event(gdth_ha_str *ha, u8 application, 
Linus Torvalds's avatar
Linus Torvalds committed
161 162 163
                               gdth_evt_str *estr);
static void gdth_clear_events(void);

164
static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
165
                                    char *buffer, u16 count);
166
static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
167
static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u16 hdrive);
Linus Torvalds's avatar
Linus Torvalds committed
168

169 170 171 172
static void gdth_enable_int(gdth_ha_str *ha);
static int gdth_test_busy(gdth_ha_str *ha);
static int gdth_get_cmd_index(gdth_ha_str *ha);
static void gdth_release_event(gdth_ha_str *ha);
173 174 175
static int gdth_wait(gdth_ha_str *ha, int index,u32 time);
static int gdth_internal_cmd(gdth_ha_str *ha, u8 service, u16 opcode,
                                             u32 p1, u64 p2,u64 p3);
176
static int gdth_search_drives(gdth_ha_str *ha);
177
static int gdth_analyse_hdrive(gdth_ha_str *ha, u16 hdrive);
Linus Torvalds's avatar
Linus Torvalds committed
178

179
static const char *gdth_ctr_name(gdth_ha_str *ha);
Linus Torvalds's avatar
Linus Torvalds committed
180 181 182

static int gdth_open(struct inode *inode, struct file *filep);
static int gdth_close(struct inode *inode, struct file *filep);
183 184
static long gdth_unlocked_ioctl(struct file *filep, unsigned int cmd,
			        unsigned long arg);
Linus Torvalds's avatar
Linus Torvalds committed
185

186
static void gdth_flush(gdth_ha_str *ha);
Jeff Garzik's avatar
Jeff Garzik committed
187
static int gdth_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
188 189
static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
				struct gdth_cmndinfo *cmndinfo);
190
static void gdth_scsi_done(struct scsi_cmnd *scp);
Linus Torvalds's avatar
Linus Torvalds committed
191 192

#ifdef DEBUG_GDTH
193
static u8   DebugState = DEBUG_GDTH;
Linus Torvalds's avatar
Linus Torvalds committed
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273

#ifdef __SERIAL__
#define MAX_SERBUF 160
static void ser_init(void);
static void ser_puts(char *str);
static void ser_putc(char c);
static int  ser_printk(const char *fmt, ...);
static char strbuf[MAX_SERBUF+1];
#ifdef __COM2__
#define COM_BASE 0x2f8
#else
#define COM_BASE 0x3f8
#endif
static void ser_init()
{
    unsigned port=COM_BASE;

    outb(0x80,port+3);
    outb(0,port+1);
    /* 19200 Baud, if 9600: outb(12,port) */
    outb(6, port);
    outb(3,port+3);
    outb(0,port+1);
    /*
    ser_putc('I');
    ser_putc(' ');
    */
}

static void ser_puts(char *str)
{
    char *ptr;

    ser_init();
    for (ptr=str;*ptr;++ptr)
        ser_putc(*ptr);
}

static void ser_putc(char c)
{
    unsigned port=COM_BASE;

    while ((inb(port+5) & 0x20)==0);
    outb(c,port);
    if (c==0x0a)
    {
        while ((inb(port+5) & 0x20)==0);
        outb(0x0d,port);
    }
}

static int ser_printk(const char *fmt, ...)
{
    va_list args;
    int i;

    va_start(args,fmt);
    i = vsprintf(strbuf,fmt,args);
    ser_puts(strbuf);
    va_end(args);
    return i;
}

#define TRACE(a)    {if (DebugState==1) {ser_printk a;}}
#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {ser_printk a;}}
#define TRACE3(a)   {if (DebugState!=0) {ser_printk a;}}

#else /* !__SERIAL__ */
#define TRACE(a)    {if (DebugState==1) {printk a;}}
#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {printk a;}}
#define TRACE3(a)   {if (DebugState!=0) {printk a;}}
#endif

#else /* !DEBUG */
#define TRACE(a)
#define TRACE2(a)
#define TRACE3(a)
#endif

#ifdef GDTH_STATISTICS
274
static u32 max_rq=0, max_index=0, max_sg=0;
Linus Torvalds's avatar
Linus Torvalds committed
275
#ifdef INT_COAL
276
static u32 max_int_coal=0;
Linus Torvalds's avatar
Linus Torvalds committed
277
#endif
278
static u32 act_ints=0, act_ios=0, act_stats=0, act_rq=0;
Linus Torvalds's avatar
Linus Torvalds committed
279 280 281
static struct timer_list gdth_timer;
#endif

282
#define PTR2USHORT(a)   (u16)(unsigned long)(a)
283 284
#define GDTOFFSOF(a,b)  (size_t)&(((a*)0)->b)
#define INDEX_OK(i,t)   ((i)<ARRAY_SIZE(t))
Linus Torvalds's avatar
Linus Torvalds committed
285 286 287

#define BUS_L2P(a,b)    ((b)>(a)->virt_bus ? (b-1):(b))

288
#ifdef CONFIG_ISA
289
static u8   gdth_drq_tab[4] = {5,6,7,7};            /* DRQ table */
290
#endif
291
#if defined(CONFIG_EISA) || defined(CONFIG_ISA)
292
static u8   gdth_irq_tab[6] = {0,10,11,12,14,0};    /* IRQ table */
293
#endif
294
static u8   gdth_polling;                           /* polling if TRUE */
Linus Torvalds's avatar
Linus Torvalds committed
295
static int      gdth_ctr_count  = 0;                    /* controller count */
296
static LIST_HEAD(gdth_instances);                       /* controller list */
297
static u8   gdth_write_through = FALSE;             /* write through */
Linus Torvalds's avatar
Linus Torvalds committed
298 299 300 301 302 303 304 305 306
static gdth_evt_str ebuffer[MAX_EVENTS];                /* event buffer */
static int elastidx;
static int eoldidx;
static int major;

#define DIN     1                               /* IN data direction */
#define DOU     2                               /* OUT data direction */
#define DNO     DIN                             /* no data transfer */
#define DUN     DIN                             /* unknown data direction */
307
static u8 gdth_direction_tab[0x100] = {
Linus Torvalds's avatar
Linus Torvalds committed
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
    DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN,
    DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN,
    DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DOU,DNO,DUN,DIN,DOU,DOU,
    DOU,DOU,DOU,DNO,DIN,DNO,DNO,DIN,DOU,DOU,DOU,DOU,DIN,DOU,DIN,DOU,
    DOU,DOU,DIN,DIN,DIN,DNO,DUN,DNO,DNO,DNO,DUN,DNO,DOU,DIN,DUN,DUN,
    DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN,
    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,
    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN,
    DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DOU,DUN,DNO,DUN,DOU,DOU,
    DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
    DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,
    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN
};

/* LILO and modprobe/insmod parameters */
/* IRQ list for GDT3000/3020 EISA controllers */
static int irq[MAXHA] __initdata = 
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
/* disable driver flag */
static int disable __initdata = 0;
/* reserve flag */
static int reserve_mode = 1;                  
/* reserve list */
static int reserve_list[MAX_RES_ARGS] = 
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
/* scan order for PCI controllers */
static int reverse_scan = 0;
/* virtual channel for the host drives */
static int hdr_channel = 0;
/* max. IDs per channel */
static int max_ids = MAXID;
/* rescan all IDs */
static int rescan = 0;
/* shared access */
static int shared_access = 1;
/* enable support for EISA and ISA controllers */
static int probe_eisa_isa = 0;
/* 64 bit DMA mode, support for drives > 2 TB, if force_dma32 = 0 */
static int force_dma32 = 0;

/* parameters for modprobe/insmod */
module_param_array(irq, int, NULL, 0);
module_param(disable, int, 0);
module_param(reserve_mode, int, 0);
module_param_array(reserve_list, int, NULL, 0);
module_param(reverse_scan, int, 0);
module_param(hdr_channel, int, 0);
module_param(max_ids, int, 0);
module_param(rescan, int, 0);
module_param(shared_access, int, 0);
module_param(probe_eisa_isa, int, 0);
module_param(force_dma32, int, 0);
MODULE_AUTHOR("Achim Leubner");
MODULE_LICENSE("GPL");

/* ioctl interface */
371
static const struct file_operations gdth_fops = {
372
    .unlocked_ioctl   = gdth_unlocked_ioctl,
Linus Torvalds's avatar
Linus Torvalds committed
373 374
    .open    = gdth_open,
    .release = gdth_close,
375
    .llseek = noop_llseek,
Linus Torvalds's avatar
Linus Torvalds committed
376 377 378 379 380
};

#include "gdth_proc.h"
#include "gdth_proc.c"

381 382 383 384 385 386 387 388 389 390 391
static gdth_ha_str *gdth_find_ha(int hanum)
{
	gdth_ha_str *ha;

	list_for_each_entry(ha, &gdth_instances, list)
		if (hanum == ha->hanum)
			return ha;

	return NULL;
}

392 393 394
static struct gdth_cmndinfo *gdth_get_cmndinfo(gdth_ha_str *ha)
{
	struct gdth_cmndinfo *priv = NULL;
395
	unsigned long flags;
396 397 398 399 400 401 402 403
	int i;

	spin_lock_irqsave(&ha->smp_lock, flags);

	for (i=0; i<GDTH_MAXCMDS; ++i) {
		if (ha->cmndinfo[i].index == 0) {
			priv = &ha->cmndinfo[i];
			memset(priv, 0, sizeof(*priv));
404
			priv->index = i+1;
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
			break;
		}
	}

	spin_unlock_irqrestore(&ha->smp_lock, flags);

	return priv;
}

static void gdth_put_cmndinfo(struct gdth_cmndinfo *priv)
{
	BUG_ON(!priv);
	priv->index = 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
420 421 422 423 424 425 426 427 428
static void gdth_delay(int milliseconds)
{
    if (milliseconds == 0) {
        udelay(1);
    } else {
        mdelay(milliseconds);
    }
}

429 430
static void gdth_scsi_done(struct scsi_cmnd *scp)
{
431 432 433
	struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
	int internal_command = cmndinfo->internal_command;

434
	TRACE2(("gdth_scsi_done()\n"));
435

436 437 438 439
	gdth_put_cmndinfo(cmndinfo);
	scp->host_scribble = NULL;

	if (internal_command)
440 441 442
		complete((struct completion *)scp->request);
	else
		scp->scsi_done(scp);
443 444 445 446 447
}

int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
                   int timeout, u32 *info)
{
448
    gdth_ha_str *ha = shost_priv(sdev->host);
449
    Scsi_Cmnd *scp;
450
    struct gdth_cmndinfo cmndinfo;
451
    DECLARE_COMPLETION_ONSTACK(wait);
452 453
    int rval;

454
    scp = kzalloc(sizeof(*scp), GFP_KERNEL);
455 456
    if (!scp)
        return -ENOMEM;
457

458 459 460 461 462 463
    scp->sense_buffer = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
    if (!scp->sense_buffer) {
	kfree(scp);
	return -ENOMEM;
    }

464
    scp->device = sdev;
465 466
    memset(&cmndinfo, 0, sizeof(cmndinfo));

467 468
    /* use request field to save the ptr. to completion struct. */
    scp->request = (struct request *)&wait;
469
    scp->cmd_len = 12;
470
    scp->cmnd = cmnd;
471
    cmndinfo.priority = IOCTL_PRI;
472
    cmndinfo.internal_cmd_str = gdtcmd;
473 474 475 476 477
    cmndinfo.internal_command = 1;

    TRACE(("__gdth_execute() cmd 0x%x\n", scp->cmnd[0]));
    __gdth_queuecommand(ha, scp, &cmndinfo);

478 479
    wait_for_completion(&wait);

480
    rval = cmndinfo.status;
481
    if (info)
482
        *info = cmndinfo.info;
483
    kfree(scp->sense_buffer);
484 485 486 487 488 489 490 491 492 493 494 495 496 497
    kfree(scp);
    return rval;
}

int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd,
                 int timeout, u32 *info)
{
    struct scsi_device *sdev = scsi_get_host_dev(shost);
    int rval = __gdth_execute(sdev, gdtcmd, cmnd, timeout, info);

    scsi_free_host_dev(sdev);
    return rval;
}

498
static void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs)
Linus Torvalds's avatar
Linus Torvalds committed
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
{
    *cyls = size /HEADS/SECS;
    if (*cyls <= MAXCYLS) {
        *heads = HEADS;
        *secs = SECS;
    } else {                                        /* too high for 64*32 */
        *cyls = size /MEDHEADS/MEDSECS;
        if (*cyls <= MAXCYLS) {
            *heads = MEDHEADS;
            *secs = MEDSECS;
        } else {                                    /* too high for 127*63 */
            *cyls = size /BIGHEADS/BIGSECS;
            *heads = BIGHEADS;
            *secs = BIGSECS;
        }
    }
}

/* controller search and initialization functions */
518
#ifdef CONFIG_EISA
519
static int __init gdth_search_eisa(u16 eisa_adr)
Linus Torvalds's avatar
Linus Torvalds committed
520
{
521
    u32 id;
Linus Torvalds's avatar
Linus Torvalds committed
522 523 524 525 526 527 528 529 530 531 532 533 534
    
    TRACE(("gdth_search_eisa() adr. %x\n",eisa_adr));
    id = inl(eisa_adr+ID0REG);
    if (id == GDT3A_ID || id == GDT3B_ID) {     /* GDT3000A or GDT3000B */
        if ((inb(eisa_adr+EISAREG) & 8) == 0)   
            return 0;                           /* not EISA configured */
        return 1;
    }
    if (id == GDT3_ID)                          /* GDT3000 */
        return 1;

    return 0;                                   
}
535
#endif /* CONFIG_EISA */
Linus Torvalds's avatar
Linus Torvalds committed
536

537
#ifdef CONFIG_ISA
538
static int __init gdth_search_isa(u32 bios_adr)
Linus Torvalds's avatar
Linus Torvalds committed
539 540
{
    void __iomem *addr;
541
    u32 id;
Linus Torvalds's avatar
Linus Torvalds committed
542 543

    TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr));
544
    if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(u32))) != NULL) {
545
        id = readl(addr);
Linus Torvalds's avatar
Linus Torvalds committed
546 547 548 549 550 551
        iounmap(addr);
        if (id == GDT2_ID)                          /* GDT2000 */
            return 1;
    }
    return 0;
}
552
#endif /* CONFIG_ISA */
Linus Torvalds's avatar
Linus Torvalds committed
553

554 555
#ifdef CONFIG_PCI

556
static bool gdth_search_vortex(u16 device)
Linus Torvalds's avatar
Linus Torvalds committed
557
{
558 559 560 561 562 563 564 565 566
	if (device <= PCI_DEVICE_ID_VORTEX_GDT6555)
		return true;
	if (device >= PCI_DEVICE_ID_VORTEX_GDT6x17RP &&
	    device <= PCI_DEVICE_ID_VORTEX_GDTMAXRP)
		return true;
	if (device == PCI_DEVICE_ID_VORTEX_GDTNEWRX ||
	    device == PCI_DEVICE_ID_VORTEX_GDTNEWRX2)
		return true;
	return false;
Linus Torvalds's avatar
Linus Torvalds committed
567 568
}

569 570 571 572 573 574
static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out);
static int gdth_pci_init_one(struct pci_dev *pdev,
			     const struct pci_device_id *ent);
static void gdth_pci_remove_one(struct pci_dev *pdev);
static void gdth_remove_one(gdth_ha_str *ha);

Linus Torvalds's avatar
Linus Torvalds committed
575 576 577
/* Vortex only makes RAID controllers.
 * We do not really want to specify all 550 ids here, so wildcard match.
 */
578 579 580 581 582
static const struct pci_device_id gdthtable[] = {
	{ PCI_VDEVICE(VORTEX, PCI_ANY_ID) },
	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SRC) },
	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SRC_XSCALE) },
	{ }	/* terminate list */
Linus Torvalds's avatar
Linus Torvalds committed
583
};
584
MODULE_DEVICE_TABLE(pci, gdthtable);
Linus Torvalds's avatar
Linus Torvalds committed
585

586 587 588 589 590 591 592
static struct pci_driver gdth_pci_driver = {
	.name		= "gdth",
	.id_table	= gdthtable,
	.probe		= gdth_pci_init_one,
	.remove		= gdth_pci_remove_one,
};

593
static void gdth_pci_remove_one(struct pci_dev *pdev)
Linus Torvalds's avatar
Linus Torvalds committed
594
{
595 596 597 598 599 600 601 602 603 604
	gdth_ha_str *ha = pci_get_drvdata(pdev);

	pci_set_drvdata(pdev, NULL);

	list_del(&ha->list);
	gdth_remove_one(ha);

	pci_disable_device(pdev);
}

605 606
static int gdth_pci_init_one(struct pci_dev *pdev,
			     const struct pci_device_id *ent)
607
{
608 609 610
	u16 vendor = pdev->vendor;
	u16 device = pdev->device;
	unsigned long base0, base1, base2;
611 612 613
	int rc;
	gdth_pci_str gdth_pcistr;
	gdth_ha_str *ha = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
614
    
615 616
	TRACE(("gdth_search_dev() cnt %d vendor %x device %x\n",
	       gdth_ctr_count, vendor, device));
Linus Torvalds's avatar
Linus Torvalds committed
617

618 619 620 621 622 623 624 625 626 627 628
	memset(&gdth_pcistr, 0, sizeof(gdth_pcistr));

	if (vendor == PCI_VENDOR_ID_VORTEX && !gdth_search_vortex(device))
		return -ENODEV;

	rc = pci_enable_device(pdev);
	if (rc)
		return rc;

	if (gdth_ctr_count >= MAXHA)
		return -EBUSY;
629

Linus Torvalds's avatar
Linus Torvalds committed
630
        /* GDT PCI controller found, resources are already in pdev */
631
	gdth_pcistr.pdev = pdev;
Linus Torvalds's avatar
Linus Torvalds committed
632 633 634 635 636 637
        base0 = pci_resource_flags(pdev, 0);
        base1 = pci_resource_flags(pdev, 1);
        base2 = pci_resource_flags(pdev, 2);
        if (device <= PCI_DEVICE_ID_VORTEX_GDT6000B ||   /* GDT6000/B */
            device >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) {  /* MPR */
            if (!(base0 & IORESOURCE_MEM)) 
638 639
		return -ENODEV;
	    gdth_pcistr.dpmem = pci_resource_start(pdev, 0);
Linus Torvalds's avatar
Linus Torvalds committed
640 641 642 643
        } else {                                  /* GDT6110, GDT6120, .. */
            if (!(base0 & IORESOURCE_MEM) ||
                !(base2 & IORESOURCE_MEM) ||
                !(base1 & IORESOURCE_IO)) 
644 645 646
		return -ENODEV;
	    gdth_pcistr.dpmem = pci_resource_start(pdev, 2);
	    gdth_pcistr.io    = pci_resource_start(pdev, 1);
Linus Torvalds's avatar
Linus Torvalds committed
647 648
        }
        TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n",
649 650 651 652
		gdth_pcistr.pdev->bus->number,
		PCI_SLOT(gdth_pcistr.pdev->devfn),
		gdth_pcistr.irq,
		gdth_pcistr.dpmem));
Linus Torvalds's avatar
Linus Torvalds committed
653

654 655 656
	rc = gdth_pci_probe_one(&gdth_pcistr, &ha);
	if (rc)
		return rc;
Linus Torvalds's avatar
Linus Torvalds committed
657

658
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
659
}
660
#endif /* CONFIG_PCI */
Linus Torvalds's avatar
Linus Torvalds committed
661

662
#ifdef CONFIG_EISA
663
static int __init gdth_init_eisa(u16 eisa_adr,gdth_ha_str *ha)
Linus Torvalds's avatar
Linus Torvalds committed
664
{
665 666
    u32 retries,id;
    u8 prot_ver,eisacf,i,irq_found;
Linus Torvalds's avatar
Linus Torvalds committed
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692

    TRACE(("gdth_init_eisa() adr. %x\n",eisa_adr));
    
    /* disable board interrupts, deinitialize services */
    outb(0xff,eisa_adr+EDOORREG);
    outb(0x00,eisa_adr+EDENABREG);
    outb(0x00,eisa_adr+EINTENABREG);
    
    outb(0xff,eisa_adr+LDOORREG);
    retries = INIT_RETRIES;
    gdth_delay(20);
    while (inb(eisa_adr+EDOORREG) != 0xff) {
        if (--retries == 0) {
            printk("GDT-EISA: Initialization error (DEINIT failed)\n");
            return 0;
        }
        gdth_delay(1);
        TRACE2(("wait for DEINIT: retries=%d\n",retries));
    }
    prot_ver = inb(eisa_adr+MAILBOXREG);
    outb(0xff,eisa_adr+EDOORREG);
    if (prot_ver != PROTOCOL_VERSION) {
        printk("GDT-EISA: Illegal protocol version\n");
        return 0;
    }
    ha->bmic = eisa_adr;
693
    ha->brd_phys = (u32)eisa_adr >> 12;
Linus Torvalds's avatar
Linus Torvalds committed
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753

    outl(0,eisa_adr+MAILBOXREG);
    outl(0,eisa_adr+MAILBOXREG+4);
    outl(0,eisa_adr+MAILBOXREG+8);
    outl(0,eisa_adr+MAILBOXREG+12);

    /* detect IRQ */ 
    if ((id = inl(eisa_adr+ID0REG)) == GDT3_ID) {
        ha->oem_id = OEM_ID_ICP;
        ha->type = GDT_EISA;
        ha->stype = id;
        outl(1,eisa_adr+MAILBOXREG+8);
        outb(0xfe,eisa_adr+LDOORREG);
        retries = INIT_RETRIES;
        gdth_delay(20);
        while (inb(eisa_adr+EDOORREG) != 0xfe) {
            if (--retries == 0) {
                printk("GDT-EISA: Initialization error (get IRQ failed)\n");
                return 0;
            }
            gdth_delay(1);
        }
        ha->irq = inb(eisa_adr+MAILBOXREG);
        outb(0xff,eisa_adr+EDOORREG);
        TRACE2(("GDT3000/3020: IRQ=%d\n",ha->irq));
        /* check the result */
        if (ha->irq == 0) {
                TRACE2(("Unknown IRQ, use IRQ table from cmd line !\n"));
                for (i = 0, irq_found = FALSE; 
                     i < MAXHA && irq[i] != 0xff; ++i) {
                if (irq[i]==10 || irq[i]==11 || irq[i]==12 || irq[i]==14) {
                    irq_found = TRUE;
                    break;
                }
                }
            if (irq_found) {
                ha->irq = irq[i];
                irq[i] = 0;
                printk("GDT-EISA: Can not detect controller IRQ,\n");
                printk("Use IRQ setting from command line (IRQ = %d)\n",
                       ha->irq);
            } else {
                printk("GDT-EISA: Initialization error (unknown IRQ), Enable\n");
                printk("the controller BIOS or use command line parameters\n");
                return 0;
            }
        }
    } else {
        eisacf = inb(eisa_adr+EISAREG) & 7;
        if (eisacf > 4)                         /* level triggered */
            eisacf -= 4;
        ha->irq = gdth_irq_tab[eisacf];
        ha->oem_id = OEM_ID_ICP;
        ha->type = GDT_EISA;
        ha->stype = id;
    }

    ha->dma64_support = 0;
    return 1;
}
754
#endif /* CONFIG_EISA */
Linus Torvalds's avatar
Linus Torvalds committed
755

756
#ifdef CONFIG_ISA
757
static int __init gdth_init_isa(u32 bios_adr,gdth_ha_str *ha)
Linus Torvalds's avatar
Linus Torvalds committed
758 759 760
{
    register gdt2_dpram_str __iomem *dp2_ptr;
    int i;
761 762
    u8 irq_drq,prot_ver;
    u32 retries;
Linus Torvalds's avatar
Linus Torvalds committed
763 764 765 766 767 768 769 770 771

    TRACE(("gdth_init_isa() bios adr. %x\n",bios_adr));

    ha->brd = ioremap(bios_adr, sizeof(gdt2_dpram_str));
    if (ha->brd == NULL) {
        printk("GDT-ISA: Initialization error (DPMEM remap error)\n");
        return 0;
    }
    dp2_ptr = ha->brd;
772
    writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */
Linus Torvalds's avatar
Linus Torvalds committed
773 774
    /* reset interface area */
    memset_io(&dp2_ptr->u, 0, sizeof(dp2_ptr->u));
775
    if (readl(&dp2_ptr->u) != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
776 777 778 779 780 781
        printk("GDT-ISA: Initialization error (DPMEM write error)\n");
        iounmap(ha->brd);
        return 0;
    }

    /* disable board interrupts, read DRQ and IRQ */
782 783 784 785
    writeb(0xff, &dp2_ptr->io.irqdel);
    writeb(0x00, &dp2_ptr->io.irqen);
    writeb(0x00, &dp2_ptr->u.ic.S_Status);
    writeb(0x00, &dp2_ptr->u.ic.Cmd_Index);
Linus Torvalds's avatar
Linus Torvalds committed
786

787
    irq_drq = readb(&dp2_ptr->io.rq);
Linus Torvalds's avatar
Linus Torvalds committed
788 789 790 791 792 793 794
    for (i=0; i<3; ++i) {
        if ((irq_drq & 1)==0)
            break;
        irq_drq >>= 1;
    }
    ha->drq = gdth_drq_tab[i];

795
    irq_drq = readb(&dp2_ptr->io.rq) >> 3;
Linus Torvalds's avatar
Linus Torvalds committed
796 797 798 799 800 801 802 803
    for (i=1; i<5; ++i) {
        if ((irq_drq & 1)==0)
            break;
        irq_drq >>= 1;
    }
    ha->irq = gdth_irq_tab[i];

    /* deinitialize services */
804 805 806
    writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]);
    writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx);
    writeb(0, &dp2_ptr->io.event);
Linus Torvalds's avatar
Linus Torvalds committed
807 808
    retries = INIT_RETRIES;
    gdth_delay(20);
809
    while (readb(&dp2_ptr->u.ic.S_Status) != 0xff) {
Linus Torvalds's avatar
Linus Torvalds committed
810 811 812 813 814 815 816
        if (--retries == 0) {
            printk("GDT-ISA: Initialization error (DEINIT failed)\n");
            iounmap(ha->brd);
            return 0;
        }
        gdth_delay(1);
    }
817
    prot_ver = (u8)readl(&dp2_ptr->u.ic.S_Info[0]);
818 819
    writeb(0, &dp2_ptr->u.ic.Status);
    writeb(0xff, &dp2_ptr->io.irqdel);
Linus Torvalds's avatar
Linus Torvalds committed
820 821 822 823 824 825 826 827 828 829 830 831 832
    if (prot_ver != PROTOCOL_VERSION) {
        printk("GDT-ISA: Illegal protocol version\n");
        iounmap(ha->brd);
        return 0;
    }

    ha->oem_id = OEM_ID_ICP;
    ha->type = GDT_ISA;
    ha->ic_all_size = sizeof(dp2_ptr->u);
    ha->stype= GDT2_ID;
    ha->brd_phys = bios_adr >> 4;

    /* special request to controller BIOS */
833 834 835 836 837 838
    writel(0x00, &dp2_ptr->u.ic.S_Info[0]);
    writel(0x00, &dp2_ptr->u.ic.S_Info[1]);
    writel(0x01, &dp2_ptr->u.ic.S_Info[2]);
    writel(0x00, &dp2_ptr->u.ic.S_Info[3]);
    writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx);
    writeb(0, &dp2_ptr->io.event);
Linus Torvalds's avatar
Linus Torvalds committed
839 840
    retries = INIT_RETRIES;
    gdth_delay(20);
841
    while (readb(&dp2_ptr->u.ic.S_Status) != 0xfe) {
Linus Torvalds's avatar
Linus Torvalds committed
842 843 844 845 846 847 848
        if (--retries == 0) {
            printk("GDT-ISA: Initialization error\n");
            iounmap(ha->brd);
            return 0;
        }
        gdth_delay(1);
    }
849 850
    writeb(0, &dp2_ptr->u.ic.Status);
    writeb(0xff, &dp2_ptr->io.irqdel);
Linus Torvalds's avatar
Linus Torvalds committed
851 852 853 854

    ha->dma64_support = 0;
    return 1;
}
855
#endif /* CONFIG_ISA */
Linus Torvalds's avatar
Linus Torvalds committed
856

857
#ifdef CONFIG_PCI
858 859
static int gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
			 gdth_ha_str *ha)
Linus Torvalds's avatar
Linus Torvalds committed
860 861 862 863
{
    register gdt6_dpram_str __iomem *dp6_ptr;
    register gdt6c_dpram_str __iomem *dp6c_ptr;
    register gdt6m_dpram_str __iomem *dp6m_ptr;
864 865 866
    u32 retries;
    u8 prot_ver;
    u16 command;
Linus Torvalds's avatar
Linus Torvalds committed
867 868 869 870
    int i, found = FALSE;

    TRACE(("gdth_init_pci()\n"));

871
    if (pdev->vendor == PCI_VENDOR_ID_INTEL)
Linus Torvalds's avatar
Linus Torvalds committed
872 873 874
        ha->oem_id = OEM_ID_INTEL;
    else
        ha->oem_id = OEM_ID_ICP;
875
    ha->brd_phys = (pdev->bus->number << 8) | (pdev->devfn & 0xf8);
876
    ha->stype = (u32)pdev->device;
877 878
    ha->irq = pdev->irq;
    ha->pdev = pdev;
Linus Torvalds's avatar
Linus Torvalds committed
879
    
880
    if (ha->pdev->device <= PCI_DEVICE_ID_VORTEX_GDT6000B) {  /* GDT6000/B */
Linus Torvalds's avatar
Linus Torvalds committed
881 882 883 884 885 886 887 888
        TRACE2(("init_pci() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
        ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6_dpram_str));
        if (ha->brd == NULL) {
            printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
            return 0;
        }
        /* check and reset interface area */
        dp6_ptr = ha->brd;
889 890
        writel(DPMEM_MAGIC, &dp6_ptr->u);
        if (readl(&dp6_ptr->u) != DPMEM_MAGIC) {
Linus Torvalds's avatar
Linus Torvalds committed
891 892 893 894 895
            printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
                   pcistr->dpmem);
            found = FALSE;
            for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
                iounmap(ha->brd);
896
                ha->brd = ioremap(i, sizeof(u16)); 
Linus Torvalds's avatar
Linus Torvalds committed
897 898 899 900
                if (ha->brd == NULL) {
                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                    return 0;
                }
901
                if (readw(ha->brd) != 0xffff) {
Linus Torvalds's avatar
Linus Torvalds committed
902 903 904 905
                    TRACE2(("init_pci_old() address 0x%x busy\n", i));
                    continue;
                }
                iounmap(ha->brd);
906
		pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, i);
Linus Torvalds's avatar
Linus Torvalds committed
907 908 909 910 911 912
                ha->brd = ioremap(i, sizeof(gdt6_dpram_str)); 
                if (ha->brd == NULL) {
                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                    return 0;
                }
                dp6_ptr = ha->brd;
913 914
                writel(DPMEM_MAGIC, &dp6_ptr->u);
                if (readl(&dp6_ptr->u) == DPMEM_MAGIC) {
Linus Torvalds's avatar
Linus Torvalds committed
915 916 917 918 919 920 921 922 923 924 925 926
                    printk("GDT-PCI: Use free address at 0x%x\n", i);
                    found = TRUE;
                    break;
                }
            }   
            if (!found) {
                printk("GDT-PCI: No free address found!\n");
                iounmap(ha->brd);
                return 0;
            }
        }
        memset_io(&dp6_ptr->u, 0, sizeof(dp6_ptr->u));
927
        if (readl(&dp6_ptr->u) != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
928 929 930 931 932 933
            printk("GDT-PCI: Initialization error (DPMEM write error)\n");
            iounmap(ha->brd);
            return 0;
        }
        
        /* disable board interrupts, deinit services */
934 935 936 937 938 939 940 941
        writeb(0xff, &dp6_ptr->io.irqdel);
        writeb(0x00, &dp6_ptr->io.irqen);
        writeb(0x00, &dp6_ptr->u.ic.S_Status);
        writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);

        writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]);
        writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx);
        writeb(0, &dp6_ptr->io.event);
Linus Torvalds's avatar
Linus Torvalds committed
942 943
        retries = INIT_RETRIES;
        gdth_delay(20);
944
        while (readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
Linus Torvalds's avatar
Linus Torvalds committed
945 946 947 948 949 950 951
            if (--retries == 0) {
                printk("GDT-PCI: Initialization error (DEINIT failed)\n");
                iounmap(ha->brd);
                return 0;
            }
            gdth_delay(1);
        }
952
        prot_ver = (u8)readl(&dp6_ptr->u.ic.S_Info[0]);
953 954
        writeb(0, &dp6_ptr->u.ic.S_Status);
        writeb(0xff, &dp6_ptr->io.irqdel);
Linus Torvalds's avatar
Linus Torvalds committed
955 956 957 958 959 960 961 962 963 964
        if (prot_ver != PROTOCOL_VERSION) {
            printk("GDT-PCI: Illegal protocol version\n");
            iounmap(ha->brd);
            return 0;
        }

        ha->type = GDT_PCI;
        ha->ic_all_size = sizeof(dp6_ptr->u);
        
        /* special command to controller BIOS */
965 966 967 968 969 970
        writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
        writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
        writel(0x00, &dp6_ptr->u.ic.S_Info[2]);
        writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
        writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
        writeb(0, &dp6_ptr->io.event);
Linus Torvalds's avatar
Linus Torvalds committed
971 972
        retries = INIT_RETRIES;
        gdth_delay(20);
973
        while (readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
Linus Torvalds's avatar
Linus Torvalds committed
974 975 976 977 978 979 980
            if (--retries == 0) {
                printk("GDT-PCI: Initialization error\n");
                iounmap(ha->brd);
                return 0;
            }
            gdth_delay(1);
        }
981 982
        writeb(0, &dp6_ptr->u.ic.S_Status);
        writeb(0xff, &dp6_ptr->io.irqdel);
Linus Torvalds's avatar
Linus Torvalds committed
983 984 985

        ha->dma64_support = 0;

986
    } else if (ha->pdev->device <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, ... */
Linus Torvalds's avatar
Linus Torvalds committed
987 988 989 990 991 992 993 994 995 996 997
        ha->plx = (gdt6c_plx_regs *)pcistr->io;
        TRACE2(("init_pci_new() dpmem %lx irq %d\n",
            pcistr->dpmem,ha->irq));
        ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6c_dpram_str));
        if (ha->brd == NULL) {
            printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
            iounmap(ha->brd);
            return 0;
        }
        /* check and reset interface area */
        dp6c_ptr = ha->brd;
998 999
        writel(DPMEM_MAGIC, &dp6c_ptr->u);
        if (readl(&dp6c_ptr->u) != DPMEM_MAGIC) {
Linus Torvalds's avatar
Linus Torvalds committed
1000 1001 1002 1003 1004
            printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
                   pcistr->dpmem);
            found = FALSE;
            for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
                iounmap(ha->brd);
1005
                ha->brd = ioremap(i, sizeof(u16)); 
Linus Torvalds's avatar
Linus Torvalds committed
1006 1007 1008 1009
                if (ha->brd == NULL) {
                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                    return 0;
                }
1010
                if (readw(ha->brd) != 0xffff) {
Linus Torvalds's avatar
Linus Torvalds committed
1011 1012 1013 1014
                    TRACE2(("init_pci_plx() address 0x%x busy\n", i));
                    continue;
                }
                iounmap(ha->brd);
1015
		pci_write_config_dword(pdev, PCI_BASE_ADDRESS_2, i);
Linus Torvalds's avatar
Linus Torvalds committed
1016 1017 1018 1019 1020 1021
                ha->brd = ioremap(i, sizeof(gdt6c_dpram_str)); 
                if (ha->brd == NULL) {
                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                    return 0;
                }
                dp6c_ptr = ha->brd;
1022 1023
                writel(DPMEM_MAGIC, &dp6c_ptr->u);
                if (readl(&dp6c_ptr->u) == DPMEM_MAGIC) {
Linus Torvalds's avatar
Linus Torvalds committed
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
                    printk("GDT-PCI: Use free address at 0x%x\n", i);
                    found = TRUE;
                    break;
                }
            }   
            if (!found) {
                printk("GDT-PCI: No free address found!\n");
                iounmap(ha->brd);
                return 0;
            }
        }
        memset_io(&dp6c_ptr->u, 0, sizeof(dp6c_ptr->u));
1036
        if (readl(&dp6c_ptr->u) != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
1037 1038 1039 1040 1041 1042 1043 1044 1045
            printk("GDT-PCI: Initialization error (DPMEM write error)\n");
            iounmap(ha->brd);
            return 0;
        }
        
        /* disable board interrupts, deinit services */
        outb(0x00,PTR2USHORT(&ha->plx->control1));
        outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
        
1046 1047
        writeb(0x00, &dp6c_ptr->u.ic.S_Status);
        writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index);
Linus Torvalds's avatar
Linus Torvalds committed
1048

1049 1050
        writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]);
        writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx);
Linus Torvalds's avatar
Linus Torvalds committed
1051 1052 1053 1054 1055

        outb(1,PTR2USHORT(&ha->plx->ldoor_reg));

        retries = INIT_RETRIES;
        gdth_delay(20);
1056
        while (readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
Linus Torvalds's avatar
Linus Torvalds committed
1057 1058 1059 1060 1061 1062 1063
            if (--retries == 0) {
                printk("GDT-PCI: Initialization error (DEINIT failed)\n");
                iounmap(ha->brd);
                return 0;
            }
            gdth_delay(1);
        }
1064
        prot_ver = (u8)readl(&dp6c_ptr->u.ic.S_Info[0]);
1065
        writeb(0, &dp6c_ptr->u.ic.Status);
Linus Torvalds's avatar
Linus Torvalds committed
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
        if (prot_ver != PROTOCOL_VERSION) {
            printk("GDT-PCI: Illegal protocol version\n");
            iounmap(ha->brd);
            return 0;
        }

        ha->type = GDT_PCINEW;
        ha->ic_all_size = sizeof(dp6c_ptr->u);

        /* special command to controller BIOS */
1076 1077 1078 1079 1080
        writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
        writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
        writel(0x00, &dp6c_ptr->u.ic.S_Info[2]);
        writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
        writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
Linus Torvalds's avatar
Linus Torvalds committed
1081 1082 1083 1084 1085
        
        outb(1,PTR2USHORT(&ha->plx->ldoor_reg));

        retries = INIT_RETRIES;
        gdth_delay(20);
1086
        while (readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
Linus Torvalds's avatar
Linus Torvalds committed
1087 1088 1089 1090 1091 1092 1093
            if (--retries == 0) {
                printk("GDT-PCI: Initialization error\n");
                iounmap(ha->brd);
                return 0;
            }
            gdth_delay(1);
        }
1094
        writeb(0, &dp6c_ptr->u.ic.S_Status);
Linus Torvalds's avatar
Linus Torvalds committed
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106

        ha->dma64_support = 0;

    } else {                                            /* MPR */
        TRACE2(("init_pci_mpr() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
        ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6m_dpram_str));
        if (ha->brd == NULL) {
            printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
            return 0;
        }

        /* manipulate config. space to enable DPMEM, start RP controller */
1107
	pci_read_config_word(pdev, PCI_COMMAND, &command);
Linus Torvalds's avatar
Linus Torvalds committed
1108
        command |= 6;
1109
	pci_write_config_word(pdev, PCI_COMMAND, command);
1110 1111
	gdth_delay(1);

Linus Torvalds's avatar
Linus Torvalds committed
1112 1113 1114 1115
        dp6m_ptr = ha->brd;

        /* Ensure that it is safe to access the non HW portions of DPMEM.
         * Aditional check needed for Xscale based RAID controllers */
1116
        while( ((int)readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 )
Linus Torvalds's avatar
Linus Torvalds committed
1117 1118 1119
            gdth_delay(1);
        
        /* check and reset interface area */
1120 1121
        writel(DPMEM_MAGIC, &dp6m_ptr->u);
        if (readl(&dp6m_ptr->u) != DPMEM_MAGIC) {
Linus Torvalds's avatar
Linus Torvalds committed
1122 1123 1124 1125 1126
            printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
                   pcistr->dpmem);
            found = FALSE;
            for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
                iounmap(ha->brd);
1127
                ha->brd = ioremap(i, sizeof(u16)); 
Linus Torvalds's avatar
Linus Torvalds committed
1128 1129 1130 1131
                if (ha->brd == NULL) {
                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                    return 0;
                }
1132
                if (readw(ha->brd) != 0xffff) {
Linus Torvalds's avatar
Linus Torvalds committed
1133 1134 1135 1136
                    TRACE2(("init_pci_mpr() address 0x%x busy\n", i));
                    continue;
                }
                iounmap(ha->brd);
1137
		pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, i);
Linus Torvalds's avatar
Linus Torvalds committed
1138 1139 1140 1141 1142 1143
                ha->brd = ioremap(i, sizeof(gdt6m_dpram_str)); 
                if (ha->brd == NULL) {
                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                    return 0;
                }
                dp6m_ptr = ha->brd;
1144 1145
                writel(DPMEM_MAGIC, &dp6m_ptr->u);
                if (readl(&dp6m_ptr->u) == DPMEM_MAGIC) {
Linus Torvalds's avatar
Linus Torvalds committed
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
                    printk("GDT-PCI: Use free address at 0x%x\n", i);
                    found = TRUE;
                    break;
                }
            }   
            if (!found) {
                printk("GDT-PCI: No free address found!\n");
                iounmap(ha->brd);
                return 0;
            }
        }
        memset_io(&dp6m_ptr->u, 0, sizeof(dp6m_ptr->u));
        
        /* disable board interrupts, deinit services */
1160
        writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) | 4,
Linus Torvalds's avatar
Linus Torvalds committed
1161
                    &dp6m_ptr->i960r.edoor_en_reg);
1162 1163 1164
        writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
        writeb(0x00, &dp6m_ptr->u.ic.S_Status);
        writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index);
Linus Torvalds's avatar
Linus Torvalds committed
1165

1166 1167 1168
        writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]);
        writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx);
        writeb(1, &dp6m_ptr->i960r.ldoor_reg);
Linus Torvalds's avatar
Linus Torvalds committed
1169 1170
        retries = INIT_RETRIES;
        gdth_delay(20);
1171
        while (readb(&dp6m_ptr->u.ic.S_Status) != 0xff) {
Linus Torvalds's avatar
Linus Torvalds committed
1172 1173 1174 1175 1176 1177 1178
            if (--retries == 0) {
                printk("GDT-PCI: Initialization error (DEINIT failed)\n");
                iounmap(ha->brd);
                return 0;
            }
            gdth_delay(1);
        }
1179
        prot_ver = (u8)readl(&dp6m_ptr->u.ic.S_Info[0]);
1180
        writeb(0, &dp6m_ptr->u.ic.S_Status);
Linus Torvalds's avatar
Linus Torvalds committed
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
        if (prot_ver != PROTOCOL_VERSION) {
            printk("GDT-PCI: Illegal protocol version\n");
            iounmap(ha->brd);
            return 0;
        }

        ha->type = GDT_PCIMPR;
        ha->ic_all_size = sizeof(dp6m_ptr->u);
        
        /* special command to controller BIOS */
1191 1192 1193 1194 1195 1196
        writel(0x00, &dp6m_ptr->u.ic.S_Info[0]);
        writel(0x00, &dp6m_ptr->u.ic.S_Info[1]);
        writel(0x00, &dp6m_ptr->u.ic.S_Info[2]);
        writel(0x00, &dp6m_ptr->u.ic.S_Info[3]);
        writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx);
        writeb(1, &dp6m_ptr->i960r.ldoor_reg);
Linus Torvalds's avatar
Linus Torvalds committed
1197 1198
        retries = INIT_RETRIES;
        gdth_delay(20);
1199
        while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) {
Linus Torvalds's avatar
Linus Torvalds committed
1200 1201 1202 1203 1204 1205 1206
            if (--retries == 0) {
                printk("GDT-PCI: Initialization error\n");
                iounmap(ha->brd);
                return 0;
            }
            gdth_delay(1);
        }
1207
        writeb(0, &dp6m_ptr->u.ic.S_Status);
Linus Torvalds's avatar
Linus Torvalds committed
1208 1209

        /* read FW version to detect 64-bit DMA support */
1210 1211
        writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx);
        writeb(1, &dp6m_ptr->i960r.ldoor_reg);
Linus Torvalds's avatar
Linus Torvalds committed
1212 1213
        retries = INIT_RETRIES;
        gdth_delay(20);
1214
        while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) {
Linus Torvalds's avatar
Linus Torvalds committed
1215 1216 1217 1218 1219 1220 1221
            if (--retries == 0) {
                printk("GDT-PCI: Initialization error (DEINIT failed)\n");
                iounmap(ha->brd);
                return 0;
            }
            gdth_delay(1);
        }
1222
        prot_ver = (u8)(readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16);
1223
        writeb(0, &dp6m_ptr->u.ic.S_Status);
Linus Torvalds's avatar
Linus Torvalds committed
1224 1225 1226 1227 1228 1229 1230 1231
        if (prot_ver < 0x2b)      /* FW < x.43: no 64-bit DMA support */
            ha->dma64_support = 0;
        else 
            ha->dma64_support = 1;
    }

    return 1;
}
1232
#endif /* CONFIG_PCI */
Linus Torvalds's avatar
Linus Torvalds committed
1233 1234 1235

/* controller protocol functions */

1236
static void gdth_enable_int(gdth_ha_str *ha)
Linus Torvalds's avatar
Linus Torvalds committed
1237
{
1238
    unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
1239 1240 1241 1242
    gdt2_dpram_str __iomem *dp2_ptr;
    gdt6_dpram_str __iomem *dp6_ptr;
    gdt6m_dpram_str __iomem *dp6m_ptr;

1243
    TRACE(("gdth_enable_int() hanum %d\n",ha->hanum));
Linus Torvalds's avatar
Linus Torvalds committed
1244 1245 1246 1247 1248 1249 1250 1251
    spin_lock_irqsave(&ha->smp_lock, flags);

    if (ha->type == GDT_EISA) {
        outb(0xff, ha->bmic + EDOORREG);
        outb(0xff, ha->bmic + EDENABREG);
        outb(0x01, ha->bmic + EINTENABREG);
    } else if (ha->type == GDT_ISA) {
        dp2_ptr = ha->brd;
1252 1253 1254
        writeb(1, &dp2_ptr->io.irqdel);
        writeb(0, &dp2_ptr->u.ic.Cmd_Index);
        writeb(1, &dp2_ptr->io.irqen);
Linus Torvalds's avatar
Linus Torvalds committed
1255 1256
    } else if (ha->type == GDT_PCI) {
        dp6_ptr = ha->brd;
1257 1258 1259
        writeb(1, &dp6_ptr->io.irqdel);
        writeb(0, &dp6_ptr->u.ic.Cmd_Index);
        writeb(1, &dp6_ptr->io.irqen);
Linus Torvalds's avatar
Linus Torvalds committed
1260 1261 1262 1263 1264
    } else if (ha->type == GDT_PCINEW) {
        outb(0xff, PTR2USHORT(&ha->plx->edoor_reg));
        outb(0x03, PTR2USHORT(&ha->plx->control1));
    } else if (ha->type == GDT_PCIMPR) {
        dp6m_ptr = ha->brd;
1265 1266
        writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
        writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4,
Linus Torvalds's avatar
Linus Torvalds committed
1267 1268 1269 1270 1271
                    &dp6m_ptr->i960r.edoor_en_reg);
    }
    spin_unlock_irqrestore(&ha->smp_lock, flags);
}

1272
/* return IStatus if interrupt was from this card else 0 */
1273
static u8 gdth_get_status(gdth_ha_str *ha)
Linus Torvalds's avatar
Linus Torvalds committed
1274
{
1275
    u8 IStatus = 0;
1276

1277
    TRACE(("gdth_get_status() irq %d ctr_count %d\n", ha->irq, gdth_ctr_count));
Linus Torvalds's avatar
Linus Torvalds committed
1278 1279

        if (ha->type == GDT_EISA)
1280
            IStatus = inb((u16)ha->bmic + EDOORREG);
Linus Torvalds's avatar
Linus Torvalds committed
1281
        else if (ha->type == GDT_ISA)
1282
            IStatus =
1283
                readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
Linus Torvalds's avatar
Linus Torvalds committed
1284
        else if (ha->type == GDT_PCI)
1285
            IStatus =
1286
                readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
Linus Torvalds's avatar
Linus Torvalds committed
1287
        else if (ha->type == GDT_PCINEW) 
1288
            IStatus = inb(PTR2USHORT(&ha->plx->edoor_reg));
Linus Torvalds's avatar
Linus Torvalds committed
1289
        else if (ha->type == GDT_PCIMPR)
1290
            IStatus =
1291
                readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg);
1292 1293

        return IStatus;
Linus Torvalds's avatar
Linus Torvalds committed
1294
}
1295

1296
static int gdth_test_busy(gdth_ha_str *ha)
Linus Torvalds's avatar
Linus Torvalds committed
1297 1298 1299
{
    register int gdtsema0 = 0;

1300 1301
    TRACE(("gdth_test_busy() hanum %d\n", ha->hanum));

Linus Torvalds's avatar
Linus Torvalds committed
1302 1303 1304
    if (ha->type == GDT_EISA)
        gdtsema0 = (int)inb(ha->bmic + SEMA0REG);
    else if (ha->type == GDT_ISA)
1305
        gdtsema0 = (int)readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
Linus Torvalds's avatar
Linus Torvalds committed
1306
    else if (ha->type == GDT_PCI)
1307
        gdtsema0 = (int)readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
Linus Torvalds's avatar
Linus Torvalds committed
1308 1309 1310 1311
    else if (ha->type == GDT_PCINEW) 
        gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg));
    else if (ha->type == GDT_PCIMPR)
        gdtsema0 = 
1312
            (int)readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
Linus Torvalds's avatar
Linus Torvalds committed
1313 1314 1315 1316 1317

    return (gdtsema0 & 1);
}


1318
static int gdth_get_cmd_index(gdth_ha_str *ha)
Linus Torvalds's avatar
Linus Torvalds committed
1319 1320 1321
{
    int i;

1322
    TRACE(("gdth_get_cmd_index() hanum %d\n", ha->hanum));
Linus Torvalds's avatar
Linus Torvalds committed
1323 1324 1325 1326 1327

    for (i=0; i<GDTH_MAXCMDS; ++i) {
        if (ha->cmd_tab[i].cmnd == UNUSED_CMND) {
            ha->cmd_tab[i].cmnd = ha->pccb->RequestBuffer;
            ha->cmd_tab[i].service = ha->pccb->Service;
1328
            ha->pccb->CommandIndex = (u32)i+2;
Linus Torvalds's avatar
Linus Torvalds committed
1329 1330 1331 1332 1333 1334 1335
            return (i+2);
        }
    }
    return 0;
}


1336
static void gdth_set_sema0(gdth_ha_str *ha)
Linus Torvalds's avatar
Linus Torvalds committed
1337
{
1338
    TRACE(("gdth_set_sema0() hanum %d\n", ha->hanum));
Linus Torvalds's avatar
Linus Torvalds committed
1339 1340 1341 1342

    if (ha->type == GDT_EISA) {
        outb(1, ha->bmic + SEMA0REG);
    } else if (ha->type == GDT_ISA) {
1343
        writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
Linus Torvalds's avatar
Linus Torvalds committed
1344
    } else if (ha->type == GDT_PCI) {
1345
        writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
Linus Torvalds's avatar
Linus Torvalds committed
1346 1347 1348
    } else if (ha->type == GDT_PCINEW) { 
        outb(1, PTR2USHORT(&ha->plx->sema0_reg));
    } else if (ha->type == GDT_PCIMPR) {
1349
        writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
Linus Torvalds's avatar
Linus Torvalds committed
1350 1351 1352 1353
    }
}


1354
static void gdth_copy_command(gdth_ha_str *ha)
Linus Torvalds's avatar
Linus Torvalds committed
1355 1356 1357 1358 1359 1360
{
    register gdth_cmd_str *cmd_ptr;
    register gdt6m_dpram_str __iomem *dp6m_ptr;
    register gdt6c_dpram_str __iomem *dp6c_ptr;
    gdt6_dpram_str __iomem *dp6_ptr;
    gdt2_dpram_str __iomem *dp2_ptr;
1361
    u16 cp_count,dp_offset,cmd_no;
Linus Torvalds's avatar
Linus Torvalds committed
1362
    
1363
    TRACE(("gdth_copy_command() hanum %d\n", ha->hanum));
Linus Torvalds's avatar
Linus Torvalds committed
1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382

    cp_count = ha->cmd_len;
    dp_offset= ha->cmd_offs_dpmem;
    cmd_no   = ha->cmd_cnt;
    cmd_ptr  = ha->pccb;

    ++ha->cmd_cnt;                                                      
    if (ha->type == GDT_EISA)
        return;                                 /* no DPMEM, no copy */

    /* set cpcount dword aligned */
    if (cp_count & 3)
        cp_count += (4 - (cp_count & 3));

    ha->cmd_offs_dpmem += cp_count;
    
    /* set offset and service, copy command to DPMEM */
    if (ha->type == GDT_ISA) {
        dp2_ptr = ha->brd;
1383
        writew(dp_offset + DPMEM_COMMAND_OFFSET,
Linus Torvalds's avatar
Linus Torvalds committed
1384
                    &dp2_ptr->u.ic.comm_queue[cmd_no].offset);
1385
        writew((u16)cmd_ptr->Service,
Linus Torvalds's avatar
Linus Torvalds committed
1386 1387 1388 1389
                    &dp2_ptr->u.ic.comm_queue[cmd_no].serv_id);
        memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
    } else if (ha->type == GDT_PCI) {
        dp6_ptr = ha->brd;
1390
        writew(dp_offset + DPMEM_COMMAND_OFFSET,
Linus Torvalds's avatar
Linus Torvalds committed
1391
                    &dp6_ptr->u.ic.comm_queue[cmd_no].offset);
1392
        writew((u16)cmd_ptr->Service,
Linus Torvalds's avatar
Linus Torvalds committed
1393 1394 1395 1396
                    &dp6_ptr->u.ic.comm_queue[cmd_no].serv_id);
        memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
    } else if (ha->type == GDT_PCINEW) {
        dp6c_ptr = ha->brd;
1397
        writew(dp_offset + DPMEM_COMMAND_OFFSET,
Linus Torvalds's avatar
Linus Torvalds committed
1398
                    &dp6c_ptr->u.ic.comm_queue[cmd_no].offset);
1399
        writew((u16)cmd_ptr->Service,
Linus Torvalds's avatar
Linus Torvalds committed
1400 1401 1402 1403
                    &dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id);
        memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
    } else if (ha->type == GDT_PCIMPR) {
        dp6m_ptr = ha->brd;
1404
        writew(dp_offset + DPMEM_COMMAND_OFFSET,
Linus Torvalds's avatar
Linus Torvalds committed
1405
                    &dp6m_ptr->u.ic.comm_queue[cmd_no].offset);
1406
        writew((u16)cmd_ptr->Service,
Linus Torvalds's avatar
Linus Torvalds committed
1407 1408 1409 1410 1411 1412
                    &dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id);
        memcpy_toio(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
    }
}


1413
static void gdth_release_event(gdth_ha_str *ha)
Linus Torvalds's avatar
Linus Torvalds committed
1414
{
1415
    TRACE(("gdth_release_event() hanum %d\n", ha->hanum));
Linus Torvalds's avatar
Linus Torvalds committed
1416 1417 1418

#ifdef GDTH_STATISTICS
    {
1419
        u32 i,j;
Linus Torvalds's avatar
Linus Torvalds committed
1420 1421 1422 1423 1424 1425
        for (i=0,j=0; j<GDTH_MAXCMDS; ++j) {
            if (ha->cmd_tab[j].cmnd != UNUSED_CMND)
                ++i;
        }
        if (max_index < i) {
            max_index = i;
1426
            TRACE3(("GDT: max_index = %d\n",(u16)i));
Linus Torvalds's avatar
Linus Torvalds committed
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438
        }
    }
#endif

    if (ha->pccb->OpCode == GDT_INIT)
        ha->pccb->Service |= 0x80;

    if (ha->type == GDT_EISA) {
        if (ha->pccb->OpCode == GDT_INIT)               /* store DMA buffer */
            outl(ha->ccb_phys, ha->bmic + MAILBOXREG);
        outb(ha->pccb->Service, ha->bmic + LDOORREG);
    } else if (ha->type == GDT_ISA) {