/************************************************************
* *
* Linux EATA SCSI PIO driver *
* *
* based on the CAM document CAM/89-004 rev. 2.0c, *
* DPT's driver kit, some internal documents and source, *
* and several other Linux scsi drivers and kernel docs. *
* *
* The driver currently: *
* -supports all EATA-PIO boards *
* -only supports DASD devices *
* *
* (c)1993-96 Michael Neuffer, Alfred Arnold *
* neuffer@goofy.zdv.uni-mainz.de *
* a.arnold@kfa-juelich.de *
* *
* Updated 2002 by Alan Cox <alan@lxorguk.ukuu.org.uk> for *
* Linux 2.5.x and the newer locking and error handling *
* *
* 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. *
* *
* For the avoidance of doubt the "preferred form" of this *
* code is one which is in an open non patent encumbered *
* format. Where cryptographic key signing forms part of *
* the process of creating an executable the information *
* including keys needed to generate an equivalently *
* functional executable are deemed to be part of the *
* source code are deemed to be part of the source code. *
* *
************************************************************
* last change: 2002/11/02 OS: Linux 2.5.45 *
************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include "eata_generic.h"
#include "eata_pio.h"
static unsigned int ISAbases[MAXISA] = {
0x1F0, 0x170, 0x330, 0x230
};
static unsigned int ISAirqs[MAXISA] = {
14, 12, 15, 11
};
static unsigned char EISAbases[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1
};
static unsigned int registered_HBAs;
static struct Scsi_Host *last_HBA;
static struct Scsi_Host *first_HBA;
static unsigned char reg_IRQ[16];
static unsigned char reg_IRQL[16];
static unsigned long int_counter;
static unsigned long queue_counter;
static struct scsi_host_template driver_template;
static int eata_pio_show_info(struct seq_file *m, struct Scsi_Host *shost)
{
seq_printf(m, "EATA (Extended Attachment) PIO driver version: "
"%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
seq_printf(m, "queued commands: %10ld\n"
"processed interrupts:%10ld\n", queue_counter, int_counter);
seq_printf(m, "\nscsi%-2d: HBA %.10s\n",
shost->host_no, SD(shost)->name);
seq_printf(m, "Firmware revision: v%s\n",
SD(shost)->revision);
seq_puts(m, "IO: PIO\n");
seq_printf(m, "Base IO : %#.4x\n", (u32) shost->base);
seq_printf(m, "Host Bus: %s\n",
(SD(shost)->bustype == 'P')?"PCI ":
(SD(shost)->bustype == 'E')?"EISA":"ISA ");
return 0;
}
static int eata_pio_release(struct Scsi_Host *sh)
{
hostdata *hd = SD(sh);
if (sh->irq && reg_IRQ[sh->irq] == 1)
free_irq(sh->irq, NULL);
else
reg_IRQ[sh->irq]--;
if (SD(sh)->channel == 0) {
if (sh->io_port && sh->n_io_port)
release_region(sh->io_port, sh->n_io_port);
}
/* At this point the PCI reference can go */
if (hd->pdev)
pci_dev_put(hd->pdev);
return 1;
}
static void IncStat(struct scsi_pointer *SCp, unsigned int Increment)
{
SCp->ptr += Increment;
if ((SCp->this_residual -= Increment) == 0) {
if ((--SCp->buffers_residual) == 0)
SCp->Status = 0;
else {
SCp->buffer++;
SCp->ptr = sg_virt(SCp->buffer);
SCp->this_residual = SCp->buffer->length;
}
}
}
static irqreturn_t eata_pio_int_handler(int irq, void *dev_id);
static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
irqreturn_t ret;
spin_lock_irqsave(dev->host_lock, flags);
ret = eata_pio_int_handler(irq, dev_id);
spin_unlock_irqrestore(dev->host_lock