# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.1215 -> 1.1230 # drivers/scsi/scsi_obsolete.h 1.1 -> 1.2 include/linux/scsi_obsolete.h (moved) # drivers/scsi/scsi.h 1.79 -> 1.81 include/linux/scsi_defs.h (moved) # drivers/scsi/hosts.h 1.63 -> 1.64 include/linux/scsi_hosts.h (moved) # drivers/scsi/Makefile 1.43 -> 1.44 # drivers/scsi/Kconfig 1.21 -> 1.22 # (new) -> 1.1 drivers/scsi/scsi_obsolete.h # (new) -> 1.1 drivers/scsi/hosts.h # (new) -> 1.5 include/linux/ata.h # (new) -> 1.13 drivers/scsi/libata.c # (new) -> 1.4 drivers/scsi/ata_piix.c # (new) -> 1.1 drivers/scsi/scsi.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/05/22 jgarzik@redhat.com 1.1216 # move drivers/scsi/{scsi,hosts,scsi_obsolete}.h to include/linux # -------------------------------------------- # 03/05/22 jgarzik@redhat.com 1.1217 # Add wrapper drivers/scsi/{scsi,scsi_obsolete,hosts}.h files, # including their respective include/linux/scsi*.h counterparts. # -------------------------------------------- # 03/05/22 jgarzik@redhat.com 1.1218 # add ata-scsi driver to build # -------------------------------------------- # 03/05/22 jgarzik@redhat.com 1.1219 # build fixes # -------------------------------------------- # 03/05/22 jgarzik@redhat.com 1.1220 # after intense debugging efforts[sic], quick fix ported to 2.5 # -------------------------------------------- # 03/05/22 jgarzik@redhat.com 1.1221 # fixes for 2.5 # -------------------------------------------- # 03/05/23 jgarzik@redhat.com 1.1222 # support read/write/read-cap 16 # -------------------------------------------- # 03/05/23 jgarzik@redhat.com 1.1223 # s/magic number/constant/ # -------------------------------------------- # 03/05/23 jgarzik@redhat.com 1.1224 # support report luns, format unit (noop), send diagnostic (noop) # -------------------------------------------- # 03/05/23 jgarzik@redhat.com 1.1225 # use SAM_STAT_xxx # -------------------------------------------- # 03/05/23 jgarzik@redhat.com 1.1226 # inquiry cleanup # -------------------------------------------- # 03/05/23 jgarzik@redhat.com 1.1227 # make reqbuf spitting easier # -------------------------------------------- # 03/05/24 jgarzik@redhat.com 1.1228 # bug fix # additional debugging output # -------------------------------------------- # 03/05/24 jgarzik@redhat.com 1.1229 # support inquiry pages 00, 80, 83 # -------------------------------------------- # 03/05/24 jgarzik@redhat.com 1.1230 # fix up legal junk in headers # -------------------------------------------- # diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig Sat May 24 14:40:31 2003 +++ b/drivers/scsi/Kconfig Sat May 24 14:40:31 2003 @@ -400,6 +400,33 @@ say M here and read . The module will be called megaraid. +config SCSI_ATA + bool "ATA support (EXPERIMENTAL)" + depends on SCSI && EXPERIMENTAL + help + This driver family supports ATA host controllers and devices + (a.k.a. IDE drives). + + If unsure, say N. + +config SCSI_ATA_PATA + bool "Parallel ATA support (EXPERIMENTAL)" + depends on SCSI_ATA && EXPERIMENTAL + help + This option enables support for parallel ATA host controllers. + + If unsure, say N. + +config SCSI_ATA_PIIX + tristate "Intel PIIX/ICH PATA/SATA support" + depends on SCSI_ATA && PCI + help + This option enables support for ICH5 Serial ATA. + If PATA support was enabled previously, this enables + support for select Intel PIIX/ICH PATA host controllers. + + If unsure, say N. + config SCSI_BUSLOGIC tristate "BusLogic SCSI support" depends on SCSI diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile Sat May 24 14:40:31 2003 +++ b/drivers/scsi/Makefile Sat May 24 14:40:31 2003 @@ -113,6 +113,7 @@ obj-$(CONFIG_SCSI_CPQFCTS) += cpqfc.o obj-$(CONFIG_SCSI_LASI700) += lasi700.o 53c700.o obj-$(CONFIG_SCSI_NSP32) += nsp32.o +obj-$(CONFIG_SCSI_ATA_PIIX) += ata_piix.o libata.o obj-$(CONFIG_ARM) += arm/ diff -Nru a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/ata_piix.c Sat May 24 14:40:31 2003 @@ -0,0 +1,312 @@ +/* + Copyright 2003 Red Hat Inc + Copyright 2003 Jeff Garzik + + + Copyright header from piix.c: + + Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer + Copyright (C) 1998-2000 Andre Hedrick + Copyright (C) 2003 Red Hat Inc + + May be copied or modified under the terms of the GNU General Public License + + + */ +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "ata_piix" +#define DRV_VERSION "0.9 " /* must be exactly four chars */ + +enum { + ICH5_PCS = 0x92, /* port control and status */ + + ich5_pata = 0, + ich5_sata = 1, + piix4_pata = 2, +}; + +static int __devinit piix_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent); +static void piix_port_probe(struct ata_host *ah); +static void piix_port_disable(struct ata_host *ah); +static void piix_set_piomode (struct ata_host *ah, struct ata_device *adev, + unsigned int pio); +static void piix_set_udmamode (struct ata_host *ah, struct ata_device *adev, + unsigned int udma); + +static unsigned int in_module_init = 1; + +static struct pci_device_id piix_pci_tbl[] __devinitdata = { + { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata }, + { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata }, + + { 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, + + { } /* terminate list */ +}; + +struct pci_driver piix_pci_driver = { + .name = DRV_NAME, + .id_table = piix_pci_tbl, + .probe = piix_init_one, + .remove = ata_pci_remove_one, +}; + +static Scsi_Host_Template piix_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .detect = ata_scsi_detect, + .release = ata_scsi_release, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = ATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, +}; + +struct ata_board ata_board_tbl[] __devinitdata = { + /* ich5_pata */ + { + .sht = &piix_sht, + .pio_mask = 0x03, /* pio3-4 */ + .udma_mask = 0x07, /* udma0-2 ; FIXME */ + }, + + /* ich5_sata */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA, + .pio_mask = 0x03, /* pio3-4 */ + .udma_mask = 0x3f, /* udma0-5 ; FIXME */ + }, + + /* piix4_pata */ + { + .sht = &piix_sht, + .pio_mask = 0x03, /* pio3-4 */ + .udma_mask = 0x07, /* udma0-2 ; FIXME */ + }, +}; + +struct ata_host_ops piix_pata_ops = { + .port_probe = ata_port_probe, + .port_disable = ata_port_disable, + .set_piomode = piix_set_piomode, + .set_udmamode = piix_set_udmamode, +}; + +struct ata_host_ops piix_sata_ops = { + .port_probe = piix_port_probe, + .port_disable = piix_port_disable, + .set_piomode = piix_set_piomode, + .set_udmamode = piix_set_udmamode, +}; + +MODULE_AUTHOR("Andre Hedrick, Alan Cox, Andrzej Krzysztofowicz, Jeff Garzik"); +MODULE_DESCRIPTION("SCSI low-level driver for Intel PIIX/ICH ATA controllers"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, piix_pci_tbl); + +static void piix_port_probe(struct ata_host *ah) +{ + u16 pcs; + struct pci_dev *pdev = ah->host_set->pdev; + + pci_read_config_word(pdev, ICH5_PCS, &pcs); + + /* if port not enabled, exit */ + if ((pcs & (1 << ah->port_no)) == 0) { + ata_port_disable(ah); + DPRINTK("port %d disabled, ignoring\n", ah->port_no); + return; + } + + /* if port enabled but no device, disable port and exit */ + if ((pcs & (1 << (ah->port_no + 4))) == 0) { + pcs &= ~(1 << ah->port_no); + pci_write_config_word(pdev, ICH5_PCS, pcs); + + ata_port_disable(ah); + DPRINTK("port %d has no dev, disabling\n", ah->port_no); + return; + } + + ata_port_probe(ah); +} + +static void piix_port_disable(struct ata_host *ah) +{ + struct pci_dev *pdev = ah->host_set->pdev; + u16 pcs; + + ata_port_disable(ah); + + pci_read_config_word(pdev, ICH5_PCS, &pcs); + + if (pcs & (1 << ah->port_no)) { + pcs &= ~(1 << ah->port_no); + pci_write_config_word(pdev, ICH5_PCS, pcs); + } +} + +static void piix_set_piomode (struct ata_host *ah, struct ata_device *adev, + unsigned int pio) +{ + struct pci_dev *dev = ah->host_set->pdev; + unsigned int is_slave = (adev->flags & ATA_DFLAG_MASTER) ? 0 : 1; + unsigned int master_port= ah->port_no ? 0x42 : 0x40; + unsigned int slave_port = 0x44; + u16 master_data; + u8 slave_data; + /* ISP RTC */ + u8 timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + pci_read_config_word(dev, master_port, &master_data); + if (is_slave) { + master_data |= 0x4000; + /* enable PPE, IE and TIME */ + master_data |= 0x0070; + pci_read_config_byte(dev, slave_port, &slave_data); + slave_data &= (ah->port_no ? 0x0f : 0xf0); + slave_data |= + (timings[pio][0] << 2) | + (timings[pio][1] << (ah->port_no ? 4 : 0)); + } else { + master_data &= 0xccf8; + /* enable PPE, IE and TIME */ + master_data |= 0x0007; + master_data |= + (timings[pio][0] << 12) | + (timings[pio][1] << 8); + } + pci_write_config_word(dev, master_port, master_data); + if (is_slave) + pci_write_config_byte(dev, slave_port, slave_data); +} + +static void piix_set_udmamode (struct ata_host *ah, struct ata_device *adev, + unsigned int udma) +{ + struct pci_dev *dev = ah->host_set->pdev; + u8 maslave = ah->port_no ? 0x42 : 0x40; + u8 speed = udma; + unsigned int drive_dn = (ah->port_no ? 2 : 0) + adev->devno; + int a_speed = 3 << (drive_dn * 4); + int u_flag = 1 << drive_dn; + int v_flag = 0x01 << drive_dn; + int w_flag = 0x10 << drive_dn; + int u_speed = 0; + int sitre; + u16 reg4042, reg44, reg48, reg4a, reg54; + u8 reg55; + + pci_read_config_word(dev, maslave, ®4042); + DPRINTK("reg4042 = 0x%04x\n", reg4042); + sitre = (reg4042 & 0x4000) ? 1 : 0; + pci_read_config_word(dev, 0x44, ®44); + pci_read_config_word(dev, 0x48, ®48); + pci_read_config_word(dev, 0x4a, ®4a); + pci_read_config_word(dev, 0x54, ®54); + pci_read_config_byte(dev, 0x55, ®55); + + switch(speed) { + case XFER_UDMA_4: + case XFER_UDMA_2: u_speed = 2 << (drive_dn * 4); break; + case XFER_UDMA_6: + case XFER_UDMA_5: + case XFER_UDMA_3: + case XFER_UDMA_1: u_speed = 1 << (drive_dn * 4); break; + case XFER_UDMA_0: u_speed = 0 << (drive_dn * 4); break; + default: + BUG(); + return; + } + + if (!(reg48 & u_flag)) + pci_write_config_word(dev, 0x48, reg48|u_flag); + if (speed == XFER_UDMA_5) { + pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); + } else { + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + } + if (!(reg4a & u_speed)) { + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + pci_write_config_word(dev, 0x4a, reg4a|u_speed); + } + if (speed > XFER_UDMA_2) { + if (!(reg54 & v_flag)) { + pci_write_config_word(dev, 0x54, reg54|v_flag); + } + } else { + pci_write_config_word(dev, 0x54, reg54 & ~v_flag); + } +} + +static int __devinit piix_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct ata_board *board_info = &ata_board_tbl[ent->driver_data]; + unsigned is_sata = board_info->host_flags & ATA_FLAG_SATA; + static int printed_version; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + /* no hotplugging support (FIXME) */ + if (!in_module_init) + return -ENODEV; + + return ata_pci_init_one(pdev, board_info, + is_sata ? &piix_sata_ops : &piix_pata_ops); +} + +static int __init piix_init(void) +{ + int rc; + + DPRINTK("pci_module_init\n"); + rc = pci_module_init(&piix_pci_driver); + if (rc) + return rc; + + in_module_init = 0; + + DPRINTK("scsi_register_host\n"); + rc = scsi_register_host(&piix_sht); + if (rc) { + rc = -ENODEV; + goto err_out; + } + + DPRINTK("done\n"); + return 0; + +err_out: + pci_unregister_driver(&piix_pci_driver); + return rc; +} + +static void __exit piix_exit(void) +{ + scsi_unregister_host(&piix_sht); + pci_unregister_driver(&piix_pci_driver); +} + +module_init(piix_init); +module_exit(piix_exit); + diff -Nru a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h --- a/drivers/scsi/hosts.h Sat May 24 14:40:31 2003 +++ b/drivers/scsi/hosts.h Sat May 24 14:40:31 2003 @@ -1,594 +1,6 @@ -/* - * hosts.h Copyright (C) 1992 Drew Eckhardt - * Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale - * - * mid to low-level SCSI driver interface header - * Initial versions: Drew Eckhardt - * Subsequent revisions: Eric Youngdale - * - * - * - * Modified by Eric Youngdale eric@andante.org to - * add scatter-gather, multiple outstanding request, and other - * enhancements. - * - * Further modified by Eric Youngdale to support multiple host adapters - * of the same type. - * - * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli - * - * Restructured scsi_host lists and associated functions. - * September 04, 2002 Mike Anderson (andmike@us.ibm.com) - */ +#ifndef __DRIVERS_SCSI_HOSTS_H +#define __DRIVERS_SCSI_HOSTS_H -#ifndef _HOSTS_H -#define _HOSTS_H +#include -#include -#include -#include - -struct scsi_host_cmd_pool; - - -/* It is senseless to set SG_ALL any higher than this - the performance - * does not get any better, and it wastes memory - */ -#define SG_NONE 0 -#define SG_ALL 0xff - -#define DISABLE_CLUSTERING 0 -#define ENABLE_CLUSTERING 1 - -/* The various choices mean: - * NONE: Self evident. Host adapter is not capable of scatter-gather. - * ALL: Means that the host adapter module can do scatter-gather, - * and that there is no limit to the size of the table to which - * we scatter/gather data. - * Anything else: Indicates the maximum number of chains that can be - * used in one scatter-gather request. - */ - -/* - * The Scsi_Host_Template type has all that is needed to interface with a SCSI - * host in a device independent matter. There is one entry for each different - * type of host adapter that is supported on the system. - */ - -typedef struct SHT -{ - /* Used with loadable modules so that we know when it is safe to unload */ - struct module * module; - - /* The pointer to the /proc/scsi directory entry */ - struct proc_dir_entry *proc_dir; - - /* proc-fs info function. - * Can be used to export driver statistics and other infos to the world - * outside the kernel ie. userspace and it also provides an interface - * to feed the driver with information. Check eata_dma_proc.c for reference - */ - int (*proc_info)(char *, char **, off_t, int, int, int); - - /* - * The name pointer is a pointer to the name of the SCSI - * device detected. - */ - const char *name; - - /* - * The detect function shall return non zero on detection, - * indicating the number of host adapters of this particular - * type were found. It should also - * initialize all data necessary for this particular - * SCSI driver. It is passed the host number, so this host - * knows where the first entry is in the scsi_hosts[] array. - * - * Note that the detect routine MUST not call any of the mid level - * functions to queue commands because things are not guaranteed - * to be set up yet. The detect routine can send commands to - * the host adapter as long as the program control will not be - * passed to scsi.c in the processing of the command. Note - * especially that scsi_malloc/scsi_free must not be called. - */ - int (* detect)(struct SHT *); - - /* Used with loadable modules to unload the host structures. Note: - * there is a default action built into the modules code which may - * be sufficient for most host adapters. Thus you may not have to supply - * this at all. - */ - int (*release)(struct Scsi_Host *); - - /* - * The info function will return whatever useful - * information the developer sees fit. If not provided, then - * the name field will be used instead. - */ - const char *(* info)(struct Scsi_Host *); - - /* - * ioctl interface - */ - int (*ioctl)(Scsi_Device *dev, int cmd, void *arg); - - /* - * The command function takes a target, a command (this is a SCSI - * command formatted as per the SCSI spec, nothing strange), a - * data buffer pointer, and data buffer length pointer. The return - * is a status int, bit fielded as follows : - * Byte What - * 0 SCSI status code - * 1 SCSI 1 byte message - * 2 host error return. - * 3 mid level error return - */ - int (* command)(Scsi_Cmnd *); - - /* - * The QueueCommand function works in a similar manner - * to the command function. It takes an additional parameter, - * void (* done)(int host, int code) which is passed the host - * # and exit result when the command is complete. - * Host number is the POSITION IN THE hosts array of THIS - * host adapter. - * - * if queuecommand returns 0, then the HBA has accepted the - * command. The done() function must be called on the command - * when the driver has finished with it. (you may call done on the - * command before queuecommand returns, but in this case you - * *must* return 0 from queuecommand). - * - * queuecommand may also reject the command, in which case it may - * not touch the command and must not call done() for it. - * - * There are two possible rejection returns: - * - * SCSI_MLQUEUE_DEVICE_BUSY: Block this device temporarily, but - * allow commands to other devices serviced by this host. - * - * SCSI_MLQUEUE_HOST_BUSY: Block all devices served by this - * host temporarily. - * - * for compatibility, any other non-zero return is treated the - * same as SCSI_MLQUEUE_HOST_BUSY. - * - * NOTE: "temporarily" means either until the next command for - * this device/host completes, or a period of time determined by - * I/O pressure in the system if there are no other outstanding - * commands. - * */ - int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); - - /* - * This is an error handling strategy routine. You don't need to - * define one of these if you don't want to - there is a default - * routine that is present that should work in most cases. For those - * driver authors that have the inclination and ability to write their - * own strategy routine, this is where it is specified. Note - the - * strategy routine is *ALWAYS* run in the context of the kernel eh - * thread. Thus you are guaranteed to *NOT* be in an interrupt handler - * when you execute this, and you are also guaranteed to *NOT* have any - * other commands being queued while you are in the strategy routine. - * When you return from this function, operations return to normal. - * - * See scsi_error.c scsi_unjam_host for additional comments about what - * this function should and should not be attempting to do. - */ - int (*eh_strategy_handler)(struct Scsi_Host *); - int (*eh_abort_handler)(Scsi_Cmnd *); - int (*eh_device_reset_handler)(Scsi_Cmnd *); - int (*eh_bus_reset_handler)(Scsi_Cmnd *); - int (*eh_host_reset_handler)(Scsi_Cmnd *); - - /* - * Old EH handlers, no longer used. Make them warn the user of old - * drivers by using a wrong type - */ - int (*abort)(int); - int (*reset)(int,int); - - /* - * slave_alloc() - Optional - * - * Before the mid layer attempts to scan for a new device where none - * currently exists, it will call this entry in your driver. Should - * your driver need to allocate any structs or perform any other init - * items in order to send commands to a currently unused target/lun - * combo, then this is where you can perform those allocations. This - * is specifically so that drivers won't have to perform any kind of - * "is this a new device" checks in their queuecommand routine, - * thereby making the hot path a bit quicker. - * - * Return values: 0 on success, non-0 on failure - * - * Deallocation: If we didn't find any devices at this ID, you will - * get an immediate call to slave_destroy(). If we find something here - * then you will get a call to slave_configure(), then the device will be - * used for however long it is kept around, then when the device is - * removed from the system (or * possibly at reboot time), you will - * then get a call to slave_detach(). This is assuming you implement - * slave_configure and slave_destroy. However, if you allocate memory - * and hang it off the device struct, then you must implement the - * slave_destroy() routine at a minimum in order to avoid leaking memory - * each time a device is tore down. - */ - int (* slave_alloc)(Scsi_Device *); - - /* - * slave_configure() - Optional - * - * Once the device has responded to an INQUIRY and we know the device - * is online, we call into the low level driver with the Scsi_Device * - * If the low level device driver implements this function, it *must* - * perform the task of setting the queue depth on the device. All other - * tasks are optional and depend on what the driver supports and various - * implementation details. - * - * Things currently recommended to be handled at this time include: - * - * 1. Setting the device queue depth. Proper setting of this is - * described in the comments for scsi_adjust_queue_depth. - * 2. Determining if the device supports the various synchronous - * negotiation protocols. The device struct will already have - * responded to INQUIRY and the results of the standard items - * will have been shoved into the various device flag bits, eg. - * device->sdtr will be true if the device supports SDTR messages. - * 3. Allocating command structs that the device will need. - * 4. Setting the default timeout on this device (if needed). - * 5. Anything else the low level driver might want to do on a device - * specific setup basis... - * 6. Return 0 on success, non-0 on error. The device will be marked - * as offline on error so that no access will occur. If you return - * non-0, your slave_detach routine will never get called for this - * device, so don't leave any loose memory hanging around, clean - * up after yourself before returning non-0 - */ - int (* slave_configure)(Scsi_Device *); - - /* - * slave_destroy() - Optional - * - * Immediately prior to deallocating the device and after all activity - * has ceased the mid layer calls this point so that the low level driver - * may completely detach itself from the scsi device and vice versa. - * The low level driver is responsible for freeing any memory it allocated - * in the slave_alloc or slave_configure calls. - */ - void (* slave_destroy)(Scsi_Device *); - - /* - * This function determines the bios parameters for a given - * harddisk. These tend to be numbers that are made up by - * the host adapter. Parameters: - * size, device, list (heads, sectors, cylinders) - */ - int (* bios_param)(struct scsi_device *, struct block_device *, - sector_t, int []); - - /* - * This determines if we will use a non-interrupt driven - * or an interrupt driven scheme, It is set to the maximum number - * of simultaneous commands a given host adapter will accept. - */ - int can_queue; - - /* - * In many instances, especially where disconnect / reconnect are - * supported, our host also has an ID on the SCSI bus. If this is - * the case, then it must be reserved. Please set this_id to -1 if - * your setup is in single initiator mode, and the host lacks an - * ID. - */ - int this_id; - - /* - * This determines the degree to which the host adapter is capable - * of scatter-gather. - */ - short unsigned int sg_tablesize; - - /* - * if the host adapter has limitations beside segment count - */ - short unsigned int max_sectors; - - /* - * True if this host adapter can make good use of linked commands. - * This will allow more than one command to be queued to a given - * unit on a given host. Set this to the maximum number of command - * blocks to be provided for each device. Set this to 1 for one - * command block per lun, 2 for two, etc. Do not set this to 0. - * You should make sure that the host adapter will do the right thing - * before you try setting this above 1. - */ - short cmd_per_lun; - - /* - * present contains counter indicating how many boards of this - * type were found when we did the scan. - */ - unsigned char present; - - /* - * true if this host adapter uses unchecked DMA onto an ISA bus. - */ - unsigned unchecked_isa_dma:1; - - /* - * true if this host adapter can make good use of clustering. - * I originally thought that if the tablesize was large that it - * was a waste of CPU cycles to prepare a cluster list, but - * it works out that the Buslogic is faster if you use a smaller - * number of segments (i.e. use clustering). I guess it is - * inefficient. - */ - unsigned use_clustering:1; - - /* - * True for emulated SCSI host adapters (e.g. ATAPI) - */ - unsigned emulated:1; - - unsigned highmem_io:1; - - /* - * True if the driver wishes to use the generic block layer - * tag queueing functions - */ - unsigned use_blk_tcq:1; - - /* - * Name of proc directory - */ - char *proc_name; - - /* - * countdown for host blocking with no commands outstanding - */ - unsigned int max_host_blocked; - - /* - * Default value for the blocking. If the queue is empty, host_blocked - * counts down in the request_fn until it restarts host operations as - * zero is reached. - * - * FIXME: This should probably be a value in the template */ - #define SCSI_DEFAULT_HOST_BLOCKED 7 - -} Scsi_Host_Template; - -/* - * The scsi_hosts array is the array containing the data for all - * possible scsi hosts. This is similar to the - * Scsi_Host_Template, except that we have one entry for each - * actual physical host adapter on the system, stored as a linked - * list. Note that if there are 2 aha1542 boards, then there will - * be two Scsi_Host entries, but only 1 Scsi_Host_Template entry. - */ - -struct Scsi_Host -{ -/* private: */ - /* - * This information is private to the scsi mid-layer. Wrapping it in a - * struct private is a way of marking it in a sort of C++ type of way. - */ - struct list_head sh_list; - struct list_head my_devices; - - struct scsi_host_cmd_pool *cmd_pool; - spinlock_t free_list_lock; - struct list_head free_list; /* backup store of cmd structs */ - struct list_head starved_list; - - spinlock_t default_lock; - spinlock_t *host_lock; - - struct list_head eh_cmd_q; - struct task_struct * ehandler; /* Error recovery thread. */ - struct semaphore * eh_wait; /* The error recovery thread waits on - this. */ - struct completion * eh_notify; /* wait for eh to begin or end */ - struct semaphore * eh_action; /* Wait for specific actions on the - host. */ - unsigned int eh_active:1; /* Indicates the eh thread is awake and active if - this is true. */ - unsigned int eh_kill:1; /* set when killing the eh thread */ - wait_queue_head_t host_wait; - Scsi_Host_Template * hostt; - volatile unsigned short host_busy; /* commands actually active on low-level */ - volatile unsigned short host_failed; /* commands that failed. */ - -/* public: */ - unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ - int resetting; /* if set, it means that last_reset is a valid value */ - unsigned long last_reset; - - /* - * These three parameters can be used to allow for wide scsi, - * and for host adapters that support multiple busses - * The first two should be set to 1 more than the actual max id - * or lun (i.e. 8 for normal systems). - */ - unsigned int max_id; - unsigned int max_lun; - unsigned int max_channel; - - /* These parameters should be set by the detect routine */ - unsigned long base; - unsigned long io_port; - unsigned char n_io_port; - unsigned char dma_channel; - unsigned int irq; - - /* - * This is a unique identifier that must be assigned so that we - * have some way of identifying each detected host adapter properly - * and uniquely. For hosts that do not support more than one card - * in the system at one time, this does not need to be set. It is - * initialized to 0 in scsi_register. - */ - unsigned int unique_id; - - /* - * The rest can be copied from the template, or specifically - * initialized, as required. - */ - - /* - * The maximum length of SCSI commands that this host can accept. - * Probably 12 for most host adapters, but could be 16 for others. - * For drivers that don't set this field, a value of 12 is - * assumed. I am leaving this as a number rather than a bit - * because you never know what subsequent SCSI standards might do - * (i.e. could there be a 20 byte or a 24-byte command a few years - * down the road?). - */ - unsigned char max_cmd_len; - - int this_id; - int can_queue; - short cmd_per_lun; - short unsigned int sg_tablesize; - short unsigned int max_sectors; - - unsigned in_recovery:1; - unsigned unchecked_isa_dma:1; - unsigned use_clustering:1; - unsigned highmem_io:1; - unsigned use_blk_tcq:1; - - /* - * Host has requested that no further requests come through for the - * time being. - */ - unsigned host_self_blocked:1; - - /* - * Host uses correct SCSI ordering not PC ordering. The bit is - * set for the minority of drivers whose authors actually read the spec ;) - */ - unsigned reverse_ordering:1; - - /* - * Host has rejected a command because it was busy. - */ - unsigned int host_blocked; - - /* - * Value host_blocked counts down from - */ - unsigned int max_host_blocked; - - /* - * Support for sysfs - */ - struct device host_gendev; - struct class_device class_dev; - - /* - * We should ensure that this is aligned, both for better performance - * and also because some compilers (m68k) don't automatically force - * alignment to a long boundary. - */ - unsigned long hostdata[0] /* Used for storage of host specific stuff */ - __attribute__ ((aligned (sizeof(unsigned long)))); -}; - -#define dev_to_shost(d) \ - container_of(d, struct Scsi_Host, host_gendev) -#define class_to_shost(d) \ - container_of(d, struct Scsi_Host, class_dev) - -/* - * These two functions are used to allocate and free a pseudo device - * which will connect to the host adapter itself rather than any - * physical device. You must deallocate when you are done with the - * thing. This physical pseudo-device isn't real and won't be available - * from any high-level drivers. - */ -extern void scsi_free_host_dev(Scsi_Device *); -extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host *); - -extern void scsi_unblock_requests(struct Scsi_Host *); -extern void scsi_block_requests(struct Scsi_Host *); -extern void scsi_report_bus_reset(struct Scsi_Host *, int); -extern void scsi_report_device_reset(struct Scsi_Host *, int, int); - -static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock) -{ - shost->host_lock = lock; -} - -static inline void scsi_set_device(struct Scsi_Host *shost, - struct device *dev) -{ - shost->host_gendev.parent = dev; -} - -static inline struct device *scsi_get_device(struct Scsi_Host *shost) -{ - return shost->host_gendev.parent; -} - -struct Scsi_Device_Template -{ - struct list_head list; - const char * name; - struct module * module; /* Used for loadable modules */ - unsigned char scsi_type; - int (*attach)(Scsi_Device *); /* Attach devices to arrays */ - void (*detach)(Scsi_Device *); - int (*init_command)(Scsi_Cmnd *); /* Used by new queueing code. - Selects command for blkdevs */ - void (*rescan)(Scsi_Device *); - struct device_driver scsi_driverfs_driver; -}; - -/* - * Highlevel driver registration/unregistration. - */ -extern int scsi_register_device(struct Scsi_Device_Template *); -extern int scsi_unregister_device(struct Scsi_Device_Template *); - -/* - * HBA allocation/freeing. - */ -extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int); -extern void scsi_unregister(struct Scsi_Host *); - -/* - * HBA registration/unregistration. - */ -extern int scsi_add_host(struct Scsi_Host *, struct device *); -extern int scsi_remove_host(struct Scsi_Host *); - -/* - * Legacy HBA template registration/unregistration. - */ -extern int scsi_register_host(Scsi_Host_Template *); -extern int scsi_unregister_host(Scsi_Host_Template *); - -extern struct Scsi_Host *scsi_host_hn_get(unsigned short); -extern void scsi_host_put(struct Scsi_Host *); - -/** - * scsi_find_device - find a device given the host - * @shost: SCSI host pointer - * @channel: SCSI channel (zero if only one channel) - * @pun: SCSI target number (physical unit number) - * @lun: SCSI Logical Unit Number - **/ -static inline Scsi_Device *scsi_find_device(struct Scsi_Host *shost, - int channel, int pun, int lun) { - Scsi_Device *sdev; - - list_for_each_entry (sdev, &shost->my_devices, siblings) - if (sdev->channel == channel && sdev->id == pun - && sdev->lun ==lun) - return sdev; - return NULL; -} - -#endif +#endif /* __DRIVERS_SCSI_HOSTS_H */ diff -Nru a/drivers/scsi/libata.c b/drivers/scsi/libata.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/libata.c Sat May 24 14:40:31 2003 @@ -0,0 +1,2239 @@ +/* + Copyright 2003 Red Hat, Inc. All rights reserved. + Copyright 2003 Jeff Garzik + + The contents of this file are subject to the Open + Software License version 1.1 that can be found at + http://www.opensource.org/licenses/osl-1.1.txt and is included herein + by reference. + + Alternatively, the contents of this file may be used under the terms + of the GNU General Public License version 2 (the "GPL") as distributed + in the kernel source COPYING file, in which case the provisions of + the GPL are applicable instead of the above. If you wish to allow + the use of your version of this file only under the terms of the + GPL and not to allow others to use your version of this file under + the OSL, indicate your decision by deleting the provisions above and + replace them with the notice and other provisions required by the GPL. + If you do not delete the provisions above, a recipient may use your + version of this file under either the OSL or the GPL. + + + TODO: + ATAPI. + ATAPI error handling. + Better ATA error handling. + request_region for legacy ATA ISA addresses. + scsi SYNCHRONIZE CACHE and associated mode page + other minor items, too many to list + replace THR_*_POLL states with calls to a poll function + use set-mult-mode/rw mult for faster PIO + + + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "libata" +#define DRV_VERSION "0.51" /* must be exactly four chars */ + +struct ata_scsi_args { + struct ata_host *ah; + struct ata_device *dev; + Scsi_Cmnd *cmd; + void (*done)(Scsi_Cmnd *); +}; + +static void ata_to_sense_error(struct ata_queued_cmd *qc, Scsi_Cmnd *cmd); +static void ata_scsi_badcmd(Scsi_Cmnd *cmd, + void (*done)(Scsi_Cmnd *), + u8 asc, u8 ascq); + +static unsigned int ata_unique_id = 1; +static LIST_HEAD(ata_probe_list); +static LIST_HEAD(ata_scsihost_list); +static spinlock_t ata_module_lock = SPIN_LOCK_UNLOCKED; + +MODULE_AUTHOR("Jeff Garzik"); +MODULE_DESCRIPTION("Library module for running ATA devices underneath SCSI"); +MODULE_LICENSE("GPL"); + +static const char * thr_state_name[] = { + "THR_UNKNOWN", + "THR_CHECKPORT", + "THR_EDD", + "THR_AWAIT_DEATH", + "THR_IDENTIFY", + "THR_CONFIG_PIO", + "THR_CONFIG_DMA", + "THR_PROBE_FAILED", + "THR_IDLE", + "THR_PROBE_SUCCESS", + "THR_PROBE_START", + "THR_CONFIG_FORCE_PIO", + "THR_PIO_POLL", + "THR_PIO_TMOUT", + "THR_PIO", + "THR_PIO_LAST", + "THR_PIO_LAST_POLL", + "THR_PIO_ERR", +}; + +static const char *ata_thr_state_name(unsigned int thr_state) +{ + if (thr_state < ARRAY_SIZE(thr_state_name)) + return thr_state_name[thr_state]; + return ""; +} + +static void msleep(unsigned long msecs) +{ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(msecs)); +} + +static void __ata_tf_to_host(struct ata_ioports *ioaddr, + struct ata_taskfile *tf) +{ + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + outb(tf->ctl, ioaddr->ctl_addr); + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + outb(tf->hob_feature, ioaddr->cmd_addr + ATA_REG_FEATURE); + outb(tf->hob_nsect, ioaddr->cmd_addr + ATA_REG_NSECT); + outb(tf->hob_lbal, ioaddr->cmd_addr + ATA_REG_LBAL); + outb(tf->hob_lbam, ioaddr->cmd_addr + ATA_REG_LBAM); + outb(tf->hob_lbah, ioaddr->cmd_addr + ATA_REG_LBAH); + DPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", + tf->hob_feature, + tf->hob_nsect, + tf->hob_lbal, + tf->hob_lbam, + tf->hob_lbah); + } + + if (is_addr) { + outb(tf->feature, ioaddr->cmd_addr + ATA_REG_FEATURE); + outb(tf->nsect, ioaddr->cmd_addr + ATA_REG_NSECT); + outb(tf->lbal, ioaddr->cmd_addr + ATA_REG_LBAL); + outb(tf->lbam, ioaddr->cmd_addr + ATA_REG_LBAM); + outb(tf->lbah, ioaddr->cmd_addr + ATA_REG_LBAH); + DPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", + tf->feature, + tf->nsect, + tf->lbal, + tf->lbam, + tf->lbah); + } + + if (tf->flags & ATA_TFLAG_DEVICE) { + outb(tf->device, ioaddr->cmd_addr + ATA_REG_DEVICE); + DPRINTK("device 0x%X\n", tf->device); + } + + ata_wait_idle(ioaddr); +} + +static inline void ata_exec(struct ata_host *ah, struct ata_taskfile *tf, + unsigned int bus_state) +{ + unsigned long flags; + + DPRINTK("command 0x%X\n", tf->command); + spin_lock_irqsave(&ah->host_set->lock, flags); + ah->bus_state = bus_state; + outb(tf->command, ah->ioaddr.cmd_addr + ATA_REG_CMD); + ndelay(400); + spin_unlock_irqrestore(&ah->host_set->lock, flags); +} + +static void ata_tf_to_host(struct ata_host *ah, struct ata_taskfile *tf, + unsigned int bus_state) +{ + init_MUTEX_LOCKED(&ah->sem); + + __ata_tf_to_host(&ah->ioaddr, tf); + + ata_exec(ah, tf, bus_state); +} + +static void ata_tf_from_host(struct ata_ioports *ioaddr, + struct ata_taskfile *tf) +{ + if (tf->flags & ATA_TFLAG_DATAREG) { + u16 data = inw(ioaddr->cmd_addr + ATA_REG_DATA); + tf->data = data & 0xff; + tf->hob_data = data >> 8; + } + + tf->nsect = inb(ioaddr->cmd_addr + ATA_REG_NSECT); + tf->lbal = inb(ioaddr->cmd_addr + ATA_REG_LBAL); + tf->lbam = inb(ioaddr->cmd_addr + ATA_REG_LBAM); + tf->lbah = inb(ioaddr->cmd_addr + ATA_REG_LBAH); + tf->device = inb(ioaddr->cmd_addr + ATA_REG_DEVICE); + + if (tf->flags & ATA_TFLAG_LBA48) { + outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + tf->hob_feature = inb(ioaddr->cmd_addr + ATA_REG_FEATURE); + tf->hob_nsect = inb(ioaddr->cmd_addr + ATA_REG_NSECT); + tf->hob_lbal = inb(ioaddr->cmd_addr + ATA_REG_LBAL); + tf->hob_lbam = inb(ioaddr->cmd_addr + ATA_REG_LBAM); + tf->hob_lbah = inb(ioaddr->cmd_addr + ATA_REG_LBAH); + } +} + +static const char * udma_str[] = { + "UDMA/16", + "UDMA/25", + "UDMA/33", + "UDMA/44", + "UDMA/66", + "UDMA/100", + "UDMA/133", + "UDMA7", +}; + +static const char *ata_udma_string(unsigned int udma_mask) +{ + unsigned int i; + + for (i = 7; i >= 0; i--) { + if (udma_mask & (1 << i)) + return udma_str[i]; + } + + return ""; +} + +static unsigned int ata_dev_classify(struct ata_taskfile *tf) +{ + /* Apple's open source Darwin code hints that some devices only + * put a proper signature into the LBA mid/high registers, + * So, we only check those. It's sufficient for uniqueness. + */ + + if (((tf->lbam == 0) && (tf->lbah == 0)) || + ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) { + DPRINTK("found ATA device by sig\n"); + return ATA_DEV_ATA; + } + + if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) || + ((tf->lbam == 0x69) && (tf->lbah == 0x96))) { + DPRINTK("found ATAPI device by sig\n"); + return ATA_DEV_ATAPI; + } + + DPRINTK("unknown device\n"); + return ATA_DEV_UNKNOWN; +} + +static unsigned int ata_dev_id_string(struct ata_device *dev, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned int c, ret = 0; + + while (len > 0) { + c = dev->id[ofs] >> 8; + *s = c; + s++; + + ret = c = dev->id[ofs] & 0xff; + *s = c; + s++; + + ofs++; + len -= 2; + } + + return ret; +} + +static void ata_dev_parse_strings(struct ata_device *dev) +{ + if (dev->class == ATA_DEV_ATA) + memcpy(dev->vendor, "ATA ", 8); + else if (dev->class == ATA_DEV_ATAPI) + memcpy(dev->vendor, "ATAPI ", 8); + else + memcpy(dev->vendor, "Unknown ", 8); + + ata_dev_id_string(dev, dev->product, ATA_ID_PROD_OFS, + sizeof(dev->product)); +} + +static u8 ata_dev_select(struct ata_host *ah, unsigned int device, + unsigned int unconditional, unsigned int islba) +{ + struct ata_ioports *ioaddr = &ah->ioaddr; + u8 tmp, newtmp; + + newtmp = tmp = inb(ioaddr->cmd_addr + ATA_REG_DEVICE); + + if (device == 0) { + newtmp = tmp & ~ATA_DEV1; + } else { + newtmp = tmp | ATA_DEV1; + } + newtmp |= ATA_DEVICE_OBS; + if (islba) + newtmp |= ATA_LBA; + + if (unconditional || (tmp != newtmp)) { + outb(newtmp, ioaddr->cmd_addr + ATA_REG_DEVICE); + ah->devsel = newtmp; + tmp = ata_wait_idle(&ah->ioaddr); + DPRINTK("selected dev using Device 0x%X, drv_stat 0x%X\n", + newtmp, tmp); + } else { + DPRINTK("Using cached Device reg, 0x%X\n", (u32) tmp); + } + + assert(ah->bus_state == BUS_IDLE); + + return tmp; +} + +static inline void ata_dump_id(struct ata_device *dev) +{ + DPRINTK("49==0x%04x " + "53==0x%04x " + "63==0x%04x " + "64==0x%04x " + "75==0x%04x \n", + dev->id[49], + dev->id[53], + dev->id[63], + dev->id[64], + dev->id[75]); + DPRINTK("80==0x%04x " + "81==0x%04x " + "82==0x%04x " + "83==0x%04x " + "84==0x%04x \n", + dev->id[80], + dev->id[81], + dev->id[82], + dev->id[83], + dev->id[84]); + DPRINTK("88==0x%04x " + "93==0x%04x\n", + dev->id[88], + dev->id[93]); +} + +static void ata_dev_identify(struct ata_host *ah, unsigned int device) +{ + struct ata_device *dev = &ah->device[device]; + unsigned int i; + u16 tmp; + u8 status; + struct ata_taskfile tf; + + if (!ata_dev_present(dev)) { + DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n", + ah->id, device); + return; + } + + DPRINTK("ENTER, host %u, dev %u\n", ah->id, device); + + if (dev->class == ATA_DEV_UNKNOWN) + BUG(); + if (device > ATA_MAX_DEVICES) + BUG(); + if (device > 1) + BUG(); + + ata_dev_select(ah, device, 0, 0); /* select device 0/1 */ + + ata_tf_init(ah, &tf); + + if (dev->class == ATA_DEV_ATA) + tf.command = ATA_CMD_ID_ATA; + else + tf.command = ATA_CMD_ID_ATAPI; + + DPRINTK("do identify\n"); + ata_tf_to_host(ah, &tf, BUS_IDENTIFY); + + /* wait for completion or timeout */ + DPRINTK("completion wait\n"); + down(&ah->sem); + DPRINTK("end wait\n"); + + assert(ah->bus_state == BUS_PIO); + + /* make sure we have BSY=0, DRQ=1 */ + status = ata_busy_wait(&ah->ioaddr, ATA_BUSY, 1000); + assert (((status & ATA_BUSY) == 0) && (status & ATA_DRQ)); + + /* read IDENTIFY [X] DEVICE page */ + for (i = 0; i < ATA_ID_WORDS; i++) + dev->id[i] = inw(ah->ioaddr.cmd_addr + ATA_REG_DATA); + + /* wait for host_idle */ + status = ata_wait_idle(&ah->ioaddr); + if (status & (ATA_BUSY | ATA_DRQ)) { + DPRINTK("abormal status 2, 0x%X\n", status); + goto err_out; + } + + ah->bus_state = BUS_IDLE; + + if (dev->class == ATA_DEV_ATA) { + ata_dump_id(dev); + + if (!ata_id_is_ata(dev)) /* sanity check */ + goto err_out_nosup; + + if (ata_id_has_lba48(dev)) { + dev->flags |= ATA_DFLAG_LBA48; + dev->n_sectors = ata_id_u64(dev, 100); + } else { + dev->n_sectors = ata_id_u32(dev, 60); + } + + /* we require LBA and DMA support (bits 8 & 9 of word 49) */ + if (!ata_id_has_dma(dev) || !ata_id_has_lba(dev)) + goto err_out_nosup; + + ata_dev_parse_strings(dev); + + tmp = dev->id[ATA_ID_MAJOR_VER]; + for (i = 14; i >= 1; i--) + if (tmp & (1 << i)) + break; + + /* we require at least ATA-3 */ + if (i < 3) + goto err_out_nosup; + + /* we require UDMA support */ + tmp = dev->id[ATA_ID_UDMA_MODES]; + if ((tmp & 0xff) == 0) + goto err_out_nosup; + + /* print device info to dmesg */ + printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors\n", + ah->id, device, + ata_udma_string(tmp), + dev->n_sectors); + } else { + /* we require UDMA support */ + tmp = dev->id[ATA_ID_UDMA_MODES]; + if ((tmp & 0xff) == 0) + goto err_out_nosup; + + /* print device info to dmesg */ + printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n", + ah->id, device, + ata_udma_string(tmp)); + } + + DPRINTK("EXIT\n"); + return; + +err_out_nosup: + printk(KERN_WARNING "ata%u: dev %u not supported, ignoring\n", + ah->id, device); +err_out: + dev->class = ATA_DEV_NONE; + DPRINTK("EXIT, err\n"); +} + +void ata_port_probe(struct ata_host *ah) +{ + ah->flags &= ~ATA_FLAG_PORT_DISABLED; +} + +void ata_port_disable(struct ata_host *ah) +{ + ah->device[0].class = ATA_DEV_NONE; + ah->device[1].class = ATA_DEV_NONE; + ah->flags |= ATA_FLAG_PORT_DISABLED; +} + +static unsigned int ata_bus_reset(struct ata_host *ah) +{ + unsigned int slave_possible = ah->flags & ATA_FLAG_SLAVE_POSS; + struct ata_taskfile tf; + u8 err, devsel, status; + unsigned int rc = 0; + + DPRINTK("ENTER, host %u, port %u\n", ah->id, ah->port_no); + + DPRINTK("irq toggle\n"); + ata_irq_on(ah); /* make sure interrupts are enabled */ + + /* set up execute-device-diag (bus reset) taskfile */ + DPRINTK("execute-device-diag\n"); + ata_tf_init(ah, &tf); + tf.command = ATA_CMD_EDD; + + /* do bus reset */ + ata_tf_to_host(ah, &tf, BUS_EDD); + + /* wait for completion or timeout */ + DPRINTK("EDD completion wait\n"); + down(&ah->sem); + DPRINTK("EDD end wait, bus_idle: %s\n", + (ah->bus_state == BUS_IDLE) ? "YES" : "NO"); + + /* select device 0 */ + devsel = ata_dev_select(ah, 0, 1, 0); + + /* read back results of E.D.D. */ + status = ata_chk_status(&ah->ioaddr); + err = inb(ah->ioaddr.cmd_addr + ATA_REG_ERR); + + if ((devsel == 0xff) && (err == 0xff) && (status == 0xff)) { + ah->ops->port_disable(ah); + rc = 0; + goto out; + } + + ah->device[1].class = ATA_DEV_NONE; + + /* spec says 01h or 81h indicates device 0 passed diags */ + DPRINTK("err register == 0x%X\n", err); + if ((err == 0x01) || (err == 0x81)) { + ata_tf_from_host(&ah->ioaddr, &tf); + ah->device[0].class = ata_dev_classify(&tf); + + /* check for invalid signature */ + if (ah->device[0].class == ATA_DEV_UNKNOWN) { + rc = 1; + goto out; + } + + /* exit now if device 1 is absent/failed as well */ + if ((!slave_possible) || (err == 0x81)) + goto out; + } else { + /* no device 0 exists (or device 0 failed diags) */ + ah->device[0].class = ATA_DEV_NONE; + + /* exit now if device 1 is absent as well */ + if ((!slave_possible) || (err == 0x80) || + ((err >= 0x82) && (err <= 0xff))) + goto out; + } + + /* if we reach this point, we _might_ have a device 1 */ + /* FIXME (PATA only case, so we put it off until later) */ + +out: + DPRINTK("EXIT, returning %u\n", rc); + return rc; +} + +static void ata_host_set_pio(struct ata_host *ah) +{ + struct ata_device *master, *slave; + unsigned int pio, i; + u16 mask; + + master = &ah->device[0]; + slave = &ah->device[1]; + + assert (ata_dev_present(master) || ata_dev_present(slave)); + + mask = ah->pio_mask; + if (ata_dev_present(master)) + mask &= (master->id[ATA_ID_PIO_MODES] & 0x03); + if (ata_dev_present(slave)) + mask &= (slave->id[ATA_ID_PIO_MODES] & 0x03); + + /* require pio mode 3 or 4 support for host and all devices */ + if (mask == 0) { + printk(KERN_WARNING "ata%u: no PIO3/4 support, ignoring\n", + ah->id); + goto err_out; + } + + pio = (mask & ATA_ID_PIO4) ? 4 : 3; + for (i = 0; i < ATA_MAX_DEVICES; i++) + if (ata_dev_present(&ah->device[i])) { + ah->device[i].pio_mode = (pio == 3) ? + XFER_PIO_3 : XFER_PIO_4; + ah->ops->set_piomode(ah, &ah->device[i], pio); + } + + return; + +err_out: + ah->ops->port_disable(ah); +} + +static void ata_host_set_udma(struct ata_host *ah) +{ + struct ata_device *master, *slave; + u16 mask; + unsigned int i, j; + int udma_mode = -1; + + master = &ah->device[0]; + slave = &ah->device[1]; + + assert (ata_dev_present(master) || ata_dev_present(slave)); + assert ((ah->flags & ATA_FLAG_PORT_DISABLED) == 0); + + DPRINTK("udma masks: host 0x%X, master 0x%X, slave 0x%X\n", + ah->udma_mask, + (!ata_dev_present(master)) ? 0xff : + (master->id[ATA_ID_UDMA_MODES] & 0xff), + (!ata_dev_present(slave)) ? 0xff : + (slave->id[ATA_ID_UDMA_MODES] & 0xff)); + + mask = ah->udma_mask; + if (ata_dev_present(master)) + mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); + if (ata_dev_present(slave)) + mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); + + i = XFER_UDMA_7; + while (i >= XFER_UDMA_0) { + j = i - XFER_UDMA_0; + DPRINTK("mask 0x%X i 0x%X j %u\n", mask, i, j); + if (mask & (1 << j)) { + udma_mode = i; + break; + } + + i--; + } + + /* require udma for host and all attached devices */ + if (udma_mode < 0) { + printk(KERN_WARNING "ata%u: no UltraDMA support, ignoring\n", + ah->id); + goto err_out; + } + + for (i = 0; i < ATA_MAX_DEVICES; i++) + if (ata_dev_present(&ah->device[i])) { + ah->device[i].udma_mode = udma_mode; + ah->ops->set_udmamode(ah, &ah->device[i], udma_mode); + } + + return; + +err_out: + ah->ops->port_disable(ah); +} + +static void ata_dev_set_xfermode(struct ata_host *ah, struct ata_device *dev) +{ + struct ata_taskfile tf; + + /* set up set-features taskfile */ + DPRINTK("set features - xfer mode\n"); + ata_tf_init(ah, &tf); + tf.command = ATA_CMD_SET_FEATURES; + tf.feature = SETFEATURES_XFER; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + if (dev->flags & ATA_DFLAG_PIO) + tf.nsect = dev->pio_mode; + else + tf.nsect = dev->udma_mode; + + /* do bus reset */ + ata_tf_to_host(ah, &tf, BUS_NODATA); + + /* wait for completion or timeout */ + DPRINTK("SETFEATURES completion wait\n"); + down(&ah->sem); + DPRINTK("SETFEATURES end wait\n"); + + assert(ah->bus_state == BUS_IDLE); + + ata_wait_idle(&ah->ioaddr); + + DPRINTK("EXIT\n"); +} + +static void ata_dev_set_udma(struct ata_host *ah, unsigned int device) +{ + struct ata_device *dev = &ah->device[device]; + + if (!ata_dev_present(dev) || (ah->flags & ATA_FLAG_PORT_DISABLED)) + return; + + ata_dev_set_xfermode(ah, dev); + + assert((dev->udma_mode >= XFER_UDMA_0) && + (dev->udma_mode <= XFER_UDMA_7)); + printk(KERN_INFO "ata%u: dev %u configured for %s\n", + ah->id, device, + udma_str[dev->udma_mode - XFER_UDMA_0]); +} + +static void ata_dev_set_pio(struct ata_host *ah, unsigned int device) +{ + struct ata_device *dev = &ah->device[device]; + + if (!ata_dev_present(dev) || (ah->flags & ATA_FLAG_PORT_DISABLED)) + return; + + /* force PIO mode */ + dev->flags |= ATA_DFLAG_PIO; + + ata_dev_set_xfermode(ah, dev); + + assert((dev->pio_mode >= XFER_PIO_3) && + (dev->pio_mode <= XFER_PIO_4)); + printk(KERN_INFO "ata%u: dev %u configured for PIO%c\n", + ah->id, device, + dev->pio_mode == 3 ? '3' : '4'); +} + +static void ata_sg_clean(struct ata_host *ah, struct ata_queued_cmd *qc) +{ + Scsi_Cmnd *cmd = qc->scsicmd; + struct scatterlist *sg; + unsigned int dma = (qc->flags & ATA_QCFLAG_DMA); + +#ifndef ATA_DEBUG + if (!dma) + return; +#endif + + sg = (struct scatterlist *)qc->scsicmd->request_buffer; + +#if defined(ATA_DEBUG) && defined(ATA_READ_POISON) + { + unsigned int i, j, match; + unsigned char *p; + + for (i = 0; i < qc->n_elem; i++) { + match = 1; + p = sg[i].address; + for (j = 0; j < sg[i].length; j++) + if (p[j] != 0xfb) { + match = 0; + break; + } + if (match) + DPRINTK("PRD[%u] STILL POISONED\n", i); + } + + } +#endif + + if (dma) { + int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + DPRINTK("unmapping %u sg elements\n", qc->n_elem); + + pci_unmap_sg(ah->host_set->pdev, sg, qc->n_elem, dir); + } +} + +static int ata_sg_setup(struct ata_host *ah, struct ata_queued_cmd *qc) +{ + Scsi_Cmnd *cmd = qc->scsicmd; + struct scatterlist *sg; + int n_elem; + unsigned int i; + unsigned int dma = (qc->flags & ATA_QCFLAG_DMA); +#if defined(ATA_DEBUG) && defined(ATA_READ_POISON) + unsigned int rw = (qc->flags & ATA_QCFLAG_WRITE); +#endif + + VPRINTK("ENTER, ata%u, use_sg %d\n", ah->id, cmd->use_sg); + assert(cmd->use_sg > 0); + + sg = (struct scatterlist *)cmd->request_buffer; + if (dma) { + int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + n_elem = pci_map_sg(ah->host_set->pdev, sg, cmd->use_sg, dir); + if (n_elem < 1) + return -1; + DPRINTK("%d sg elements mapped\n", n_elem); + } else { + n_elem = cmd->use_sg; + } + qc->n_elem = n_elem; + + +#ifndef ATA_DEBUG + if (!dma) + return 0; +#endif + + for (i = 0; i < n_elem; i++) { +#if defined(ATA_DEBUG) && defined(ATA_READ_POISON) + if (!rw) + memset(sg[i].address, 0xfb, sg[i].length); +#endif + ah->prd[i].addr = cpu_to_le32(sg[i].dma_address); + ah->prd[i].flags_len = cpu_to_le32(sg[i].length); + DPRINTK("PRD[%u] = (0x%X, 0x%X)\n", + i, ah->prd[i].addr, ah->prd[i].flags_len); + } + ah->prd[n_elem - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); + +#ifdef ATA_DEBUG + i = n_elem - 1; + DPRINTK("PRD[%u] = (0x%X, 0x%X)\n", + i, ah->prd[i].addr, ah->prd[i].flags_len); + + for (i = n_elem; i < ATA_MAX_PRD; i++) { + ah->prd[i].addr = 0; + ah->prd[i].flags_len = cpu_to_le32(ATA_PRD_EOT); + } +#endif + + return 0; +} + +static unsigned long ata_pio_poll(struct ata_host *ah) +{ + u8 status; + unsigned int poll_state = THR_UNKNOWN; + unsigned int reg_state = THR_UNKNOWN; + const unsigned int tmout_state = THR_PIO_TMOUT; + + switch (ah->thr_state) { + case THR_PIO: + case THR_PIO_POLL: + poll_state = THR_PIO_POLL; + reg_state = THR_PIO; + break; + case THR_PIO_LAST: + case THR_PIO_LAST_POLL: + poll_state = THR_PIO_LAST_POLL; + reg_state = THR_PIO_LAST; + break; + default: + BUG(); + break; + } + + status = ata_chk_status(&ah->ioaddr); + if (status & ATA_BUSY) { + if (time_after(jiffies, ah->thr_timeout)) { + ah->thr_state = tmout_state; + return 0; + } + ah->thr_state = poll_state; + return ATA_SHORT_PAUSE; + } + + ah->thr_state = reg_state; + return 0; +} + +static void ata_pio_start (struct ata_host *ah, struct ata_queued_cmd *qc) +{ + /* FIXME: support TCQ */ + qc->tf.ctl |= ATA_NIEN; /* disable interrupts */ + ata_tf_to_host(ah, &qc->tf, BUS_PIO); + assert(ah->thr_state == THR_IDLE); + ah->thr_state = THR_PIO; + up(&ah->thr_sem); +} + +static void ata_pio_complete (struct ata_host *ah) +{ + struct ata_queued_cmd *qc; + unsigned long flags; + u8 drv_stat; + + /* + * This is purely hueristic. This is a fast path. + * Sometimes when we enter, BSY will be cleared in + * a chk-status or two. If not, the drive is probably seeking + * or something. Snooze for a couple msecs, then + * chk-status again. If still busy, fall back to + * THR_PIO_POLL state. + */ + drv_stat = ata_busy_wait(&ah->ioaddr, ATA_BUSY | ATA_DRQ, 10); + if (drv_stat & (ATA_BUSY | ATA_DRQ)) { + msleep(2); + drv_stat = ata_busy_wait(&ah->ioaddr, ATA_BUSY | ATA_DRQ, 10); + if (drv_stat & (ATA_BUSY | ATA_DRQ)) { + ah->thr_state = THR_PIO_LAST_POLL; + ah->thr_timeout = jiffies + ATA_TMOUT_PIO; + return; + } + } + + drv_stat = ata_wait_idle(&ah->ioaddr); + if (drv_stat & (ATA_BUSY | ATA_DRQ)) { + ah->thr_state = THR_PIO_ERR; + return; + } + + /* FIXME: support TCQ */ + qc = &ah->qcmd[0]; + + ata_sg_clean(ah, qc); + + qc->flags &= ~ATA_QCFLAG_ACTIVE; + ah->thr_state = THR_IDLE; + + spin_lock_irqsave(&ah->host_set->lock, flags); + assert(ah->bus_state == BUS_PIO); + ah->bus_state = BUS_IDLE; + spin_unlock_irqrestore(&ah->host_set->lock, flags); + + ata_irq_on(ah); + + if (drv_stat & ATA_ERR) { + ata_to_sense_error(qc, qc->scsicmd); + } else { + qc->scsicmd->result = SAM_STAT_GOOD; + qc->done(qc->scsicmd); + } +} + +static void ata_pio_sector(struct ata_host *ah) +{ + struct ata_queued_cmd *qc; + struct scatterlist *sg; + Scsi_Cmnd *cmd; + void *kaddr; + unsigned char *buf; + u8 status; + + assert(ah->bus_state == BUS_PIO); + + /* + * This is purely hueristic. This is a fast path. + * Sometimes when we enter, BSY will be cleared in + * a chk-status or two. If not, the drive is probably seeking + * or something. Snooze for a couple msecs, then + * chk-status again. If still busy, fall back to + * THR_PIO_POLL state. + */ + status = ata_busy_wait(&ah->ioaddr, ATA_BUSY, 5); + if (status & ATA_BUSY) { + msleep(2); + status = ata_busy_wait(&ah->ioaddr, ATA_BUSY, 10); + if (status & ATA_BUSY) { + ah->thr_state = THR_PIO_POLL; + ah->thr_timeout = jiffies + ATA_TMOUT_PIO; + return; + } + } + + /* handle BSY=0, DRQ=0 as error */ + if ((status & ATA_DRQ) == 0) { + ah->thr_state = THR_PIO_ERR; + return; + } + + /* FIXME: support TCQ */ + qc = &ah->qcmd[0]; + cmd = qc->scsicmd; + sg = (struct scatterlist *)cmd->request_buffer; + if (qc->cursect == (qc->nsect - 1)) + ah->thr_state = THR_PIO_LAST; + + kaddr = kmap(sg[qc->cursg].page); + buf = kaddr + sg[qc->cursg].offset + (qc->cursg_ofs * ATA_SECT_SIZE); + + qc->cursect++; + qc->cursg_ofs++; + + if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg[qc->cursg].length) { + qc->cursg++; + qc->cursg_ofs = 0; + } + + DPRINTK("data %s, drv_stat 0x%X\n", + qc->flags & ATA_QCFLAG_WRITE ? "write" : "read", + status); + + /* do the actual data transfer */ + if (qc->flags & ATA_QCFLAG_WRITE) + outsl(ah->ioaddr.cmd_addr + ATA_REG_DATA, buf, ATA_SECT_DWORDS); + else + insl(ah->ioaddr.cmd_addr + ATA_REG_DATA, buf, ATA_SECT_DWORDS); + + kunmap(sg[qc->cursg].page); +} + +static void ata_dma_start (struct ata_host *ah, struct ata_queued_cmd *qc) +{ + unsigned int rw = (qc->flags & ATA_QCFLAG_WRITE); + u8 host_stat, dmactl; + + /* load taskfile registers */ + __ata_tf_to_host(&ah->ioaddr, &qc->tf); + + /* load PRD table addr. */ + outl(ah->prd_dma, ah->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); + + /* specify data direction */ + /* FIXME: redundant to later start-dma command? */ + ah->dmactl = rw ? 0 : ATA_DMA_WR; + outb(ah->dmactl, ah->ioaddr.bmdma_addr + ATA_DMA_CMD); + + /* clear interrupt, error bits */ + host_stat = inb(ah->ioaddr.bmdma_addr + ATA_DMA_STATUS); + outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, + ah->ioaddr.bmdma_addr + ATA_DMA_STATUS); + + /* issue r/w command */ + ata_exec(ah, &qc->tf, BUS_DMA); + + /* start host DMA transaction */ + dmactl = inb(ah->ioaddr.bmdma_addr + ATA_DMA_CMD); + outb(dmactl | ATA_DMA_START, + ah->ioaddr.bmdma_addr + ATA_DMA_CMD); +} + +static void ata_dma_complete(struct ata_host *ah, u8 host_stat, + unsigned int err) +{ + struct ata_queued_cmd *qc; + u8 drv_stat; + + VPRINTK("ENTER\n"); + + /* clear start/stop bit */ + outb(0, ah->ioaddr.bmdma_addr + ATA_DMA_CMD); + + /* get controller status; clear intr, err bits */ + outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, + ah->ioaddr.bmdma_addr + ATA_DMA_STATUS); + + /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ + inb(ah->ioaddr.ctl_addr); /* dummy read */ + + /* get drive status; clear intr */ + drv_stat = ata_wait_idle(&ah->ioaddr); + + DPRINTK("host %u, host_stat==0x%X, drv_stat==0x%X\n", + ah->id, (u32) host_stat, (u32) drv_stat); + + /* FIXME: support TCQ */ + qc = &ah->qcmd[0]; + if (!(qc->flags & ATA_QCFLAG_ACTIVE)) + printk(KERN_ERR "ata%u: BUG: SCSI cmd not active\n", ah->id); + else { + ata_sg_clean(ah, qc); + + if (err || (drv_stat & ATA_ERR)) { + ata_to_sense_error(qc, qc->scsicmd); + } else { + qc->scsicmd->result = SAM_STAT_GOOD; + qc->done(qc->scsicmd); + } + + qc->flags &= ~ATA_QCFLAG_ACTIVE; + } +} + +static inline unsigned int ata_host_intr (struct ata_host *ah) +{ + u8 status, host_stat; + unsigned int handled = 0; + + switch (ah->bus_state) { + case BUS_NOINTR: /* do nothing; (hopefully!) shared irq */ + case BUS_IDLE: + case BUS_PIO: + ah->stats.idle_irq++; + +#ifdef ATA_IRQ_TRAP + if ((ah->stats.idle_irq % 1000) == 0) { + handled = 1; + ata_irq_ack(ah, 0); /* debug trap */ + printk(KERN_WARNING "ata%d: irq trap\n", ah->id); + } +#endif + break; + + case BUS_DMA: + host_stat = inb(ah->ioaddr.bmdma_addr + ATA_DMA_STATUS); + DPRINTK("BUS_DMA (host_stat 0x%X)\n", host_stat); + + if (!(host_stat & ATA_DMA_INTR)) { + ah->stats.idle_irq++; + break; + } + + ata_dma_complete(ah, host_stat, 0); + ah->bus_state = BUS_IDLE; + handled = 1; + break; + + case BUS_EDD: + status = ata_irq_ack(ah, 0); + DPRINTK("BUS_EDD (drv_stat 0x%X)\n", status); + if (status & ATA_BUSY) + DPRINTK("abnormal status 0x%X host_stat 0x%X\n", + status, inb(ah->ioaddr.bmdma_addr + + ATA_DMA_STATUS)); + ah->bus_state = BUS_IDLE; + up(&ah->sem); + handled = 1; + break; + + case BUS_NODATA: /* command completion, but no data xfer */ + status = ata_irq_ack(ah, 1); + DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status); + ah->bus_state = BUS_IDLE; + up(&ah->sem); + handled = 1; + break; + + case BUS_IDENTIFY: + status = ata_irq_ack(ah, 0); + DPRINTK("BUS_IDENTIFY (drv_stat 0x%X)\n", status); + ah->bus_state = BUS_PIO; + up(&ah->sem); + handled = 1; + break; + + default: + printk(KERN_DEBUG "ata%u: unhandled bus state %u\n", + ah->id, ah->bus_state); + ah->stats.unhandled_irq++; + +#ifdef ATA_IRQ_TRAP + if ((ah->stats.unhandled_irq % 1000) == 0) { + handled = 1; + ata_irq_ack(ah, 0); /* debug trap */ + printk(KERN_WARNING "ata%d: irq trap\n", ah->id); + } +#endif + break; + } + + return handled; +} + +static irqreturn_t ata_interrupt (int irq, void *dev_instance, + struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + unsigned int i; + unsigned int handled = 0; + + spin_lock(&host_set->lock); + + for (i = 0; i < host_set->n_hosts; i++) { + struct ata_host *ah; + + ah = host_set->hosts[i]; + if (ah && (!(ah->flags & ATA_FLAG_PORT_DISABLED))) + handled += ata_host_intr(ah); + } + + spin_unlock(&host_set->lock); + + return IRQ_RETVAL(handled); +} + +static void ata_timer(struct ata_host *ah) +{ + unsigned long flags; + unsigned int bus_state; + u8 host_stat; + + DPRINTK("ENTER\n"); + + spin_lock_irqsave(&ah->host_set->lock, flags); + bus_state = ah->bus_state; + ah->bus_state = BUS_TIMER; + spin_unlock_irqrestore(&ah->host_set->lock, flags); + + switch (bus_state) { + case BUS_PIO: + case BUS_EDD: + case BUS_NODATA: + ata_wait_idle(&ah->ioaddr); + up(&ah->sem); + break; + + case BUS_DMA: + printk(KERN_WARNING "ata%u: DMA timeout\n", ah->id); + host_stat = inb(ah->ioaddr.bmdma_addr + ATA_DMA_STATUS); + ata_dma_complete(ah, host_stat, 1); + break; + + default: + DPRINTK("unhandled bus state %u\n", bus_state); + break; + } + + spin_lock_irqsave(&ah->host_set->lock, flags); + ah->bus_state = BUS_IDLE; + spin_unlock_irqrestore(&ah->host_set->lock, flags); + DPRINTK("EXIT\n"); +} + +static void ata_thread_timer(unsigned long opaque) +{ + struct ata_host *ah = (struct ata_host *) opaque; + + up(&ah->thr_sem); +} + +static unsigned long ata_thread_iter(struct ata_host *ah) +{ + long timeout = 0; + + DPRINTK("ata%u: thr_state %s\n", + ah->id, ata_thr_state_name(ah->thr_state)); + + switch (ah->thr_state) { + case THR_UNKNOWN: + ah->thr_state = THR_CHECKPORT; + break; + + case THR_PROBE_START: + down(&ah->sem); + ah->thr_state = THR_CHECKPORT; + break; + + case THR_CHECKPORT: + ah->ops->port_probe(ah); + if (ah->flags & ATA_FLAG_PORT_DISABLED) + ah->thr_state = THR_PROBE_FAILED; + else + ah->thr_state = THR_EDD; + break; + + case THR_EDD: + if ((ata_bus_reset(ah)) || (ah->flags & ATA_FLAG_PORT_DISABLED)) + ah->thr_state = THR_PROBE_FAILED; + else + ah->thr_state = THR_IDENTIFY; + break; + + case THR_IDENTIFY: + ata_dev_identify(ah, 0); + ata_dev_identify(ah, 1); + + if (!ata_dev_present(&ah->device[0]) && + !ata_dev_present(&ah->device[1])) { + ah->ops->port_disable(ah); + ah->thr_state = THR_PROBE_FAILED; + } else + ah->thr_state = THR_CONFIG_PIO; + break; + + case THR_CONFIG_PIO: + ata_host_set_pio(ah); + if (ah->flags & ATA_FLAG_PORT_DISABLED) + ah->thr_state = THR_PROBE_FAILED; + else +#ifdef ATA_FORCE_PIO + ah->thr_state = THR_CONFIG_FORCE_PIO; +#else + ah->thr_state = THR_CONFIG_DMA; +#endif + break; + + case THR_CONFIG_FORCE_PIO: + ata_dev_set_pio(ah, 0); + ata_dev_set_pio(ah, 1); + + if (ah->flags & ATA_FLAG_PORT_DISABLED) + ah->thr_state = THR_PROBE_FAILED; + else + ah->thr_state = THR_PROBE_SUCCESS; + break; + + case THR_CONFIG_DMA: + ata_host_set_udma(ah); + ata_dev_set_udma(ah, 0); + ata_dev_set_udma(ah, 1); + + if (ah->flags & ATA_FLAG_PORT_DISABLED) + ah->thr_state = THR_PROBE_FAILED; + else + ah->thr_state = THR_PROBE_SUCCESS; + break; + + case THR_PROBE_SUCCESS: + up(&ah->probe_sem); + ah->thr_state = THR_IDLE; + break; + + case THR_PROBE_FAILED: + up(&ah->probe_sem); + ah->thr_state = THR_AWAIT_DEATH; + break; + + case THR_AWAIT_DEATH: + timeout = -1; + break; + + case THR_IDLE: + timeout = 30 * HZ; + break; + + case THR_PIO: + ata_pio_sector(ah); + break; + + case THR_PIO_LAST: + ata_pio_complete(ah); + break; + + case THR_PIO_POLL: + case THR_PIO_LAST_POLL: + timeout = ata_pio_poll(ah); + break; + + case THR_PIO_TMOUT: + printk(KERN_ERR "ata%d: FIXME: THR_PIO_TMOUT\n", /* FIXME */ + ah->id); + timeout = 11 * HZ; + break; + + case THR_PIO_ERR: + printk(KERN_ERR "ata%d: FIXME: THR_PIO_ERR\n", /* FIXME */ + ah->id); + timeout = 11 * HZ; + break; + + default: + DPRINTK("unknown thread state %u!\n", ah->thr_state); + break; + } + + DPRINTK("ata%u: new thr_state %s, returning %ld\n", + ah->id, ata_thr_state_name(ah->thr_state), timeout); + return timeout; +} + +static int ata_thread (void *data) +{ + struct ata_host *ah = data; + long timeout; + + daemonize ("katad-%u", ah->id); + allow_signal(SIGTERM); + + while (1) { + cond_resched(); + + timeout = ata_thread_iter(ah); + + if (signal_pending (current)) + flush_signals(current); + + if ((timeout < 0) || (ah->time_to_die)) + break; + + /* note sleeping for full timeout not guaranteed (that's ok) */ + if (timeout) { + mod_timer(&ah->thr_timer, jiffies + timeout); + down_interruptible(&ah->thr_sem); + + if (signal_pending (current)) + flush_signals(current); + + if (ah->time_to_die) + break; + } + } + + printk(KERN_INFO "ata%u: thread exiting\n", ah->id); + ah->thr_pid = -1; + complete_and_exit (&ah->thr_exited, 0); +} + +static void ata_to_sense_error(struct ata_queued_cmd *qc, Scsi_Cmnd *cmd) +{ + cmd->result = SAM_STAT_CHECK_CONDITION; + + cmd->sense_buffer[0] = 0x70; + cmd->sense_buffer[2] = MEDIUM_ERROR; + cmd->sense_buffer[7] = 14 - 8; /* addnl. sense len. FIXME: correct? */ + + /* additional-sense-code[-qualifier] */ + if ((qc->flags & ATA_QCFLAG_WRITE) == 0) { + cmd->sense_buffer[12] = 0x11; /* "unrecovered read error" */ + cmd->sense_buffer[13] = 0x04; + } else { + cmd->sense_buffer[12] = 0x0C; /* "write error - */ + cmd->sense_buffer[13] = 0x02; /* auto-reallocation failed" */ + } + + qc->done(cmd); +} + +int ata_scsi_error(struct Scsi_Host *host) +{ + struct ata_host *ah; + struct ata_queued_cmd *qc; + Scsi_Cmnd *cmd; + + DPRINTK("ENTER\n"); + ah = (struct ata_host *) &host->hostdata[0]; + + ata_timer(ah); + + /* FIXME: support TCQ */ + qc = &ah->qcmd[0]; + if (qc->flags & ATA_QCFLAG_ACTIVE) { + DPRINTK("cancelling command\n"); + + ata_sg_clean(ah, qc); + + cmd = qc->scsicmd; + + /* FIXME: slackness!! we just assume medium error */ + ata_to_sense_error(qc, cmd); + + qc->flags &= ~ATA_QCFLAG_ACTIVE; + } + + DPRINTK("EXIT\n"); + return 0; +} + +static unsigned int scsi_rw_to_ata(struct ata_queued_cmd *qc, u8 *scsicmd, + unsigned int cmd_size) +{ + struct ata_taskfile *tf = &qc->tf; + unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; + unsigned int pio = tf->flags & ATA_TFLAG_PIO; + + qc->cursect = qc->cursg = qc->cursg_ofs = 0; + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->hob_nsect = 0; + tf->hob_lbal = 0; + tf->hob_lbam = 0; + tf->hob_lbah = 0; + + if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 || + scsicmd[0] == READ_16) { + if (pio) { + if (lba48) + tf->command = ATA_CMD_PIO_READ_EXT; + else + tf->command = ATA_CMD_PIO_READ; + } else { + if (lba48) + tf->command = ATA_CMD_READ_EXT; + else + tf->command = ATA_CMD_READ; + } + qc->flags &= ~ATA_QCFLAG_WRITE; + DPRINTK("reading\n"); + } else { + if (pio) { + if (lba48) + tf->command = ATA_CMD_PIO_WRITE_EXT; + else + tf->command = ATA_CMD_PIO_WRITE; + } else { + if (lba48) + tf->command = ATA_CMD_WRITE_EXT; + else + tf->command = ATA_CMD_WRITE; + } + qc->flags |= ATA_QCFLAG_WRITE; + DPRINTK("writing\n"); + } + + if (cmd_size == 10) { + if (lba48) { + tf->hob_nsect = scsicmd[7]; + tf->hob_lbal = scsicmd[2]; + + qc->nsect = ((unsigned int)scsicmd[7] << 8) | + scsicmd[8]; + } else { + /* if we don't support LBA48 addressing, the request + * -may- be too large. */ + if ((scsicmd[2] & 0xf0) || scsicmd[7]) + return 1; + + /* stores LBA27:24 in lower 4 bits of device reg */ + tf->device |= scsicmd[2]; + + qc->nsect = scsicmd[8]; + } + tf->device |= ATA_LBA; + + tf->nsect = scsicmd[8]; + tf->lbal = scsicmd[5]; + tf->lbam = scsicmd[4]; + tf->lbah = scsicmd[3]; + + DPRINTK("ten-byte command\n"); + return 0; + } + + if (cmd_size == 6) { + qc->nsect = tf->nsect = scsicmd[4]; + tf->lbal = scsicmd[3]; + tf->lbam = scsicmd[2]; + tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */ + + DPRINTK("six-byte command\n"); + return 0; + } + + if (cmd_size == 16) { + /* rule out impossible LBAs and sector counts */ + if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11]) + return 1; + + if (lba48) { + tf->hob_nsect = scsicmd[12]; + tf->hob_lbal = scsicmd[6]; + tf->hob_lbam = scsicmd[5]; + tf->hob_lbah = scsicmd[4]; + + qc->nsect = ((unsigned int)scsicmd[12] << 8) | + scsicmd[13]; + } else { + /* once again, filter out impossible non-zero values */ + if (scsicmd[4] || scsicmd[5] || scsicmd[12] || + (scsicmd[6] & 0xf0)) + return 1; + + /* stores LBA27:24 in lower 4 bits of device reg */ + tf->device |= scsicmd[2]; + + qc->nsect = scsicmd[13]; + } + tf->device |= ATA_LBA; + + tf->nsect = scsicmd[13]; + tf->lbal = scsicmd[9]; + tf->lbam = scsicmd[8]; + tf->lbah = scsicmd[7]; + + DPRINTK("sixteen-byte command\n"); + return 0; + } + + DPRINTK("no-byte command\n"); + return 1; +} + +static void ata_do_rw(struct ata_host *ah, struct ata_device *dev, + Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *), + unsigned int cmd_size) +{ + struct ata_queued_cmd *qc; + u8 *scsicmd = cmd->cmnd; + unsigned int pio; + + VPRINTK("ENTER\n"); + /* FIXME: support TCQ */ + qc = &ah->qcmd[0]; + qc->flags = ATA_QCFLAG_ACTIVE; + qc->scsicmd = cmd; + qc->done = done; + + ata_dev_select(ah, dev->devno, 0, 1); + + ata_tf_init(ah, &qc->tf); + pio = (dev->flags & ATA_DFLAG_PIO); + if (pio) + qc->tf.flags |= ATA_TFLAG_PIO; + else + qc->flags |= ATA_QCFLAG_DMA; + if (scsi_rw_to_ata(qc, scsicmd, cmd_size)) + goto err_out; + + /* set up SG table */ + if (cmd->use_sg) { + if (ata_sg_setup(ah, qc)) + goto err_out; + } else { + printk(KERN_ERR "ata%u: BUG: cmd->use_sg == 0\n", ah->id); + goto err_out; + } + + if (pio) + ata_pio_start(ah, qc); + else + ata_dma_start(ah, qc); + + VPRINTK("EXIT\n"); + return; + +err_out: + ata_scsi_badcmd(cmd, done, 0x24, 0x00); + DPRINTK("EXIT - badcmd\n"); +} + +static unsigned int ata_scsi_get_reqbuf(Scsi_Cmnd *cmd, u8 **buf_out) +{ + u8 *buf; + unsigned int buflen; + + if (cmd->use_sg) { + struct scatterlist *sg; + + sg = (struct scatterlist *) cmd->request_buffer; + buf = kmap(sg->page) + sg->offset; + buflen = sg->length; + } else { + buf = cmd->request_buffer; + buflen = cmd->request_bufflen; + } + + memset(buf, 0, buflen); + *buf_out = buf; + return buflen; +} + +static inline void ata_scsi_put_reqbuf(Scsi_Cmnd *cmd) +{ + if (cmd->use_sg) { + struct scatterlist *sg; + + sg = (struct scatterlist *) cmd->request_buffer; + kunmap(sg->page); + } +} + +static void ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *reqbuf, + unsigned int buflen) +{ + VPRINTK("ENTER\n"); + + reqbuf[0] = TYPE_DISK; + reqbuf[2] = 0x5; /* claim SPC-3 version compatibility */ + reqbuf[3] = 2; + reqbuf[4] = 96 - 4; + + if (buflen > 36) { + memcpy(&reqbuf[8], args->dev->vendor, 8); + memcpy(&reqbuf[16], args->dev->product, 16); + memcpy(&reqbuf[32], DRV_VERSION, 4); + } + + if (buflen > 63) { + reqbuf[59] = 0x60; /* SAM-3 (no version claimed) */ + + reqbuf[60] = 0x03; + reqbuf[61] = 0x20; /* SBC-2 (no version claimed) */ + + reqbuf[62] = 0x02; + reqbuf[63] = 0x60; /* SPC-3 (no version claimed) */ + } +} + +static void ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *reqbuf, + unsigned int buflen) +{ + reqbuf[3] = 3; /* number of supported EVPD pages */ + + if (buflen > 6) { + reqbuf[4] = 0x00; /* page 0x00, this page */ + reqbuf[5] = 0x80; /* page 0x80, unit serial no page */ + reqbuf[6] = 0x83; /* page 0x83, device ident page */ + } +} + +static void ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *reqbuf, + unsigned int buflen) +{ + reqbuf[1] = 0x80; /* this page code */ + reqbuf[3] = ATA_SERNO_LEN; /* page len */ + + if (buflen > (ATA_SERNO_LEN + 4)) + ata_dev_id_string(args->dev, (unsigned char *) &reqbuf[4], + ATA_ID_SERNO_OFS, ATA_SERNO_LEN); +} + +static const char *inq_83_str = "Linux ATA-SCSI simulator"; + +static void ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *reqbuf, + unsigned int buflen) +{ + reqbuf[1] = 0x83; /* this page code */ + reqbuf[3] = 4 + strlen(inq_83_str); /* page len */ + + /* our one and only identification descriptor (vendor-specific) */ + if (buflen > (strlen(inq_83_str) + 4 + 4)) { + reqbuf[4 + 0] = 2; /* code set: ASCII */ + reqbuf[4 + 3] = strlen(inq_83_str); + memcpy(reqbuf + 4 + 4, inq_83_str, strlen(inq_83_str)); + } +} + +static void ata_scsiop_noop(struct ata_scsi_args *args, u8 *reqbuf, + unsigned int buflen) +{ + VPRINTK("ENTER\n"); +} + +static void ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *reqbuf, + unsigned int buflen) +{ + u64 n_sectors = args->dev->n_sectors; + u32 tmp; + + VPRINTK("ENTER\n"); + + tmp = n_sectors; /* note: truncates, if lba48 */ + if (args->cmd->cmnd[0] == READ_CAPACITY) { + reqbuf[0] = tmp >> (8 * 3); + reqbuf[1] = tmp >> (8 * 2); + reqbuf[2] = tmp >> (8 * 1); + reqbuf[3] = tmp; + + tmp = ATA_SECT_SIZE; + reqbuf[6] = tmp >> 8; + reqbuf[7] = tmp; + + } else { + reqbuf[2] = n_sectors >> (8 * 7); + reqbuf[3] = n_sectors >> (8 * 6); + reqbuf[4] = n_sectors >> (8 * 5); + reqbuf[5] = n_sectors >> (8 * 4); + reqbuf[6] = tmp >> (8 * 3); + reqbuf[7] = tmp >> (8 * 2); + reqbuf[8] = tmp >> (8 * 1); + reqbuf[9] = tmp; + + tmp = ATA_SECT_SIZE; + reqbuf[12] = tmp >> 8; + reqbuf[13] = tmp; + } +} + +static void ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *reqbuf, + unsigned int buflen) +{ + VPRINTK("ENTER\n"); + reqbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */ +} + +static void ata_scsi_reqfill(struct ata_scsi_args *args, + void (*actor) (struct ata_scsi_args *args, + u8 *reqbuf, + unsigned int buflen)) +{ + u8 *reqbuf; + unsigned int buflen; + Scsi_Cmnd *cmd = args->cmd; + + buflen = ata_scsi_get_reqbuf(cmd, &reqbuf); + actor(args, reqbuf, buflen); + ata_scsi_put_reqbuf(cmd); + + cmd->result = SAM_STAT_GOOD; + args->done(cmd); +} + +static void ata_scsi_badcmd(Scsi_Cmnd *cmd, + void (*done)(Scsi_Cmnd *), + u8 asc, u8 ascq) +{ + DPRINTK("ENTER\n"); + cmd->result = SAM_STAT_CHECK_CONDITION; + + cmd->sense_buffer[0] = 0x70; + cmd->sense_buffer[2] = ILLEGAL_REQUEST; + cmd->sense_buffer[7] = 14 - 8; /* addnl. sense len. FIXME: correct? */ + cmd->sense_buffer[12] = asc; + cmd->sense_buffer[13] = ascq; + + done(cmd); +} + +int ata_scsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +{ + u8 *scsicmd = cmd->cmnd; + struct ata_host *ah; + struct ata_device *dev; + struct ata_scsi_args args; + + DPRINTK("CDB (%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + cmd->channel, cmd->target, cmd->lun, + scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3], + scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7], + scsicmd[8]); + + /* skip commands not addressed to targets we care about */ + if ((cmd->device->channel != 0) || (cmd->device->lun != 0) || + (cmd->device->id >= ATA_MAX_DEVICES)) { + cmd->result = (DID_BAD_TARGET << 16); /* FIXME: correct? */ + done(cmd); + return 0; + } + + ah = (struct ata_host *) &cmd->device->host->hostdata[0]; + dev = &ah->device[cmd->device->id]; + + DPRINTK("ata%u: chan %u, target %u, lun %u\n", + ah->id, cmd->device->channel, cmd->device->id, + cmd->device->lun); + + if (!ata_dev_present(dev)) { + DPRINTK("no ATA device\n"); + cmd->result = (DID_BAD_TARGET << 16); /* FIXME: correct? */ + done(cmd); + return 0; + } + + if (dev->class == ATA_DEV_ATAPI) { + DPRINTK("FIXME: support ATAPI\n"); + cmd->result = (DID_BAD_TARGET << 16); /* FIXME: correct? */ + done(cmd); + return 0; + } + + /* fast path */ + switch(scsicmd[0]) { + case READ_6: + case WRITE_6: + ata_do_rw(ah, dev, cmd, done, 6); + return 0; + + case READ_10: + case WRITE_10: + ata_do_rw(ah, dev, cmd, done, 10); + return 0; + + case READ_16: + case WRITE_16: + ata_do_rw(ah, dev, cmd, done, 16); + return 0; + + default: + /* do nothing */ + break; + } + + /* + * slow path + */ + + args.ah = ah; + args.dev = dev; + args.cmd = cmd; + args.done = done; + + switch(scsicmd[0]) { + case TEST_UNIT_READY: /* FIXME: correct? */ + case FORMAT_UNIT: /* FIXME: correct? */ + case SEND_DIAGNOSTIC: /* FIXME: correct? */ + ata_scsi_reqfill(&args, ata_scsiop_noop); + break; + + case INQUIRY: + if (scsicmd[1] & 2) /* is CmdDt set? */ + ata_scsi_badcmd(cmd, done, 0x24, 0x00); + else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */ + ata_scsi_reqfill(&args, ata_scsiop_inq_std); + else if (scsicmd[2] == 0x00) + ata_scsi_reqfill(&args, ata_scsiop_inq_00); + else if (scsicmd[2] == 0x80) + ata_scsi_reqfill(&args, ata_scsiop_inq_80); + else if (scsicmd[2] == 0x83) + ata_scsi_reqfill(&args, ata_scsiop_inq_83); + else + ata_scsi_badcmd(cmd, done, 0x24, 0x00); + break; + + case READ_CAPACITY: + ata_scsi_reqfill(&args, ata_scsiop_read_cap); + break; + + case SERVICE_ACTION_IN: + if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16) + ata_scsi_reqfill(&args, ata_scsiop_read_cap); + else + ata_scsi_badcmd(cmd, done, 0x24, 0x00); + break; + + case REPORT_LUNS: + ata_scsi_reqfill(&args, ata_scsiop_report_luns); + break; + + /* mandantory commands we haven't implemented yet */ + case REQUEST_SENSE: + + /* all other commands */ + default: + ata_scsi_badcmd(cmd, done, 0x20, 0x00); + break; + } + + return 0; +} + +static void ata_host_remove(struct ata_host *ah, unsigned int do_unregister) +{ + struct Scsi_Host *sh = ah->host; + + DPRINTK("ENTER\n"); + outl(0, ah->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); + pci_free_consistent(ah->host_set->pdev, ATA_PRD_TBL_SZ, ah->prd, ah->prd_dma); + + if (do_unregister) + scsi_unregister(sh); +} + +static struct ata_host * __init ata_host_add(struct ata_probe_ent *ent, + struct ata_host_set *host_set, + unsigned int port_no) +{ + struct pci_dev *pdev = ent->pdev; + struct Scsi_Host *host; + struct ata_host *ah; + unsigned int i; + + DPRINTK("ENTER\n"); + host = scsi_register(ent->sht, sizeof(struct ata_host)); + if (!host) + return NULL; + + host->max_id = 16; + host->max_lun = 1; + host->max_channel = 1; + host->unique_id = ata_unique_id++; + host->max_cmd_len = 16; + + ah = (struct ata_host *) &host->hostdata[0]; + ah->flags = ATA_FLAG_PORT_DISABLED; + ah->id = host->unique_id; + ah->host = host; + ah->ctl = ATA_DEVCTL_OBS; + ah->host_set = host_set; + ah->port_no = port_no; + ah->pio_mask = ent->pio_mask; + ah->udma_mask = ent->udma_mask; + ah->flags |= ent->host_flags; + ah->ops = ent->host_ops; + ah->bus_state = BUS_UNKNOWN; + ah->thr_state = THR_PROBE_START; + ah->device[0].flags = ATA_DFLAG_MASTER; + for (i = 0; i < ATA_MAX_DEVICES; i++) + ah->device[i].devno = i; + init_completion(&ah->thr_exited); + init_MUTEX_LOCKED(&ah->probe_sem); + init_MUTEX_LOCKED(&ah->sem); + init_MUTEX_LOCKED(&ah->thr_sem); + init_timer(&ah->thr_timer); + ah->thr_timer.function = ata_thread_timer; + ah->thr_timer.data = (unsigned long) ah; +#ifdef ATA_IRQ_TRAP + ah->stats.unhandled_irq = 1; + ah->stats.idle_irq = 1; +#endif + + memcpy(&ah->ioaddr, &ent->port[port_no], sizeof(struct ata_ioports)); + + ah->prd = pci_alloc_consistent(pdev, ATA_PRD_TBL_SZ, &ah->prd_dma); + if (!ah->prd) + goto err_out; + DPRINTK("prd alloc, virt %p, dma %x\n", ah->prd, ah->prd_dma); + + ah->thr_pid = kernel_thread(ata_thread, ah, CLONE_FS | CLONE_FILES); + if (ah->thr_pid < 0) { + printk(KERN_ERR "ata%d: unable to start kernel thread\n", + ah->id); + goto err_out_free; + } + + return ah; + +err_out_free: + pci_free_consistent(ah->host_set->pdev, ATA_PRD_TBL_SZ, ah->prd, ah->prd_dma); +err_out: + scsi_unregister(host); + return NULL; +} + +static int __init ata_device_add(struct ata_probe_ent *ent) +{ + unsigned int count = 0, i; + struct pci_dev *pdev = ent->pdev; + struct ata_host_set *host_set; + struct ata_host *host; + + DPRINTK("ENTER\n"); + /* alloc a container for our list of ATA ports (buses) */ + host_set = kmalloc(sizeof(struct ata_host_set) + + (ent->n_ports * sizeof(void *)), GFP_KERNEL); + if (!host_set) + return 0; + memset(host_set, 0, sizeof(struct ata_host_set) + (ent->n_ports * sizeof(void *))); + INIT_LIST_HEAD(&host_set->driver_list); + spin_lock_init(&host_set->lock); + + host_set->pdev = pdev; + host_set->n_hosts = ent->n_ports; + host_set->irq = ent->irq; + + /* register each port bound to this device */ + for (i = 0; i < ent->n_ports; i++) { + host = ata_host_add(ent, host_set, i); + if (!host) + goto err_out; + + host_set->hosts[i] = host; + + /* print per-port info to dmesg */ + printk(KERN_INFO "ata%u: %cATA max %s cmd 0x%lX ctl 0x%lX " + "bmdma 0x%lX irq %lu\n", + host->id, + host->flags & ATA_FLAG_SATA ? 'S' : 'P', + ata_udma_string(ent->udma_mask), + host->ioaddr.cmd_addr, + host->ioaddr.ctl_addr, + host->ioaddr.bmdma_addr, + ent->irq); + + count++; + } + + if (!count) { + kfree(host_set); + return 0; + } + + /* obtain irq, that is shared between channels */ + if (request_irq(ent->irq, ata_interrupt, ent->irq_flags, + DRV_NAME, host_set)) + goto err_out; + + /* perform each probe synchronously */ + DPRINTK("probe begin\n"); + for (i = 0; i < count; i++) { + DPRINTK("ata%u: probe begin\n", host_set->hosts[i]->id); + up(&host_set->hosts[i]->sem); /* start probe */ + DPRINTK("ata%u: probe-wait begin\n", host_set->hosts[i]->id); + down(&host_set->hosts[i]->probe_sem); /* wait for end */ + DPRINTK("ata%u: probe-wait end\n", host_set->hosts[i]->id); + } + + /* add to driver-global list */ + spin_lock(&ata_module_lock); + list_add_tail(&host_set->driver_list, &ata_scsihost_list); + spin_unlock(&ata_module_lock); + + pci_set_drvdata(pdev, host_set); + + VPRINTK("EXIT, returning %u\n", ent->n_ports); + return ent->n_ports; /* success */ + +err_out: + for (i = 0; i < count; i++) + ata_host_remove(host_set->hosts[i], 1); + kfree(host_set); + VPRINTK("EXIT, returning 0\n"); + return 0; +} + +int ata_scsi_detect(Scsi_Host_Template *sht) +{ + struct list_head *node; + struct ata_probe_ent *ent; + int count = 0; + + VPRINTK("ENTER\n"); + + spin_lock(&ata_module_lock); + while (!list_empty(&ata_probe_list)) { + node = ata_probe_list.next; + ent = list_entry(node, struct ata_probe_ent, node); + list_del(node); + + spin_unlock(&ata_module_lock); + + count += ata_device_add(ent); + kfree(ent); + + spin_lock(&ata_module_lock); + } + spin_unlock(&ata_module_lock); + + VPRINTK("EXIT, returning %d\n", count); + return count; +} + +int ata_scsi_release(struct Scsi_Host *host) +{ + struct ata_host *ah = (struct ata_host *) &host->hostdata[0]; + int ret = 0; + + DPRINTK("ENTER\n"); + + if (ah->thr_pid >= 0) { + ah->time_to_die = 1; + wmb(); + ret = kill_proc(ah->thr_pid, SIGTERM, 1); + if (ret) { + printk(KERN_ERR "ata%d: unable to kill kernel thread\n", + ah->id); + return 0; /* FIXME: correct ret code? */ + } + wait_for_completion(&ah->thr_exited); + } + + ah->ops->port_disable(ah); + ata_host_remove(ah, 0); + + DPRINTK("EXIT\n"); + return 1; +} + +int ata_pci_init_one (struct pci_dev *pdev, struct ata_board *board_info, + struct ata_host_ops *host_ops) +{ + struct ata_probe_ent *probe_ent, *probe_ent2 = NULL; + u8 tmp8, mask; + unsigned int legacy_mode = 0; + int rc; + + DPRINTK("ENTER\n"); + + /* require that firmware put us in native mode. + * FIXME: temporary restriction. + */ + pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); + mask = (1 << 2) | (1 << 0); + if ((tmp8 & mask) != mask) + legacy_mode = 1; + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) { + rc = -ENOMEM; + goto err_out_regions; + } + + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->pdev = pdev; + INIT_LIST_HEAD(&probe_ent->node); + + if (legacy_mode) { + probe_ent2 = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent2) { + rc = -ENOMEM; + goto err_out_free_ent; + } + + memset(probe_ent2, 0, sizeof(*probe_ent)); + probe_ent2->pdev = pdev; + INIT_LIST_HEAD(&probe_ent2->node); + } + + probe_ent->pio_mask = board_info->pio_mask; + probe_ent->udma_mask = board_info->udma_mask; + probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); + probe_ent->host_flags = board_info->host_flags; + probe_ent->host_ops = host_ops; + probe_ent->sht = board_info->sht; + + if (legacy_mode) { + probe_ent->port[0].cmd_addr = 0x1f0; + probe_ent->port[0].ctl_addr = 0x3f6; + probe_ent->n_ports = 1; + probe_ent->irq = 14; + + probe_ent2->port[0].cmd_addr = 0x170; + probe_ent2->port[0].ctl_addr = 0x376; + probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8; + probe_ent2->n_ports = 1; + probe_ent2->irq = 15; + + probe_ent2->pio_mask = board_info->pio_mask; + probe_ent2->udma_mask = board_info->udma_mask; + probe_ent2->host_flags = board_info->host_flags; + probe_ent2->host_ops = host_ops; + probe_ent2->sht = board_info->sht; + } else { + probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); + probe_ent->port[0].ctl_addr = + pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; + + probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); + probe_ent->port[1].ctl_addr = + pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; + probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; + + probe_ent->n_ports = 2; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + } + + pci_set_master(pdev); + + spin_lock(&ata_module_lock); + list_add_tail(&probe_ent->node, &ata_probe_list); + if (legacy_mode) + list_add_tail(&probe_ent2->node, &ata_probe_list); + spin_unlock(&ata_module_lock); + + return 0; + +err_out_free_ent: + kfree(probe_ent); +err_out_regions: + pci_release_regions(pdev); +err_out: + pci_disable_device(pdev); + return rc; +} + +void ata_pci_remove_one (struct pci_dev *pdev) +{ + struct ata_host_set *host_set = pci_get_drvdata(pdev); + + /* FIXME: remove host_set from module-global list */ + + free_irq(host_set->irq, host_set); + kfree(host_set); + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +static int __init ata_init(void) +{ + printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n"); + return 0; +} + +module_init(ata_init); + +EXPORT_SYMBOL(ata_port_probe); +EXPORT_SYMBOL(ata_port_disable); +EXPORT_SYMBOL(ata_pci_init_one); +EXPORT_SYMBOL(ata_pci_remove_one); +EXPORT_SYMBOL(ata_scsi_detect); +EXPORT_SYMBOL(ata_scsi_release); +EXPORT_SYMBOL(ata_scsi_queuecmd); +EXPORT_SYMBOL(ata_scsi_error); + diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h --- a/drivers/scsi/scsi.h Sat May 24 14:40:31 2003 +++ b/drivers/scsi/scsi.h Sat May 24 14:40:31 2003 @@ -1,686 +1,6 @@ -/* - * scsi.h Copyright (C) 1992 Drew Eckhardt - * Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale - * generic SCSI package header file by - * Initial versions: Drew Eckhardt - * Subsequent revisions: Eric Youngdale - * - * - * - * Modified by Eric Youngdale eric@andante.org to - * add scatter-gather, multiple outstanding request, and other - * enhancements. - */ +#ifndef __DRIVERS_SCSI_SCSI_H +#define __DRIVERS_SCSI_SCSI_H -#ifndef _SCSI_H -#define _SCSI_H +#include -#include /* for CONFIG_SCSI_LOGGING */ -#include - -/* - * These are the values that the SCpnt->sc_data_direction and - * SRpnt->sr_data_direction can take. These need to be set - * The SCSI_DATA_UNKNOWN value is essentially the default. - * In the event that the command creator didn't bother to - * set a value, you will see SCSI_DATA_UNKNOWN. - */ -#define SCSI_DATA_UNKNOWN 0 -#define SCSI_DATA_WRITE 1 -#define SCSI_DATA_READ 2 -#define SCSI_DATA_NONE 3 - -#ifdef CONFIG_PCI -#include -#if ((SCSI_DATA_UNKNOWN == PCI_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == PCI_DMA_TODEVICE) && (SCSI_DATA_READ == PCI_DMA_FROMDEVICE) && (SCSI_DATA_NONE == PCI_DMA_NONE)) -#define scsi_to_pci_dma_dir(scsi_dir) ((int)(scsi_dir)) -#else -extern __inline__ int scsi_to_pci_dma_dir(unsigned char scsi_dir) -{ - if (scsi_dir == SCSI_DATA_UNKNOWN) - return PCI_DMA_BIDIRECTIONAL; - if (scsi_dir == SCSI_DATA_WRITE) - return PCI_DMA_TODEVICE; - if (scsi_dir == SCSI_DATA_READ) - return PCI_DMA_FROMDEVICE; - return PCI_DMA_NONE; -} -#endif -#endif - -#if defined(CONFIG_SBUS) && !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) -#include -#if ((SCSI_DATA_UNKNOWN == SBUS_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == SBUS_DMA_TODEVICE) && (SCSI_DATA_READ == SBUS_DMA_FROMDEVICE) && (SCSI_DATA_NONE == SBUS_DMA_NONE)) -#define scsi_to_sbus_dma_dir(scsi_dir) ((int)(scsi_dir)) -#else -extern __inline__ int scsi_to_sbus_dma_dir(unsigned char scsi_dir) -{ - if (scsi_dir == SCSI_DATA_UNKNOWN) - return SBUS_DMA_BIDIRECTIONAL; - if (scsi_dir == SCSI_DATA_WRITE) - return SBUS_DMA_TODEVICE; - if (scsi_dir == SCSI_DATA_READ) - return SBUS_DMA_FROMDEVICE; - return SBUS_DMA_NONE; -} -#endif -#endif - -/* - * Some defs, in case these are not defined elsewhere. - */ -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#define MAX_SCSI_DEVICE_CODE 14 -extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; - -#ifdef DEBUG -#define SCSI_TIMEOUT (5*HZ) -#else -#define SCSI_TIMEOUT (2*HZ) -#endif - -/* - * Use these to separate status msg and our bytes - * - * These are set by: - * - * status byte = set from target device - * msg_byte = return status from host adapter itself. - * host_byte = set by low-level driver to indicate status. - * driver_byte = set by mid-level. - */ -#define status_byte(result) (((result) >> 1) & 0x1f) -#define msg_byte(result) (((result) >> 8) & 0xff) -#define host_byte(result) (((result) >> 16) & 0xff) -#define driver_byte(result) (((result) >> 24) & 0xff) -#define suggestion(result) (driver_byte(result) & SUGGEST_MASK) - -#define sense_class(sense) (((sense) >> 4) & 0x7) -#define sense_error(sense) ((sense) & 0xf) -#define sense_valid(sense) ((sense) & 0x80); - -#define NEEDS_RETRY 0x2001 -#define SUCCESS 0x2002 -#define FAILED 0x2003 -#define QUEUED 0x2004 -#define SOFT_ERROR 0x2005 -#define ADD_TO_MLQUEUE 0x2006 - -/* - * These are the values that scsi_cmd->state can take. - */ -#define SCSI_STATE_TIMEOUT 0x1000 -#define SCSI_STATE_FINISHED 0x1001 -#define SCSI_STATE_FAILED 0x1002 -#define SCSI_STATE_QUEUED 0x1003 -#define SCSI_STATE_UNUSED 0x1006 -#define SCSI_STATE_DISCONNECTING 0x1008 -#define SCSI_STATE_INITIALIZING 0x1009 -#define SCSI_STATE_BHQUEUE 0x100a -#define SCSI_STATE_MLQUEUE 0x100b - -#define IDENTIFY_BASE 0x80 -#define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\ - ((can_disconnect) ? 0x40 : 0) |\ - ((lun) & 0x07)) - -/* host byte codes */ -#define DID_OK 0x00 /* NO error */ -#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ -#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ -#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ -#define DID_BAD_TARGET 0x04 /* BAD target. */ -#define DID_ABORT 0x05 /* Told to abort for some other reason */ -#define DID_PARITY 0x06 /* Parity error */ -#define DID_ERROR 0x07 /* Internal error */ -#define DID_RESET 0x08 /* Reset by somebody. */ -#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ -#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ -#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ -#define DRIVER_OK 0x00 /* Driver status */ - -/* - * These indicate the error that occurred, and what is available. - */ - -#define DRIVER_BUSY 0x01 -#define DRIVER_SOFT 0x02 -#define DRIVER_MEDIA 0x03 -#define DRIVER_ERROR 0x04 - -#define DRIVER_INVALID 0x05 -#define DRIVER_TIMEOUT 0x06 -#define DRIVER_HARD 0x07 -#define DRIVER_SENSE 0x08 - -#define SUGGEST_RETRY 0x10 -#define SUGGEST_ABORT 0x20 -#define SUGGEST_REMAP 0x30 -#define SUGGEST_DIE 0x40 -#define SUGGEST_SENSE 0x80 -#define SUGGEST_IS_OK 0xff - -#define DRIVER_MASK 0x0f -#define SUGGEST_MASK 0xf0 - -#define MAX_COMMAND_SIZE 16 -#define SCSI_SENSE_BUFFERSIZE 64 - -/* - * SCSI command sets - */ - -#define SCSI_UNKNOWN 0 -#define SCSI_1 1 -#define SCSI_1_CCS 2 -#define SCSI_2 3 -#define SCSI_3 4 - -/* - * Every SCSI command starts with a one byte OP-code. - * The next byte's high three bits are the LUN of the - * device. Any multi-byte quantities are stored high byte - * first, and may have a 5 bit MSB in the same byte - * as the LUN. - */ - -/* - * As the scsi do command functions are intelligent, and may need to - * redo a command, we need to keep track of the last command - * executed on each one. - */ - -#define WAS_RESET 0x01 -#define WAS_TIMEDOUT 0x02 -#define WAS_SENSE 0x04 -#define IS_RESETTING 0x08 -#define IS_ABORTING 0x10 -#define ASKED_FOR_SENSE 0x20 -#define SYNC_RESET 0x40 - -/* - * This specifies "machine infinity" for host templates which don't - * limit the transfer size. Note this limit represents an absolute - * maximum, and may be over the transfer limits allowed for individual - * devices (e.g. 256 for SCSI-1) - */ -#define SCSI_DEFAULT_MAX_SECTORS 1024 - -/* - * This is the crap from the old error handling code. We have it in a special - * place so that we can more easily delete it later on. - */ -#include "scsi_obsolete.h" - -/* - * Forward-declaration of structs for prototypes. - */ -struct Scsi_Host; -struct scsi_target; -struct scatterlist; - -/* - * Add some typedefs so that we can prototyope a bunch of the functions. - */ -typedef struct scsi_device Scsi_Device; -typedef struct scsi_cmnd Scsi_Cmnd; -typedef struct scsi_request Scsi_Request; - -/* - * These are the error handling functions defined in scsi_error.c - */ -extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout, - void (*complete) (Scsi_Cmnd *)); -extern int scsi_delete_timer(Scsi_Cmnd * SCset); -extern int scsi_block_when_processing_errors(Scsi_Device *); -extern void scsi_sleep(int); - -/* - * Prototypes for functions in scsicam.c - */ -extern int scsi_partsize(unsigned char *buf, unsigned long capacity, - unsigned int *cyls, unsigned int *hds, - unsigned int *secs); - -/* - * Prototypes for functions in scsi_lib.c - */ -extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, - int block_sectors); - -/* - * Prototypes for functions in scsi.c - */ -extern struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int flags); -extern void scsi_put_command(struct scsi_cmnd *cmd); -extern void scsi_adjust_queue_depth(Scsi_Device *, int, int); -extern int scsi_track_queue_full(Scsi_Device *, int); -extern int scsi_device_get(struct scsi_device *); -extern void scsi_device_put(struct scsi_device *); -extern void scsi_set_device_offline(struct scsi_device *); - -/* - * Newer request-based interfaces. - */ -extern Scsi_Request *scsi_allocate_request(Scsi_Device *); -extern void scsi_release_request(Scsi_Request *); -extern void scsi_wait_req(Scsi_Request *, const void *cmnd, - void *buffer, unsigned bufflen, - int timeout, int retries); -extern void scsi_do_req(Scsi_Request *, const void *cmnd, - void *buffer, unsigned bufflen, - void (*done) (struct scsi_cmnd *), - int timeout, int retries); - -/* - * Prototypes for functions in scsi_scan.c - */ -extern struct scsi_device *scsi_add_device(struct Scsi_Host *, - uint, uint, uint); -extern int scsi_remove_device(struct scsi_device *); -extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *); - -/* - * Prototypes for functions in constants.c - * Some of these used to live in constants.h - */ -extern void print_Scsi_Cmnd (Scsi_Cmnd *); -extern void print_command(unsigned char *); -extern void print_sense(const char *, Scsi_Cmnd *); -extern void print_req_sense(const char *, Scsi_Request *); -extern void print_driverbyte(int scsiresult); -extern void print_hostbyte(int scsiresult); -extern void print_status(unsigned char status); -extern int print_msg(const unsigned char *); -extern const char *scsi_sense_key_string(unsigned char); -extern const char *scsi_extd_sense_format(unsigned char, unsigned char); - - -/* - * The scsi_device struct contains what we know about each given scsi - * device. - * - * FIXME(eric) - One of the great regrets that I have is that I failed to - * define these structure elements as something like sdev_foo instead of foo. - * This would make it so much easier to grep through sources and so forth. - * I propose that all new elements that get added to these structures follow - * this convention. As time goes on and as people have the stomach for it, - * it should be possible to go back and retrofit at least some of the elements - * here with with the prefix. - */ - -struct scsi_device { - /* - * This information is private to the scsi mid-layer. - */ - struct list_head siblings; /* list of all devices on this host */ - struct list_head same_target_siblings; /* just the devices sharing same target id */ - struct Scsi_Host *host; - request_queue_t *request_queue; - volatile unsigned short device_busy; /* commands actually active on low-level */ - spinlock_t sdev_lock; /* also the request queue_lock */ - spinlock_t list_lock; - struct list_head cmd_list; /* queue of in use SCSI Command structures */ - struct list_head starved_entry; - Scsi_Cmnd *current_cmnd; /* currently active command */ - unsigned short queue_depth; /* How deep of a queue we want */ - unsigned short last_queue_full_depth; /* These two are used by */ - unsigned short last_queue_full_count; /* scsi_track_queue_full() */ - unsigned long last_queue_full_time;/* don't let QUEUE_FULLs on the same - jiffie count on our counter, they - could all be from the same event. */ - - unsigned int id, lun, channel; - - unsigned int manufacturer; /* Manufacturer of device, for using - * vendor-specific cmd's */ - unsigned sector_size; /* size in bytes */ - - int access_count; /* Count of open channels/mounts */ - - void *hostdata; /* available to low-level driver */ - char devfs_name[256]; /* devfs junk */ - char type; - char scsi_level; - unsigned char inquiry_len; /* valid bytes in 'inquiry' */ - unsigned char * inquiry; /* INQUIRY response data */ - char * vendor; /* [back_compat] point into 'inquiry' ... */ - char * model; /* ... after scan; point to static string */ - char * rev; /* ... "nullnullnullnull" before scan */ - unsigned char current_tag; /* current tag */ -// unsigned char sync_min_period; /* Not less than this period */ -// unsigned char sync_max_offset; /* Not greater than this offset */ - struct scsi_target *sdev_target; /* used only for single_lun */ - - unsigned online:1; - unsigned writeable:1; - unsigned removable:1; - unsigned random:1; - unsigned changed:1; /* Data invalid due to media change */ - unsigned busy:1; /* Used to prevent races */ - unsigned lockable:1; /* Able to prevent media removal */ - unsigned locked:1; /* Media removal disabled */ - unsigned borken:1; /* Tell the Seagate driver to be - * painfully slow on this device */ - unsigned disconnect:1; /* can disconnect */ - unsigned soft_reset:1; /* Uses soft reset option */ - unsigned sdtr:1; /* Device supports SDTR messages */ - unsigned wdtr:1; /* Device supports WDTR messages */ - unsigned ppr:1; /* Device supports PPR messages */ - unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */ - unsigned tagged_queue:1;/* This is going away!!!! Look at simple_tags - instead!!! Please fix your driver now!! */ - unsigned simple_tags:1; /* simple queue tag messages are enabled */ - unsigned ordered_tags:1;/* ordered queue tag messages are enabled */ - unsigned single_lun:1; /* Indicates we should only allow I/O to - * one of the luns for the device at a - * time. */ - unsigned was_reset:1; /* There was a bus reset on the bus for - * this device */ - unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN - * because we did a bus reset. */ - unsigned ten:1; /* support ten byte read / write */ - unsigned remap:1; /* support remapping */ -// unsigned sync:1; /* Sync transfer state, managed by host */ -// unsigned wide:1; /* WIDE transfer state, managed by host */ - - unsigned int device_blocked; /* Device returned QUEUE_FULL. */ - - unsigned int max_device_blocked; /* what device_blocked counts down from */ - /* default value if the device doesn't override */ - #define SCSI_DEFAULT_DEVICE_BLOCKED 3 - - struct device sdev_driverfs_dev; -}; -#define to_scsi_device(d) \ - container_of(d, struct scsi_device, sdev_driverfs_dev) - - -/* - * The Scsi_Cmnd structure is used by scsi.c internally, and for communication - * with low level drivers that support multiple outstanding commands. - */ -typedef struct scsi_pointer { - char *ptr; /* data pointer */ - int this_residual; /* left in this buffer */ - struct scatterlist *buffer; /* which buffer */ - int buffers_residual; /* how many buffers left */ - - dma_addr_t dma_handle; - - volatile int Status; - volatile int Message; - volatile int have_data_in; - volatile int sent_command; - volatile int phase; -} Scsi_Pointer; - -/* - * This is essentially a slimmed down version of Scsi_Cmnd. The point of - * having this is that requests that are injected into the queue as result - * of things like ioctls and character devices shouldn't be using a - * Scsi_Cmnd until such a time that the command is actually at the head - * of the queue and being sent to the driver. - */ -struct scsi_request { - int sr_magic; - int sr_result; /* Status code from lower level driver */ - unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE - * when CHECK CONDITION is - * received on original command - * (auto-sense) */ - - struct Scsi_Host *sr_host; - Scsi_Device *sr_device; - Scsi_Cmnd *sr_command; - struct request *sr_request; /* A copy of the command we are - working on */ - unsigned sr_bufflen; /* Size of data buffer */ - void *sr_buffer; /* Data buffer */ - int sr_allowed; - unsigned char sr_data_direction; - unsigned char sr_cmd_len; - unsigned char sr_cmnd[MAX_COMMAND_SIZE]; - void (*sr_done) (struct scsi_cmnd *); /* Mid-level done function */ - int sr_timeout_per_command; - unsigned short sr_use_sg; /* Number of pieces of scatter-gather */ - unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */ - unsigned sr_underflow; /* Return error if less than - this amount is transferred */ - void * upper_private_data; /* reserved for owner (usually upper - level driver) of this request */ -}; - -/* - * FIXME(eric) - one of the great regrets that I have is that I failed to define - * these structure elements as something like sc_foo instead of foo. This would - * make it so much easier to grep through sources and so forth. I propose that - * all new elements that get added to these structures follow this convention. - * As time goes on and as people have the stomach for it, it should be possible to - * go back and retrofit at least some of the elements here with with the prefix. - */ -struct scsi_cmnd { - int sc_magic; - - struct scsi_device *device; - unsigned short state; - unsigned short owner; - Scsi_Request *sc_request; - - struct list_head list; /* scsi_cmnd participates in queue lists */ - - struct list_head eh_entry; /* entry for the host eh_cmd_q */ - int eh_state; /* Used for state tracking in error handlr */ - int eh_eflags; /* Used by error handlr */ - void (*done) (struct scsi_cmnd *); /* Mid-level done function */ - /* - A SCSI Command is assigned a nonzero serial_number when internal_cmnd - passes it to the driver's queue command function. The serial_number - is cleared when scsi_done is entered indicating that the command has - been completed. If a timeout occurs, the serial number at the moment - of timeout is copied into serial_number_at_timeout. By subsequently - comparing the serial_number and serial_number_at_timeout fields - during abort or reset processing, we can detect whether the command - has already completed. This also detects cases where the command has - completed and the SCSI Command structure has already being reused - for another command, so that we can avoid incorrectly aborting or - resetting the new command. - */ - - unsigned long serial_number; - unsigned long serial_number_at_timeout; - - int retries; - int allowed; - int timeout_per_command; - int timeout_total; - int timeout; - - /* - * We handle the timeout differently if it happens when a reset, - * abort, etc are in process. - */ - unsigned volatile char internal_timeout; - - unsigned char cmd_len; - unsigned char old_cmd_len; - unsigned char sc_data_direction; - unsigned char sc_old_data_direction; - - /* These elements define the operation we are about to perform */ - unsigned char cmnd[MAX_COMMAND_SIZE]; - unsigned request_bufflen; /* Actual request size */ - - struct timer_list eh_timeout; /* Used to time out the command. */ - void *request_buffer; /* Actual requested buffer */ - - /* These elements define the operation we ultimately want to perform */ - unsigned char data_cmnd[MAX_COMMAND_SIZE]; - unsigned short old_use_sg; /* We save use_sg here when requesting - * sense info */ - unsigned short use_sg; /* Number of pieces of scatter-gather */ - unsigned short sglist_len; /* size of malloc'd scatter-gather list */ - unsigned short abort_reason; /* If the mid-level code requests an - * abort, this is the reason. */ - unsigned bufflen; /* Size of data buffer */ - void *buffer; /* Data buffer */ - - unsigned underflow; /* Return error if less than - this amount is transferred */ - unsigned old_underflow; /* save underflow here when reusing the - * command for error handling */ - - unsigned transfersize; /* How much we are guaranteed to - transfer with each SCSI transfer - (ie, between disconnect / - reconnects. Probably == sector - size */ - - int resid; /* Number of bytes requested to be - transferred less actual number - transferred (0 if not supported) */ - - struct request *request; /* The command we are - working on */ - - unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE - * when CHECK CONDITION is - * received on original command - * (auto-sense) */ - - unsigned flags; - - /* Low-level done function - can be used by low-level driver to point - * to completion function. Not used by mid/upper level code. */ - void (*scsi_done) (struct scsi_cmnd *); - - /* - * The following fields can be written to by the host specific code. - * Everything else should be left alone. - */ - - Scsi_Pointer SCp; /* Scratchpad used by some host adapters */ - - unsigned char *host_scribble; /* The host adapter is allowed to - * call scsi_malloc and get some memory - * and hang it here. The host adapter - * is also expected to call scsi_free - * to release this memory. (The memory - * obtained by scsi_malloc is guaranteed - * to be at an address < 16Mb). */ - - int result; /* Status code from lower level driver */ - - unsigned char tag; /* SCSI-II queued command tag */ - unsigned long pid; /* Process ID, starts at 0 */ -}; - -/* - * Definitions and prototypes used for scsi mid-level queue. - */ -#define SCSI_MLQUEUE_HOST_BUSY 0x1055 -#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 -#define SCSI_MLQUEUE_EH_RETRY 0x1057 - -/* - * Reset request from external source - */ -#define SCSI_TRY_RESET_DEVICE 1 -#define SCSI_TRY_RESET_BUS 2 -#define SCSI_TRY_RESET_HOST 3 - -extern int scsi_reset_provider(Scsi_Device *, int); - -#define MSG_SIMPLE_TAG 0x20 -#define MSG_HEAD_TAG 0x21 -#define MSG_ORDERED_TAG 0x22 - -#define SCSI_NO_TAG (-1) /* identify no tag in use */ - -/** - * scsi_activate_tcq - turn on tag command queueing - * @SDpnt: device to turn on TCQ for - * @depth: queue depth - * - * Notes: - * Eventually, I hope depth would be the maximum depth - * the device could cope with and the real queue depth - * would be adjustable from 0 to depth. - **/ -static inline void scsi_activate_tcq(Scsi_Device *SDpnt, int depth) { - if(SDpnt->tagged_supported) { - if(!blk_queue_tagged(SDpnt->request_queue)) - blk_queue_init_tags(SDpnt->request_queue, depth); - scsi_adjust_queue_depth(SDpnt, MSG_ORDERED_TAG, depth); - } -} - -/** - * scsi_deactivate_tcq - turn off tag command queueing - * @SDpnt: device to turn off TCQ for - **/ -static inline void scsi_deactivate_tcq(Scsi_Device *SDpnt, int depth) { - if(blk_queue_tagged(SDpnt->request_queue)) - blk_queue_free_tags(SDpnt->request_queue); - scsi_adjust_queue_depth(SDpnt, 0, depth); -} - -/** - * scsi_populate_tag_msg - place a tag message in a buffer - * @SCpnt: pointer to the Scsi_Cmnd for the tag - * @msg: pointer to the area to place the tag - * - * Notes: - * designed to create the correct type of tag message for the - * particular request. Returns the size of the tag message. - * May return 0 if TCQ is disabled for this device. - **/ -static inline int scsi_populate_tag_msg(Scsi_Cmnd *SCpnt, char *msg) { - struct request *req = SCpnt->request; - - if(!blk_rq_tagged(req)) - return 0; - - if (req->flags & REQ_HARDBARRIER) - *msg++ = MSG_ORDERED_TAG; - else - *msg++ = MSG_SIMPLE_TAG; - - *msg++ = SCpnt->request->tag; - - return 2; -} - -/** - * scsi_find_tag - find a tagged command by device - * @SDpnt: pointer to the ScSI device - * @tag: the tag number - * - * Notes: - * Only works with tags allocated by the generic blk layer. - **/ -static inline Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) { - - struct request *req; - - if(tag == SCSI_NO_TAG) - /* single command, look in space */ - return SDpnt->current_cmnd; - - req = blk_queue_find_tag(SDpnt->request_queue, tag); - - if(req == NULL) - return NULL; - - return (Scsi_Cmnd *)req->special; -} - -int scsi_set_medium_removal(Scsi_Device *dev, char state); - -#endif /* _SCSI_H */ +#endif /* __DRIVERS_SCSI_SCSI_H */ diff -Nru a/drivers/scsi/scsi_obsolete.h b/drivers/scsi/scsi_obsolete.h --- a/drivers/scsi/scsi_obsolete.h Sat May 24 14:40:31 2003 +++ b/drivers/scsi/scsi_obsolete.h Sat May 24 14:40:31 2003 @@ -1,106 +1,6 @@ -/* - * scsi_obsolete.h Copyright (C) 1997 Eric Youngdale - * - */ +#ifndef __DRIVERS_SCSI_SCSI_OBSOLETE_H +#define __DRIVERS_SCSI_SCSI_OBSOLETE_H -#ifndef _SCSI_OBSOLETE_H -#define _SCSI_OBSOLETE_H +#include -/* - * These are the return codes for the abort and reset functions. The mid-level - * code uses these to decide what to do next. Each of the low level abort - * and reset functions must correctly indicate what it has done. - * The descriptions are written from the point of view of the mid-level code, - * so that the return code is telling the mid-level drivers exactly what - * the low level driver has already done, and what remains to be done. - */ - -/* We did not do anything. - * Wait some more for this command to complete, and if this does not work, - * try something more serious. */ -#define SCSI_ABORT_SNOOZE 0 - -/* This means that we were able to abort the command. We have already - * called the mid-level done function, and do not expect an interrupt that - * will lead to another call to the mid-level done function for this command */ -#define SCSI_ABORT_SUCCESS 1 - -/* We called for an abort of this command, and we should get an interrupt - * when this succeeds. Thus we should not restore the timer for this - * command in the mid-level abort function. */ -#define SCSI_ABORT_PENDING 2 - -/* Unable to abort - command is currently on the bus. Grin and bear it. */ -#define SCSI_ABORT_BUSY 3 - -/* The command is not active in the low level code. Command probably - * finished. */ -#define SCSI_ABORT_NOT_RUNNING 4 - -/* Something went wrong. The low level driver will indicate the correct - * error condition when it calls scsi_done, so the mid-level abort function - * can simply wait until this comes through */ -#define SCSI_ABORT_ERROR 5 - -/* We do not know how to reset the bus, or we do not want to. Bummer. - * Anyway, just wait a little more for the command in question, and hope that - * it eventually finishes. If it never finishes, the SCSI device could - * hang, so use this with caution. */ -#define SCSI_RESET_SNOOZE 0 - -/* We do not know how to reset the bus, or we do not want to. Bummer. - * We have given up on this ever completing. The mid-level code will - * request sense information to decide how to proceed from here. */ -#define SCSI_RESET_PUNT 1 - -/* This means that we were able to reset the bus. We have restarted all of - * the commands that should be restarted, and we should be able to continue - * on normally from here. We do not expect any interrupts that will return - * DID_RESET to any of the other commands in the host_queue, and the mid-level - * code does not need to do anything special to keep the commands alive. - * If a hard reset was performed then all outstanding commands on the - * bus have been restarted. */ -#define SCSI_RESET_SUCCESS 2 - -/* We called for a reset of this bus, and we should get an interrupt - * when this succeeds. Each command should get its own status - * passed up to scsi_done, but this has not happened yet. - * If a hard reset was performed, then we expect an interrupt - * for *each* of the outstanding commands that will have the - * effect of restarting the commands. - */ -#define SCSI_RESET_PENDING 3 - -/* We did a reset, but do not expect an interrupt to signal DID_RESET. - * This tells the upper level code to request the sense info, and this - * should keep the command alive. */ -#define SCSI_RESET_WAKEUP 4 - -/* The command is not active in the low level code. Command probably - finished. */ -#define SCSI_RESET_NOT_RUNNING 5 - -/* Something went wrong, and we do not know how to fix it. */ -#define SCSI_RESET_ERROR 6 - -#define SCSI_RESET_SYNCHRONOUS 0x01 -#define SCSI_RESET_ASYNCHRONOUS 0x02 -#define SCSI_RESET_SUGGEST_BUS_RESET 0x04 -#define SCSI_RESET_SUGGEST_HOST_RESET 0x08 -/* - * This is a bitmask that is ored with one of the above codes. - * It tells the mid-level code that we did a hard reset. - */ -#define SCSI_RESET_BUS_RESET 0x100 -/* - * This is a bitmask that is ored with one of the above codes. - * It tells the mid-level code that we did a host adapter reset. - */ -#define SCSI_RESET_HOST_RESET 0x200 -/* - * Used to mask off bits and to obtain the basic action that was - * performed. - */ -#define SCSI_RESET_ACTION 0xff - -#endif /* SCSI_OBSOLETE_H */ +#endif /* __DRIVERS_SCSI_SCSI_OBSOLETE_H */ diff -Nru a/include/linux/ata.h b/include/linux/ata.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/ata.h Sat May 24 14:40:31 2003 @@ -0,0 +1,483 @@ +/* + Copyright 2003 Red Hat, Inc. All rights reserved. + Copyright 2003 Jeff Garzik + + The contents of this file are subject to the Open + Software License version 1.1 that can be found at + http://www.opensource.org/licenses/osl-1.1.txt and is included herein + by reference. + + Alternatively, the contents of this file may be used under the terms + of the GNU General Public License version 2 (the "GPL") as distributed + in the kernel source COPYING file, in which case the provisions of + the GPL are applicable instead of the above. If you wish to allow + the use of your version of this file only under the terms of the + GPL and not to allow others to use your version of this file under + the OSL, indicate your decision by deleting the provisions above and + replace them with the notice and other provisions required by the GPL. + If you do not delete the provisions above, a recipient may use your + version of this file under either the OSL or the GPL. + + */ + +#ifndef __LINUX_ATA_H__ +#define __LINUX_ATA_H__ + +#include +#include +#include +#include + +/* + * compile-time options + */ +#undef ATA_FORCE_PIO /* do not configure or use DMA */ +#undef ATA_READ_POISON /* poison membufs before data is read in */ +#undef ATA_DEBUG /* debugging output */ +#undef ATA_VERBOSE_DEBUG /* yet more debugging output */ +#undef ATA_IRQ_TRAP /* define to ack screaming irqs */ +#undef ATA_NDEBUG /* define to disable quick runtime checks */ + + +/* note: prints function name for you */ +#ifdef ATA_DEBUG +#define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) +#ifdef ATA_VERBOSE_DEBUG +#define VPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) +#else +#define VPRINTK(fmt, args...) +#endif /* ATA_VERBOSE_DEBUG */ +#else +#define DPRINTK(fmt, args...) +#define VPRINTK(fmt, args...) +#endif /* ATA_DEBUG */ + +#ifdef ATA_NDEBUG +#define assert(expr) +#else +#define assert(expr) \ + if(!(expr)) { \ + printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#endif + +enum { + /* various global constants */ + ATA_MAX_PORTS = 2, + ATA_MAX_DEVICES = 2, /* per bus/port */ + ATA_DEF_QUEUE = 1, + ATA_MAX_QUEUE = 1, + ATA_MAX_PRD = 256, /* we could make these 256/256 */ + ATA_MAX_SECTORS = 200, /* FIXME */ + ATA_MAX_BUS = 2, + ATA_SECT_SIZE = 512, + ATA_SECT_SIZE_MASK = (ATA_SECT_SIZE - 1), + ATA_SECT_DWORDS = ATA_SECT_SIZE / sizeof(u32), + ATA_ID_WORDS = 256, + ATA_ID_PROD_OFS = 27, + ATA_ID_SERNO_OFS = 10, + ATA_ID_MAJOR_VER = 80, + ATA_ID_PIO_MODES = 64, + ATA_ID_UDMA_MODES = 88, + ATA_ID_PIO4 = (1 << 1), + ATA_DEF_BUSY_WAIT = 10000, + ATA_PCI_CTL_OFS = 2, + ATA_SHORT_PAUSE = (HZ >> 6) + 1, + ATA_SERNO_LEN = 20, + + ATA_SHT_EMULATED = 1, + ATA_SHT_CMD_PER_LUN = 1, + ATA_SHT_THIS_ID = -1, + ATA_SHT_USE_CLUSTERING = 0, /* FIXME: which is best, 0 or 1? */ + + /* DMA-related */ + ATA_PRD_SZ = 8, + ATA_PRD_TBL_SZ = (ATA_MAX_PRD * ATA_PRD_SZ), + ATA_PRD_EOT = (1 << 31), /* end-of-table flag */ + + ATA_DMA_MASK = 0xffffffff, + ATA_DMA_TABLE_OFS = 4, + ATA_DMA_STATUS = 2, + ATA_DMA_CMD = 0, + ATA_DMA_WR = (1 << 3), + ATA_DMA_START = (1 << 0), + ATA_DMA_INTR = (1 << 2), + ATA_DMA_ERR = (1 << 1), + ATA_DMA_ACTIVE = (1 << 0), + + /* bits in ATA command block registers */ + ATA_HOB = (1 << 7), /* LBA48 selector */ + ATA_NIEN = (1 << 1), /* disable-irq flag */ + ATA_LBA = (1 << 6), /* LBA28 selector */ + ATA_DEV1 = (1 << 4), /* Select Device 1 (slave) */ + ATA_BUSY = (1 << 7), /* BSY status bit */ + ATA_DEVICE_OBS = (1 << 7) | (1 << 5), /* obs bits in dev reg */ + ATA_DEVCTL_OBS = (1 << 3), + ATA_DRQ = (1 << 3), + ATA_ERR = (1 << 0), + + /* ATA command block registers */ + ATA_REG_DATA = 0x00, + ATA_REG_ERR = 0x01, + ATA_REG_NSECT = 0x02, + ATA_REG_LBAL = 0x03, + ATA_REG_LBAM = 0x04, + ATA_REG_LBAH = 0x05, + ATA_REG_DEVICE = 0x06, + ATA_REG_STATUS = 0x07, + + ATA_REG_FEATURE = ATA_REG_ERR, /* and their aliases */ + ATA_REG_CMD = ATA_REG_STATUS, + ATA_REG_BYTEL = ATA_REG_LBAM, + ATA_REG_BYTEH = ATA_REG_LBAH, + ATA_REG_DEVSEL = ATA_REG_DEVICE, + ATA_REG_IRQ = ATA_REG_NSECT, + + /* struct ata_device stuff */ + ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */ + ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */ + ATA_DFLAG_MASTER = (1 << 2), /* is device 0? */ + + ATA_DEV_UNKNOWN = 0, /* unknown device */ + ATA_DEV_ATA = 1, /* ATA device */ + ATA_DEV_ATAPI = 2, /* ATAPI device */ + ATA_DEV_NONE = 3, /* no device */ + + /* struct ata_host flags */ + ATA_FLAG_SLAVE_POSS = (1 << 1), /* host supports slave dev */ + /* (doesn't imply presence) */ + ATA_FLAG_PORT_DISABLED = (1 << 2), /* port is disabled, ignore it */ + ATA_FLAG_SATA = (1 << 3), + + /* struct ata_taskfile flags */ + ATA_TFLAG_LBA48 = (1 << 0), + ATA_TFLAG_DATAREG = (1 << 1), + ATA_TFLAG_ISADDR = (1 << 2), /* enable r/w to nsect/lba regs */ + ATA_TFLAG_DEVICE = (1 << 4), /* enable r/w to device reg */ + ATA_TFLAG_PIO = (1 << 5), + + ATA_QCFLAG_WRITE = (1 << 0), /* read==0, write==1 */ + ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ + ATA_QCFLAG_DMA = (1 << 2), /* data delivered via DMA */ + + /* ATA device commands */ + ATA_CMD_EDD = 0x90, /* execute device diagnostic */ + ATA_CMD_ID_ATA = 0xEC, + ATA_CMD_ID_ATAPI = 0xA1, + ATA_CMD_READ = 0xC8, + ATA_CMD_READ_EXT = 0x25, + ATA_CMD_WRITE = 0xCA, + ATA_CMD_WRITE_EXT = 0x35, + ATA_CMD_PIO_READ = 0x20, + ATA_CMD_PIO_READ_EXT = 0x24, + ATA_CMD_PIO_WRITE = 0x30, + ATA_CMD_PIO_WRITE_EXT = 0x34, + ATA_CMD_SET_FEATURES = 0xEF, + + /* various lengths of time */ + ATA_TMOUT_BOOT = 30, /* seconds */ + ATA_TMOUT_EDD = 5 * HZ, /* just a guess */ + ATA_TMOUT_PIO = 30 * HZ, + + /* ATA bus states */ + BUS_UNKNOWN = 0, + BUS_DMA = 1, + BUS_IDLE = 2, + BUS_NOINTR = 3, + BUS_NODATA = 4, + BUS_TIMER = 5, + BUS_PIO = 6, + BUS_EDD = 7, + BUS_IDENTIFY = 8, + + /* thread states */ + THR_UNKNOWN = 0, + THR_CHECKPORT = 1, + THR_EDD = 2, + THR_AWAIT_DEATH = 3, + THR_IDENTIFY = 4, + THR_CONFIG_PIO = 5, + THR_CONFIG_DMA = 6, + THR_PROBE_FAILED = 7, + THR_IDLE = 8, + THR_PROBE_SUCCESS = 9, + THR_PROBE_START = 10, + THR_CONFIG_FORCE_PIO = 11, + THR_PIO_POLL = 12, + THR_PIO_TMOUT = 13, + THR_PIO = 14, + THR_PIO_LAST = 15, + THR_PIO_LAST_POLL = 16, + THR_PIO_ERR = 17, + + /* SATA port states */ + PORT_UNKNOWN = 0, + PORT_ENABLED = 1, + PORT_DISABLED = 2, + + /* SETFEATURES stuff */ + SETFEATURES_XFER = 0x03, + XFER_UDMA_7 = 0x47, + XFER_UDMA_6 = 0x46, + XFER_UDMA_5 = 0x45, + XFER_UDMA_4 = 0x44, + XFER_UDMA_3 = 0x43, + XFER_UDMA_2 = 0x42, + XFER_UDMA_1 = 0x41, + XFER_UDMA_0 = 0x40, + XFER_PIO_4 = 0x0C, + XFER_PIO_3 = 0x0B, +}; + +struct ata_prd { + u32 addr; + u32 flags_len; +} __attribute__((packed)); + +struct ata_ioports { + unsigned long cmd_addr; + unsigned long ctl_addr; + unsigned long bmdma_addr; +}; + +struct ata_probe_ent { + struct list_head node; + struct pci_dev *pdev; + struct ata_host_ops *host_ops; + Scsi_Host_Template *sht; + struct ata_ioports port[ATA_MAX_PORTS]; + unsigned int n_ports; + unsigned int pio_mask; + unsigned int udma_mask; + unsigned int legacy_mode; + unsigned long irq; + unsigned int irq_flags; + unsigned long host_flags; +}; + +struct ata_host_set { + struct list_head driver_list; + spinlock_t lock; + struct pci_dev *pdev; + unsigned long irq; + unsigned int n_hosts; + struct ata_host * hosts[0]; +}; + +struct ata_taskfile { + unsigned long flags; /* ATA_TFLAG_xxx */ + + u8 data; /* command registers */ + u8 feature; + u8 nsect; + u8 lbal; + u8 lbam; + u8 lbah; + u8 device; + + u8 command; /* IO operation */ + + u8 hob_feature; /* additional data */ + u8 hob_nsect; /* to support LBA48 */ + u8 hob_lbal; + u8 hob_lbam; + u8 hob_lbah; + u8 hob_data; + + u8 ctl; /* control reg/altstatus */ +}; + +struct ata_queued_cmd { + unsigned long flags; /* ATA_QCFLAG_xxx */ + unsigned int n_elem; + unsigned int nsect; + unsigned int cursect; + unsigned int cursg; + unsigned int cursg_ofs; + Scsi_Cmnd *scsicmd; + void (*done)(Scsi_Cmnd *); + struct ata_taskfile tf; + struct scatterlist sgent; +}; + +struct ata_host_stats { + unsigned long unhandled_irq; + unsigned long idle_irq; + unsigned long rw_reqbuf; +}; + +struct ata_device { + u64 n_sectors; /* size of device, if ATA */ + unsigned long flags; /* ATA_DFLAG_xxx */ + unsigned int class; /* ATA_DEV_xxx */ + unsigned int devno; /* 0 or 1 */ + u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ + unsigned int pio_mode; + unsigned int udma_mode; + + unsigned char vendor[8]; /* space-padded, not ASCIIZ */ + unsigned char product[16]; +}; + +struct ata_host_ops; +struct ata_host { + struct Scsi_Host *host; /* our co-allocated scsi host */ + struct ata_host_ops *ops; + unsigned long flags; /* ATA_FLAG_xxx */ + unsigned int id; /* unique id req'd by scsi midlyr */ + unsigned int port_no; /* unique port #; from zero */ + + struct ata_prd *prd; /* our SG list */ + dma_addr_t prd_dma; /* and its DMA mapping */ + + struct ata_ioports ioaddr; /* ATA cmd/ctl/dma register blocks */ + + u8 ctl; /* cache of ATA control register */ + u8 dmactl; /* cache of DMA control register */ + u8 devsel; /* cache of Device Select reg */ + unsigned int bus_state; + unsigned int port_state; + unsigned int pio_mask; + unsigned int udma_mask; + + struct ata_device device[ATA_MAX_DEVICES]; + struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; + struct ata_host_stats stats; + struct ata_host_set *host_set; + + struct semaphore sem; + struct semaphore probe_sem; + + unsigned int thr_state; + int time_to_die; + pid_t thr_pid; + struct completion thr_exited; + struct semaphore thr_sem; + struct timer_list thr_timer; + unsigned long thr_timeout; +}; + +struct ata_host_ops { + void (*port_probe) (struct ata_host *); + void (*port_disable) (struct ata_host *); + + void (*set_piomode) (struct ata_host *, struct ata_device *, + unsigned int); + void (*set_udmamode) (struct ata_host *, struct ata_device *, + unsigned int); +}; + +struct ata_board { + Scsi_Host_Template *sht; + unsigned long host_flags; + unsigned long pio_mask; + unsigned long udma_mask; +}; + +#define ata_id_is_ata(dev) (((dev)->id[0] & (1 << 15)) == 0) +#define ata_id_has_lba48(dev) ((dev)->id[83] & (1 << 10)) +#define ata_id_has_lba(dev) ((dev)->id[49] & (1 << 8)) +#define ata_id_has_dma(dev) ((dev)->id[49] & (1 << 9)) +#define ata_id_u32(dev,n) \ + (((u32) (dev)->id[(n) + 1] << 16) | ((u32) (dev)->id[(n)])) +#define ata_id_u64(dev,n) \ + ( ((u64) dev->id[(n) + 3] << 48) | \ + ((u64) dev->id[(n) + 2] << 32) | \ + ((u64) dev->id[(n) + 1] << 16) | \ + ((u64) dev->id[(n) + 0]) ) + +extern void ata_port_probe(struct ata_host *); +extern void ata_port_disable(struct ata_host *); +extern int ata_pci_init_one (struct pci_dev *, struct ata_board *, + struct ata_host_ops *); +extern void ata_pci_remove_one (struct pci_dev *pdev); +extern int ata_scsi_detect(Scsi_Host_Template *sht); +extern int ata_scsi_release(struct Scsi_Host *host); +extern int ata_scsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); +extern int ata_scsi_error(struct Scsi_Host *host); + +static inline unsigned long msecs_to_jiffies(unsigned long msecs) +{ + return ((HZ * msecs + 999) / 1000); +} + +static inline unsigned int ata_dev_present(struct ata_device *dev) +{ + return ((dev->class == ATA_DEV_ATA) || + (dev->class == ATA_DEV_ATAPI)); +} + +static inline u8 ata_chk_status(struct ata_ioports *ioaddr) +{ + return inb(ioaddr->cmd_addr + ATA_REG_STATUS); +} + +static inline u8 ata_busy_wait(struct ata_ioports *ioaddrs, unsigned int bits, + unsigned int max) +{ + u8 status; + + do { + udelay(10); + status = ata_chk_status(ioaddrs); + max--; + } while ((status & bits) && (max > 0)); + + return status; +} + +static inline u8 ata_wait_idle(struct ata_ioports *ioaddrs) +{ + u8 status = ata_busy_wait(ioaddrs, ATA_BUSY | ATA_DRQ, 1000); + + if (status & (ATA_BUSY | ATA_DRQ)) { + unsigned long l = ioaddrs->cmd_addr + ATA_REG_STATUS; + printk(KERN_WARNING + "ATA: abnormal status 0x%X on port 0x%lX\n", + status, l); + } + + return status; +} + +static inline void ata_tf_init(struct ata_host *ah, struct ata_taskfile *tf) +{ + memset(tf, 0, sizeof(*tf)); + + tf->ctl = ah->ctl; + tf->device = ah->devsel; +} + +static inline void ata_irq_on(struct ata_host *ah) +{ + struct ata_ioports *ioaddr = &ah->ioaddr; + + ah->ctl &= ~ATA_NIEN; + outb(ah->ctl, ioaddr->ctl_addr); + + ata_wait_idle(ioaddr); +} + +static inline u8 ata_irq_ack(struct ata_host *ah, unsigned int chk_drq) +{ + unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; + u8 host_stat, status; + + status = ata_busy_wait(&ah->ioaddr, bits, 1000); + if (status & bits) + DPRINTK("abnormal status 0x%X\n", status); + + /* get controller status; clear intr, err bits */ + host_stat = inb(ah->ioaddr.bmdma_addr + ATA_DMA_STATUS); + outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, + ah->ioaddr.bmdma_addr + ATA_DMA_STATUS); + + VPRINTK("irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n", + host_stat, inb(ah->ioaddr.bmdma_addr + ATA_DMA_STATUS), + status); + + return status; +} + +#endif /* __LINUX_ATA_H__ */ diff -Nru a/include/linux/scsi_defs.h b/include/linux/scsi_defs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/scsi_defs.h Sat May 24 14:40:31 2003 @@ -0,0 +1,686 @@ +/* + * scsi.h Copyright (C) 1992 Drew Eckhardt + * Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale + * generic SCSI package header file by + * Initial versions: Drew Eckhardt + * Subsequent revisions: Eric Youngdale + * + * + * + * Modified by Eric Youngdale eric@andante.org to + * add scatter-gather, multiple outstanding request, and other + * enhancements. + */ + +#ifndef _SCSI_H +#define _SCSI_H + +#include /* for CONFIG_SCSI_LOGGING */ +#include + +/* + * These are the values that the SCpnt->sc_data_direction and + * SRpnt->sr_data_direction can take. These need to be set + * The SCSI_DATA_UNKNOWN value is essentially the default. + * In the event that the command creator didn't bother to + * set a value, you will see SCSI_DATA_UNKNOWN. + */ +#define SCSI_DATA_UNKNOWN 0 +#define SCSI_DATA_WRITE 1 +#define SCSI_DATA_READ 2 +#define SCSI_DATA_NONE 3 + +#ifdef CONFIG_PCI +#include +#if ((SCSI_DATA_UNKNOWN == PCI_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == PCI_DMA_TODEVICE) && (SCSI_DATA_READ == PCI_DMA_FROMDEVICE) && (SCSI_DATA_NONE == PCI_DMA_NONE)) +#define scsi_to_pci_dma_dir(scsi_dir) ((int)(scsi_dir)) +#else +extern __inline__ int scsi_to_pci_dma_dir(unsigned char scsi_dir) +{ + if (scsi_dir == SCSI_DATA_UNKNOWN) + return PCI_DMA_BIDIRECTIONAL; + if (scsi_dir == SCSI_DATA_WRITE) + return PCI_DMA_TODEVICE; + if (scsi_dir == SCSI_DATA_READ) + return PCI_DMA_FROMDEVICE; + return PCI_DMA_NONE; +} +#endif +#endif + +#if defined(CONFIG_SBUS) && !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) +#include +#if ((SCSI_DATA_UNKNOWN == SBUS_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == SBUS_DMA_TODEVICE) && (SCSI_DATA_READ == SBUS_DMA_FROMDEVICE) && (SCSI_DATA_NONE == SBUS_DMA_NONE)) +#define scsi_to_sbus_dma_dir(scsi_dir) ((int)(scsi_dir)) +#else +extern __inline__ int scsi_to_sbus_dma_dir(unsigned char scsi_dir) +{ + if (scsi_dir == SCSI_DATA_UNKNOWN) + return SBUS_DMA_BIDIRECTIONAL; + if (scsi_dir == SCSI_DATA_WRITE) + return SBUS_DMA_TODEVICE; + if (scsi_dir == SCSI_DATA_READ) + return SBUS_DMA_FROMDEVICE; + return SBUS_DMA_NONE; +} +#endif +#endif + +/* + * Some defs, in case these are not defined elsewhere. + */ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define MAX_SCSI_DEVICE_CODE 14 +extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; + +#ifdef DEBUG +#define SCSI_TIMEOUT (5*HZ) +#else +#define SCSI_TIMEOUT (2*HZ) +#endif + +/* + * Use these to separate status msg and our bytes + * + * These are set by: + * + * status byte = set from target device + * msg_byte = return status from host adapter itself. + * host_byte = set by low-level driver to indicate status. + * driver_byte = set by mid-level. + */ +#define status_byte(result) (((result) >> 1) & 0x1f) +#define msg_byte(result) (((result) >> 8) & 0xff) +#define host_byte(result) (((result) >> 16) & 0xff) +#define driver_byte(result) (((result) >> 24) & 0xff) +#define suggestion(result) (driver_byte(result) & SUGGEST_MASK) + +#define sense_class(sense) (((sense) >> 4) & 0x7) +#define sense_error(sense) ((sense) & 0xf) +#define sense_valid(sense) ((sense) & 0x80); + +#define NEEDS_RETRY 0x2001 +#define SUCCESS 0x2002 +#define FAILED 0x2003 +#define QUEUED 0x2004 +#define SOFT_ERROR 0x2005 +#define ADD_TO_MLQUEUE 0x2006 + +/* + * These are the values that scsi_cmd->state can take. + */ +#define SCSI_STATE_TIMEOUT 0x1000 +#define SCSI_STATE_FINISHED 0x1001 +#define SCSI_STATE_FAILED 0x1002 +#define SCSI_STATE_QUEUED 0x1003 +#define SCSI_STATE_UNUSED 0x1006 +#define SCSI_STATE_DISCONNECTING 0x1008 +#define SCSI_STATE_INITIALIZING 0x1009 +#define SCSI_STATE_BHQUEUE 0x100a +#define SCSI_STATE_MLQUEUE 0x100b + +#define IDENTIFY_BASE 0x80 +#define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\ + ((can_disconnect) ? 0x40 : 0) |\ + ((lun) & 0x07)) + +/* host byte codes */ +#define DID_OK 0x00 /* NO error */ +#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ +#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ +#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ +#define DID_BAD_TARGET 0x04 /* BAD target. */ +#define DID_ABORT 0x05 /* Told to abort for some other reason */ +#define DID_PARITY 0x06 /* Parity error */ +#define DID_ERROR 0x07 /* Internal error */ +#define DID_RESET 0x08 /* Reset by somebody. */ +#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ +#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ +#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ +#define DRIVER_OK 0x00 /* Driver status */ + +/* + * These indicate the error that occurred, and what is available. + */ + +#define DRIVER_BUSY 0x01 +#define DRIVER_SOFT 0x02 +#define DRIVER_MEDIA 0x03 +#define DRIVER_ERROR 0x04 + +#define DRIVER_INVALID 0x05 +#define DRIVER_TIMEOUT 0x06 +#define DRIVER_HARD 0x07 +#define DRIVER_SENSE 0x08 + +#define SUGGEST_RETRY 0x10 +#define SUGGEST_ABORT 0x20 +#define SUGGEST_REMAP 0x30 +#define SUGGEST_DIE 0x40 +#define SUGGEST_SENSE 0x80 +#define SUGGEST_IS_OK 0xff + +#define DRIVER_MASK 0x0f +#define SUGGEST_MASK 0xf0 + +#define MAX_COMMAND_SIZE 16 +#define SCSI_SENSE_BUFFERSIZE 64 + +/* + * SCSI command sets + */ + +#define SCSI_UNKNOWN 0 +#define SCSI_1 1 +#define SCSI_1_CCS 2 +#define SCSI_2 3 +#define SCSI_3 4 + +/* + * Every SCSI command starts with a one byte OP-code. + * The next byte's high three bits are the LUN of the + * device. Any multi-byte quantities are stored high byte + * first, and may have a 5 bit MSB in the same byte + * as the LUN. + */ + +/* + * As the scsi do command functions are intelligent, and may need to + * redo a command, we need to keep track of the last command + * executed on each one. + */ + +#define WAS_RESET 0x01 +#define WAS_TIMEDOUT 0x02 +#define WAS_SENSE 0x04 +#define IS_RESETTING 0x08 +#define IS_ABORTING 0x10 +#define ASKED_FOR_SENSE 0x20 +#define SYNC_RESET 0x40 + +/* + * This specifies "machine infinity" for host templates which don't + * limit the transfer size. Note this limit represents an absolute + * maximum, and may be over the transfer limits allowed for individual + * devices (e.g. 256 for SCSI-1) + */ +#define SCSI_DEFAULT_MAX_SECTORS 1024 + +/* + * This is the crap from the old error handling code. We have it in a special + * place so that we can more easily delete it later on. + */ +#include + +/* + * Forward-declaration of structs for prototypes. + */ +struct Scsi_Host; +struct scsi_target; +struct scatterlist; + +/* + * Add some typedefs so that we can prototyope a bunch of the functions. + */ +typedef struct scsi_device Scsi_Device; +typedef struct scsi_cmnd Scsi_Cmnd; +typedef struct scsi_request Scsi_Request; + +/* + * These are the error handling functions defined in scsi_error.c + */ +extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout, + void (*complete) (Scsi_Cmnd *)); +extern int scsi_delete_timer(Scsi_Cmnd * SCset); +extern int scsi_block_when_processing_errors(Scsi_Device *); +extern void scsi_sleep(int); + +/* + * Prototypes for functions in scsicam.c + */ +extern int scsi_partsize(unsigned char *buf, unsigned long capacity, + unsigned int *cyls, unsigned int *hds, + unsigned int *secs); + +/* + * Prototypes for functions in scsi_lib.c + */ +extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, + int block_sectors); + +/* + * Prototypes for functions in scsi.c + */ +extern struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int flags); +extern void scsi_put_command(struct scsi_cmnd *cmd); +extern void scsi_adjust_queue_depth(Scsi_Device *, int, int); +extern int scsi_track_queue_full(Scsi_Device *, int); +extern int scsi_device_get(struct scsi_device *); +extern void scsi_device_put(struct scsi_device *); +extern void scsi_set_device_offline(struct scsi_device *); + +/* + * Newer request-based interfaces. + */ +extern Scsi_Request *scsi_allocate_request(Scsi_Device *); +extern void scsi_release_request(Scsi_Request *); +extern void scsi_wait_req(Scsi_Request *, const void *cmnd, + void *buffer, unsigned bufflen, + int timeout, int retries); +extern void scsi_do_req(Scsi_Request *, const void *cmnd, + void *buffer, unsigned bufflen, + void (*done) (struct scsi_cmnd *), + int timeout, int retries); + +/* + * Prototypes for functions in scsi_scan.c + */ +extern struct scsi_device *scsi_add_device(struct Scsi_Host *, + uint, uint, uint); +extern int scsi_remove_device(struct scsi_device *); +extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *); + +/* + * Prototypes for functions in constants.c + * Some of these used to live in constants.h + */ +extern void print_Scsi_Cmnd (Scsi_Cmnd *); +extern void print_command(unsigned char *); +extern void print_sense(const char *, Scsi_Cmnd *); +extern void print_req_sense(const char *, Scsi_Request *); +extern void print_driverbyte(int scsiresult); +extern void print_hostbyte(int scsiresult); +extern void print_status(unsigned char status); +extern int print_msg(const unsigned char *); +extern const char *scsi_sense_key_string(unsigned char); +extern const char *scsi_extd_sense_format(unsigned char, unsigned char); + + +/* + * The scsi_device struct contains what we know about each given scsi + * device. + * + * FIXME(eric) - One of the great regrets that I have is that I failed to + * define these structure elements as something like sdev_foo instead of foo. + * This would make it so much easier to grep through sources and so forth. + * I propose that all new elements that get added to these structures follow + * this convention. As time goes on and as people have the stomach for it, + * it should be possible to go back and retrofit at least some of the elements + * here with with the prefix. + */ + +struct scsi_device { + /* + * This information is private to the scsi mid-layer. + */ + struct list_head siblings; /* list of all devices on this host */ + struct list_head same_target_siblings; /* just the devices sharing same target id */ + struct Scsi_Host *host; + request_queue_t *request_queue; + volatile unsigned short device_busy; /* commands actually active on low-level */ + spinlock_t sdev_lock; /* also the request queue_lock */ + spinlock_t list_lock; + struct list_head cmd_list; /* queue of in use SCSI Command structures */ + struct list_head starved_entry; + Scsi_Cmnd *current_cmnd; /* currently active command */ + unsigned short queue_depth; /* How deep of a queue we want */ + unsigned short last_queue_full_depth; /* These two are used by */ + unsigned short last_queue_full_count; /* scsi_track_queue_full() */ + unsigned long last_queue_full_time;/* don't let QUEUE_FULLs on the same + jiffie count on our counter, they + could all be from the same event. */ + + unsigned int id, lun, channel; + + unsigned int manufacturer; /* Manufacturer of device, for using + * vendor-specific cmd's */ + unsigned sector_size; /* size in bytes */ + + int access_count; /* Count of open channels/mounts */ + + void *hostdata; /* available to low-level driver */ + char devfs_name[256]; /* devfs junk */ + char type; + char scsi_level; + unsigned char inquiry_len; /* valid bytes in 'inquiry' */ + unsigned char * inquiry; /* INQUIRY response data */ + char * vendor; /* [back_compat] point into 'inquiry' ... */ + char * model; /* ... after scan; point to static string */ + char * rev; /* ... "nullnullnullnull" before scan */ + unsigned char current_tag; /* current tag */ +// unsigned char sync_min_period; /* Not less than this period */ +// unsigned char sync_max_offset; /* Not greater than this offset */ + struct scsi_target *sdev_target; /* used only for single_lun */ + + unsigned online:1; + unsigned writeable:1; + unsigned removable:1; + unsigned random:1; + unsigned changed:1; /* Data invalid due to media change */ + unsigned busy:1; /* Used to prevent races */ + unsigned lockable:1; /* Able to prevent media removal */ + unsigned locked:1; /* Media removal disabled */ + unsigned borken:1; /* Tell the Seagate driver to be + * painfully slow on this device */ + unsigned disconnect:1; /* can disconnect */ + unsigned soft_reset:1; /* Uses soft reset option */ + unsigned sdtr:1; /* Device supports SDTR messages */ + unsigned wdtr:1; /* Device supports WDTR messages */ + unsigned ppr:1; /* Device supports PPR messages */ + unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */ + unsigned tagged_queue:1;/* This is going away!!!! Look at simple_tags + instead!!! Please fix your driver now!! */ + unsigned simple_tags:1; /* simple queue tag messages are enabled */ + unsigned ordered_tags:1;/* ordered queue tag messages are enabled */ + unsigned single_lun:1; /* Indicates we should only allow I/O to + * one of the luns for the device at a + * time. */ + unsigned was_reset:1; /* There was a bus reset on the bus for + * this device */ + unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN + * because we did a bus reset. */ + unsigned ten:1; /* support ten byte read / write */ + unsigned remap:1; /* support remapping */ +// unsigned sync:1; /* Sync transfer state, managed by host */ +// unsigned wide:1; /* WIDE transfer state, managed by host */ + + unsigned int device_blocked; /* Device returned QUEUE_FULL. */ + + unsigned int max_device_blocked; /* what device_blocked counts down from */ + /* default value if the device doesn't override */ + #define SCSI_DEFAULT_DEVICE_BLOCKED 3 + + struct device sdev_driverfs_dev; +}; +#define to_scsi_device(d) \ + container_of(d, struct scsi_device, sdev_driverfs_dev) + + +/* + * The Scsi_Cmnd structure is used by scsi.c internally, and for communication + * with low level drivers that support multiple outstanding commands. + */ +typedef struct scsi_pointer { + char *ptr; /* data pointer */ + int this_residual; /* left in this buffer */ + struct scatterlist *buffer; /* which buffer */ + int buffers_residual; /* how many buffers left */ + + dma_addr_t dma_handle; + + volatile int Status; + volatile int Message; + volatile int have_data_in; + volatile int sent_command; + volatile int phase; +} Scsi_Pointer; + +/* + * This is essentially a slimmed down version of Scsi_Cmnd. The point of + * having this is that requests that are injected into the queue as result + * of things like ioctls and character devices shouldn't be using a + * Scsi_Cmnd until such a time that the command is actually at the head + * of the queue and being sent to the driver. + */ +struct scsi_request { + int sr_magic; + int sr_result; /* Status code from lower level driver */ + unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE + * when CHECK CONDITION is + * received on original command + * (auto-sense) */ + + struct Scsi_Host *sr_host; + Scsi_Device *sr_device; + Scsi_Cmnd *sr_command; + struct request *sr_request; /* A copy of the command we are + working on */ + unsigned sr_bufflen; /* Size of data buffer */ + void *sr_buffer; /* Data buffer */ + int sr_allowed; + unsigned char sr_data_direction; + unsigned char sr_cmd_len; + unsigned char sr_cmnd[MAX_COMMAND_SIZE]; + void (*sr_done) (struct scsi_cmnd *); /* Mid-level done function */ + int sr_timeout_per_command; + unsigned short sr_use_sg; /* Number of pieces of scatter-gather */ + unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */ + unsigned sr_underflow; /* Return error if less than + this amount is transferred */ + void * upper_private_data; /* reserved for owner (usually upper + level driver) of this request */ +}; + +/* + * FIXME(eric) - one of the great regrets that I have is that I failed to define + * these structure elements as something like sc_foo instead of foo. This would + * make it so much easier to grep through sources and so forth. I propose that + * all new elements that get added to these structures follow this convention. + * As time goes on and as people have the stomach for it, it should be possible to + * go back and retrofit at least some of the elements here with with the prefix. + */ +struct scsi_cmnd { + int sc_magic; + + struct scsi_device *device; + unsigned short state; + unsigned short owner; + Scsi_Request *sc_request; + + struct list_head list; /* scsi_cmnd participates in queue lists */ + + struct list_head eh_entry; /* entry for the host eh_cmd_q */ + int eh_state; /* Used for state tracking in error handlr */ + int eh_eflags; /* Used by error handlr */ + void (*done) (struct scsi_cmnd *); /* Mid-level done function */ + /* + A SCSI Command is assigned a nonzero serial_number when internal_cmnd + passes it to the driver's queue command function. The serial_number + is cleared when scsi_done is entered indicating that the command has + been completed. If a timeout occurs, the serial number at the moment + of timeout is copied into serial_number_at_timeout. By subsequently + comparing the serial_number and serial_number_at_timeout fields + during abort or reset processing, we can detect whether the command + has already completed. This also detects cases where the command has + completed and the SCSI Command structure has already being reused + for another command, so that we can avoid incorrectly aborting or + resetting the new command. + */ + + unsigned long serial_number; + unsigned long serial_number_at_timeout; + + int retries; + int allowed; + int timeout_per_command; + int timeout_total; + int timeout; + + /* + * We handle the timeout differently if it happens when a reset, + * abort, etc are in process. + */ + unsigned volatile char internal_timeout; + + unsigned char cmd_len; + unsigned char old_cmd_len; + unsigned char sc_data_direction; + unsigned char sc_old_data_direction; + + /* These elements define the operation we are about to perform */ + unsigned char cmnd[MAX_COMMAND_SIZE]; + unsigned request_bufflen; /* Actual request size */ + + struct timer_list eh_timeout; /* Used to time out the command. */ + void *request_buffer; /* Actual requested buffer */ + + /* These elements define the operation we ultimately want to perform */ + unsigned char data_cmnd[MAX_COMMAND_SIZE]; + unsigned short old_use_sg; /* We save use_sg here when requesting + * sense info */ + unsigned short use_sg; /* Number of pieces of scatter-gather */ + unsigned short sglist_len; /* size of malloc'd scatter-gather list */ + unsigned short abort_reason; /* If the mid-level code requests an + * abort, this is the reason. */ + unsigned bufflen; /* Size of data buffer */ + void *buffer; /* Data buffer */ + + unsigned underflow; /* Return error if less than + this amount is transferred */ + unsigned old_underflow; /* save underflow here when reusing the + * command for error handling */ + + unsigned transfersize; /* How much we are guaranteed to + transfer with each SCSI transfer + (ie, between disconnect / + reconnects. Probably == sector + size */ + + int resid; /* Number of bytes requested to be + transferred less actual number + transferred (0 if not supported) */ + + struct request *request; /* The command we are + working on */ + + unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE + * when CHECK CONDITION is + * received on original command + * (auto-sense) */ + + unsigned flags; + + /* Low-level done function - can be used by low-level driver to point + * to completion function. Not used by mid/upper level code. */ + void (*scsi_done) (struct scsi_cmnd *); + + /* + * The following fields can be written to by the host specific code. + * Everything else should be left alone. + */ + + Scsi_Pointer SCp; /* Scratchpad used by some host adapters */ + + unsigned char *host_scribble; /* The host adapter is allowed to + * call scsi_malloc and get some memory + * and hang it here. The host adapter + * is also expected to call scsi_free + * to release this memory. (The memory + * obtained by scsi_malloc is guaranteed + * to be at an address < 16Mb). */ + + int result; /* Status code from lower level driver */ + + unsigned char tag; /* SCSI-II queued command tag */ + unsigned long pid; /* Process ID, starts at 0 */ +}; + +/* + * Definitions and prototypes used for scsi mid-level queue. + */ +#define SCSI_MLQUEUE_HOST_BUSY 0x1055 +#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 +#define SCSI_MLQUEUE_EH_RETRY 0x1057 + +/* + * Reset request from external source + */ +#define SCSI_TRY_RESET_DEVICE 1 +#define SCSI_TRY_RESET_BUS 2 +#define SCSI_TRY_RESET_HOST 3 + +extern int scsi_reset_provider(Scsi_Device *, int); + +#define MSG_SIMPLE_TAG 0x20 +#define MSG_HEAD_TAG 0x21 +#define MSG_ORDERED_TAG 0x22 + +#define SCSI_NO_TAG (-1) /* identify no tag in use */ + +/** + * scsi_activate_tcq - turn on tag command queueing + * @SDpnt: device to turn on TCQ for + * @depth: queue depth + * + * Notes: + * Eventually, I hope depth would be the maximum depth + * the device could cope with and the real queue depth + * would be adjustable from 0 to depth. + **/ +static inline void scsi_activate_tcq(Scsi_Device *SDpnt, int depth) { + if(SDpnt->tagged_supported) { + if(!blk_queue_tagged(SDpnt->request_queue)) + blk_queue_init_tags(SDpnt->request_queue, depth); + scsi_adjust_queue_depth(SDpnt, MSG_ORDERED_TAG, depth); + } +} + +/** + * scsi_deactivate_tcq - turn off tag command queueing + * @SDpnt: device to turn off TCQ for + **/ +static inline void scsi_deactivate_tcq(Scsi_Device *SDpnt, int depth) { + if(blk_queue_tagged(SDpnt->request_queue)) + blk_queue_free_tags(SDpnt->request_queue); + scsi_adjust_queue_depth(SDpnt, 0, depth); +} + +/** + * scsi_populate_tag_msg - place a tag message in a buffer + * @SCpnt: pointer to the Scsi_Cmnd for the tag + * @msg: pointer to the area to place the tag + * + * Notes: + * designed to create the correct type of tag message for the + * particular request. Returns the size of the tag message. + * May return 0 if TCQ is disabled for this device. + **/ +static inline int scsi_populate_tag_msg(Scsi_Cmnd *SCpnt, char *msg) { + struct request *req = SCpnt->request; + + if(!blk_rq_tagged(req)) + return 0; + + if (req->flags & REQ_HARDBARRIER) + *msg++ = MSG_ORDERED_TAG; + else + *msg++ = MSG_SIMPLE_TAG; + + *msg++ = SCpnt->request->tag; + + return 2; +} + +/** + * scsi_find_tag - find a tagged command by device + * @SDpnt: pointer to the ScSI device + * @tag: the tag number + * + * Notes: + * Only works with tags allocated by the generic blk layer. + **/ +static inline Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) { + + struct request *req; + + if(tag == SCSI_NO_TAG) + /* single command, look in space */ + return SDpnt->current_cmnd; + + req = blk_queue_find_tag(SDpnt->request_queue, tag); + + if(req == NULL) + return NULL; + + return (Scsi_Cmnd *)req->special; +} + +int scsi_set_medium_removal(Scsi_Device *dev, char state); + +#endif /* _SCSI_H */ diff -Nru a/include/linux/scsi_hosts.h b/include/linux/scsi_hosts.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/scsi_hosts.h Sat May 24 14:40:31 2003 @@ -0,0 +1,594 @@ +/* + * hosts.h Copyright (C) 1992 Drew Eckhardt + * Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale + * + * mid to low-level SCSI driver interface header + * Initial versions: Drew Eckhardt + * Subsequent revisions: Eric Youngdale + * + * + * + * Modified by Eric Youngdale eric@andante.org to + * add scatter-gather, multiple outstanding request, and other + * enhancements. + * + * Further modified by Eric Youngdale to support multiple host adapters + * of the same type. + * + * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli + * + * Restructured scsi_host lists and associated functions. + * September 04, 2002 Mike Anderson (andmike@us.ibm.com) + */ + +#ifndef _HOSTS_H +#define _HOSTS_H + +#include +#include +#include + +struct scsi_host_cmd_pool; + + +/* It is senseless to set SG_ALL any higher than this - the performance + * does not get any better, and it wastes memory + */ +#define SG_NONE 0 +#define SG_ALL 0xff + +#define DISABLE_CLUSTERING 0 +#define ENABLE_CLUSTERING 1 + +/* The various choices mean: + * NONE: Self evident. Host adapter is not capable of scatter-gather. + * ALL: Means that the host adapter module can do scatter-gather, + * and that there is no limit to the size of the table to which + * we scatter/gather data. + * Anything else: Indicates the maximum number of chains that can be + * used in one scatter-gather request. + */ + +/* + * The Scsi_Host_Template type has all that is needed to interface with a SCSI + * host in a device independent matter. There is one entry for each different + * type of host adapter that is supported on the system. + */ + +typedef struct SHT +{ + /* Used with loadable modules so that we know when it is safe to unload */ + struct module * module; + + /* The pointer to the /proc/scsi directory entry */ + struct proc_dir_entry *proc_dir; + + /* proc-fs info function. + * Can be used to export driver statistics and other infos to the world + * outside the kernel ie. userspace and it also provides an interface + * to feed the driver with information. Check eata_dma_proc.c for reference + */ + int (*proc_info)(char *, char **, off_t, int, int, int); + + /* + * The name pointer is a pointer to the name of the SCSI + * device detected. + */ + const char *name; + + /* + * The detect function shall return non zero on detection, + * indicating the number of host adapters of this particular + * type were found. It should also + * initialize all data necessary for this particular + * SCSI driver. It is passed the host number, so this host + * knows where the first entry is in the scsi_hosts[] array. + * + * Note that the detect routine MUST not call any of the mid level + * functions to queue commands because things are not guaranteed + * to be set up yet. The detect routine can send commands to + * the host adapter as long as the program control will not be + * passed to scsi.c in the processing of the command. Note + * especially that scsi_malloc/scsi_free must not be called. + */ + int (* detect)(struct SHT *); + + /* Used with loadable modules to unload the host structures. Note: + * there is a default action built into the modules code which may + * be sufficient for most host adapters. Thus you may not have to supply + * this at all. + */ + int (*release)(struct Scsi_Host *); + + /* + * The info function will return whatever useful + * information the developer sees fit. If not provided, then + * the name field will be used instead. + */ + const char *(* info)(struct Scsi_Host *); + + /* + * ioctl interface + */ + int (*ioctl)(Scsi_Device *dev, int cmd, void *arg); + + /* + * The command function takes a target, a command (this is a SCSI + * command formatted as per the SCSI spec, nothing strange), a + * data buffer pointer, and data buffer length pointer. The return + * is a status int, bit fielded as follows : + * Byte What + * 0 SCSI status code + * 1 SCSI 1 byte message + * 2 host error return. + * 3 mid level error return + */ + int (* command)(Scsi_Cmnd *); + + /* + * The QueueCommand function works in a similar manner + * to the command function. It takes an additional parameter, + * void (* done)(int host, int code) which is passed the host + * # and exit result when the command is complete. + * Host number is the POSITION IN THE hosts array of THIS + * host adapter. + * + * if queuecommand returns 0, then the HBA has accepted the + * command. The done() function must be called on the command + * when the driver has finished with it. (you may call done on the + * command before queuecommand returns, but in this case you + * *must* return 0 from queuecommand). + * + * queuecommand may also reject the command, in which case it may + * not touch the command and must not call done() for it. + * + * There are two possible rejection returns: + * + * SCSI_MLQUEUE_DEVICE_BUSY: Block this device temporarily, but + * allow commands to other devices serviced by this host. + * + * SCSI_MLQUEUE_HOST_BUSY: Block all devices served by this + * host temporarily. + * + * for compatibility, any other non-zero return is treated the + * same as SCSI_MLQUEUE_HOST_BUSY. + * + * NOTE: "temporarily" means either until the next command for + * this device/host completes, or a period of time determined by + * I/O pressure in the system if there are no other outstanding + * commands. + * */ + int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); + + /* + * This is an error handling strategy routine. You don't need to + * define one of these if you don't want to - there is a default + * routine that is present that should work in most cases. For those + * driver authors that have the inclination and ability to write their + * own strategy routine, this is where it is specified. Note - the + * strategy routine is *ALWAYS* run in the context of the kernel eh + * thread. Thus you are guaranteed to *NOT* be in an interrupt handler + * when you execute this, and you are also guaranteed to *NOT* have any + * other commands being queued while you are in the strategy routine. + * When you return from this function, operations return to normal. + * + * See scsi_error.c scsi_unjam_host for additional comments about what + * this function should and should not be attempting to do. + */ + int (*eh_strategy_handler)(struct Scsi_Host *); + int (*eh_abort_handler)(Scsi_Cmnd *); + int (*eh_device_reset_handler)(Scsi_Cmnd *); + int (*eh_bus_reset_handler)(Scsi_Cmnd *); + int (*eh_host_reset_handler)(Scsi_Cmnd *); + + /* + * Old EH handlers, no longer used. Make them warn the user of old + * drivers by using a wrong type + */ + int (*abort)(int); + int (*reset)(int,int); + + /* + * slave_alloc() - Optional + * + * Before the mid layer attempts to scan for a new device where none + * currently exists, it will call this entry in your driver. Should + * your driver need to allocate any structs or perform any other init + * items in order to send commands to a currently unused target/lun + * combo, then this is where you can perform those allocations. This + * is specifically so that drivers won't have to perform any kind of + * "is this a new device" checks in their queuecommand routine, + * thereby making the hot path a bit quicker. + * + * Return values: 0 on success, non-0 on failure + * + * Deallocation: If we didn't find any devices at this ID, you will + * get an immediate call to slave_destroy(). If we find something here + * then you will get a call to slave_configure(), then the device will be + * used for however long it is kept around, then when the device is + * removed from the system (or * possibly at reboot time), you will + * then get a call to slave_detach(). This is assuming you implement + * slave_configure and slave_destroy. However, if you allocate memory + * and hang it off the device struct, then you must implement the + * slave_destroy() routine at a minimum in order to avoid leaking memory + * each time a device is tore down. + */ + int (* slave_alloc)(Scsi_Device *); + + /* + * slave_configure() - Optional + * + * Once the device has responded to an INQUIRY and we know the device + * is online, we call into the low level driver with the Scsi_Device * + * If the low level device driver implements this function, it *must* + * perform the task of setting the queue depth on the device. All other + * tasks are optional and depend on what the driver supports and various + * implementation details. + * + * Things currently recommended to be handled at this time include: + * + * 1. Setting the device queue depth. Proper setting of this is + * described in the comments for scsi_adjust_queue_depth. + * 2. Determining if the device supports the various synchronous + * negotiation protocols. The device struct will already have + * responded to INQUIRY and the results of the standard items + * will have been shoved into the various device flag bits, eg. + * device->sdtr will be true if the device supports SDTR messages. + * 3. Allocating command structs that the device will need. + * 4. Setting the default timeout on this device (if needed). + * 5. Anything else the low level driver might want to do on a device + * specific setup basis... + * 6. Return 0 on success, non-0 on error. The device will be marked + * as offline on error so that no access will occur. If you return + * non-0, your slave_detach routine will never get called for this + * device, so don't leave any loose memory hanging around, clean + * up after yourself before returning non-0 + */ + int (* slave_configure)(Scsi_Device *); + + /* + * slave_destroy() - Optional + * + * Immediately prior to deallocating the device and after all activity + * has ceased the mid layer calls this point so that the low level driver + * may completely detach itself from the scsi device and vice versa. + * The low level driver is responsible for freeing any memory it allocated + * in the slave_alloc or slave_configure calls. + */ + void (* slave_destroy)(Scsi_Device *); + + /* + * This function determines the bios parameters for a given + * harddisk. These tend to be numbers that are made up by + * the host adapter. Parameters: + * size, device, list (heads, sectors, cylinders) + */ + int (* bios_param)(struct scsi_device *, struct block_device *, + sector_t, int []); + + /* + * This determines if we will use a non-interrupt driven + * or an interrupt driven scheme, It is set to the maximum number + * of simultaneous commands a given host adapter will accept. + */ + int can_queue; + + /* + * In many instances, especially where disconnect / reconnect are + * supported, our host also has an ID on the SCSI bus. If this is + * the case, then it must be reserved. Please set this_id to -1 if + * your setup is in single initiator mode, and the host lacks an + * ID. + */ + int this_id; + + /* + * This determines the degree to which the host adapter is capable + * of scatter-gather. + */ + short unsigned int sg_tablesize; + + /* + * if the host adapter has limitations beside segment count + */ + short unsigned int max_sectors; + + /* + * True if this host adapter can make good use of linked commands. + * This will allow more than one command to be queued to a given + * unit on a given host. Set this to the maximum number of command + * blocks to be provided for each device. Set this to 1 for one + * command block per lun, 2 for two, etc. Do not set this to 0. + * You should make sure that the host adapter will do the right thing + * before you try setting this above 1. + */ + short cmd_per_lun; + + /* + * present contains counter indicating how many boards of this + * type were found when we did the scan. + */ + unsigned char present; + + /* + * true if this host adapter uses unchecked DMA onto an ISA bus. + */ + unsigned unchecked_isa_dma:1; + + /* + * true if this host adapter can make good use of clustering. + * I originally thought that if the tablesize was large that it + * was a waste of CPU cycles to prepare a cluster list, but + * it works out that the Buslogic is faster if you use a smaller + * number of segments (i.e. use clustering). I guess it is + * inefficient. + */ + unsigned use_clustering:1; + + /* + * True for emulated SCSI host adapters (e.g. ATAPI) + */ + unsigned emulated:1; + + unsigned highmem_io:1; + + /* + * True if the driver wishes to use the generic block layer + * tag queueing functions + */ + unsigned use_blk_tcq:1; + + /* + * Name of proc directory + */ + char *proc_name; + + /* + * countdown for host blocking with no commands outstanding + */ + unsigned int max_host_blocked; + + /* + * Default value for the blocking. If the queue is empty, host_blocked + * counts down in the request_fn until it restarts host operations as + * zero is reached. + * + * FIXME: This should probably be a value in the template */ + #define SCSI_DEFAULT_HOST_BLOCKED 7 + +} Scsi_Host_Template; + +/* + * The scsi_hosts array is the array containing the data for all + * possible scsi hosts. This is similar to the + * Scsi_Host_Template, except that we have one entry for each + * actual physical host adapter on the system, stored as a linked + * list. Note that if there are 2 aha1542 boards, then there will + * be two Scsi_Host entries, but only 1 Scsi_Host_Template entry. + */ + +struct Scsi_Host +{ +/* private: */ + /* + * This information is private to the scsi mid-layer. Wrapping it in a + * struct private is a way of marking it in a sort of C++ type of way. + */ + struct list_head sh_list; + struct list_head my_devices; + + struct scsi_host_cmd_pool *cmd_pool; + spinlock_t free_list_lock; + struct list_head free_list; /* backup store of cmd structs */ + struct list_head starved_list; + + spinlock_t default_lock; + spinlock_t *host_lock; + + struct list_head eh_cmd_q; + struct task_struct * ehandler; /* Error recovery thread. */ + struct semaphore * eh_wait; /* The error recovery thread waits on + this. */ + struct completion * eh_notify; /* wait for eh to begin or end */ + struct semaphore * eh_action; /* Wait for specific actions on the + host. */ + unsigned int eh_active:1; /* Indicates the eh thread is awake and active if + this is true. */ + unsigned int eh_kill:1; /* set when killing the eh thread */ + wait_queue_head_t host_wait; + Scsi_Host_Template * hostt; + volatile unsigned short host_busy; /* commands actually active on low-level */ + volatile unsigned short host_failed; /* commands that failed. */ + +/* public: */ + unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ + int resetting; /* if set, it means that last_reset is a valid value */ + unsigned long last_reset; + + /* + * These three parameters can be used to allow for wide scsi, + * and for host adapters that support multiple busses + * The first two should be set to 1 more than the actual max id + * or lun (i.e. 8 for normal systems). + */ + unsigned int max_id; + unsigned int max_lun; + unsigned int max_channel; + + /* These parameters should be set by the detect routine */ + unsigned long base; + unsigned long io_port; + unsigned char n_io_port; + unsigned char dma_channel; + unsigned int irq; + + /* + * This is a unique identifier that must be assigned so that we + * have some way of identifying each detected host adapter properly + * and uniquely. For hosts that do not support more than one card + * in the system at one time, this does not need to be set. It is + * initialized to 0 in scsi_register. + */ + unsigned int unique_id; + + /* + * The rest can be copied from the template, or specifically + * initialized, as required. + */ + + /* + * The maximum length of SCSI commands that this host can accept. + * Probably 12 for most host adapters, but could be 16 for others. + * For drivers that don't set this field, a value of 12 is + * assumed. I am leaving this as a number rather than a bit + * because you never know what subsequent SCSI standards might do + * (i.e. could there be a 20 byte or a 24-byte command a few years + * down the road?). + */ + unsigned char max_cmd_len; + + int this_id; + int can_queue; + short cmd_per_lun; + short unsigned int sg_tablesize; + short unsigned int max_sectors; + + unsigned in_recovery:1; + unsigned unchecked_isa_dma:1; + unsigned use_clustering:1; + unsigned highmem_io:1; + unsigned use_blk_tcq:1; + + /* + * Host has requested that no further requests come through for the + * time being. + */ + unsigned host_self_blocked:1; + + /* + * Host uses correct SCSI ordering not PC ordering. The bit is + * set for the minority of drivers whose authors actually read the spec ;) + */ + unsigned reverse_ordering:1; + + /* + * Host has rejected a command because it was busy. + */ + unsigned int host_blocked; + + /* + * Value host_blocked counts down from + */ + unsigned int max_host_blocked; + + /* + * Support for sysfs + */ + struct device host_gendev; + struct class_device class_dev; + + /* + * We should ensure that this is aligned, both for better performance + * and also because some compilers (m68k) don't automatically force + * alignment to a long boundary. + */ + unsigned long hostdata[0] /* Used for storage of host specific stuff */ + __attribute__ ((aligned (sizeof(unsigned long)))); +}; + +#define dev_to_shost(d) \ + container_of(d, struct Scsi_Host, host_gendev) +#define class_to_shost(d) \ + container_of(d, struct Scsi_Host, class_dev) + +/* + * These two functions are used to allocate and free a pseudo device + * which will connect to the host adapter itself rather than any + * physical device. You must deallocate when you are done with the + * thing. This physical pseudo-device isn't real and won't be available + * from any high-level drivers. + */ +extern void scsi_free_host_dev(Scsi_Device *); +extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host *); + +extern void scsi_unblock_requests(struct Scsi_Host *); +extern void scsi_block_requests(struct Scsi_Host *); +extern void scsi_report_bus_reset(struct Scsi_Host *, int); +extern void scsi_report_device_reset(struct Scsi_Host *, int, int); + +static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock) +{ + shost->host_lock = lock; +} + +static inline void scsi_set_device(struct Scsi_Host *shost, + struct device *dev) +{ + shost->host_gendev.parent = dev; +} + +static inline struct device *scsi_get_device(struct Scsi_Host *shost) +{ + return shost->host_gendev.parent; +} + +struct Scsi_Device_Template +{ + struct list_head list; + const char * name; + struct module * module; /* Used for loadable modules */ + unsigned char scsi_type; + int (*attach)(Scsi_Device *); /* Attach devices to arrays */ + void (*detach)(Scsi_Device *); + int (*init_command)(Scsi_Cmnd *); /* Used by new queueing code. + Selects command for blkdevs */ + void (*rescan)(Scsi_Device *); + struct device_driver scsi_driverfs_driver; +}; + +/* + * Highlevel driver registration/unregistration. + */ +extern int scsi_register_device(struct Scsi_Device_Template *); +extern int scsi_unregister_device(struct Scsi_Device_Template *); + +/* + * HBA allocation/freeing. + */ +extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int); +extern void scsi_unregister(struct Scsi_Host *); + +/* + * HBA registration/unregistration. + */ +extern int scsi_add_host(struct Scsi_Host *, struct device *); +extern int scsi_remove_host(struct Scsi_Host *); + +/* + * Legacy HBA template registration/unregistration. + */ +extern int scsi_register_host(Scsi_Host_Template *); +extern int scsi_unregister_host(Scsi_Host_Template *); + +extern struct Scsi_Host *scsi_host_hn_get(unsigned short); +extern void scsi_host_put(struct Scsi_Host *); + +/** + * scsi_find_device - find a device given the host + * @shost: SCSI host pointer + * @channel: SCSI channel (zero if only one channel) + * @pun: SCSI target number (physical unit number) + * @lun: SCSI Logical Unit Number + **/ +static inline Scsi_Device *scsi_find_device(struct Scsi_Host *shost, + int channel, int pun, int lun) { + Scsi_Device *sdev; + + list_for_each_entry (sdev, &shost->my_devices, siblings) + if (sdev->channel == channel && sdev->id == pun + && sdev->lun ==lun) + return sdev; + return NULL; +} + +#endif diff -Nru a/include/linux/scsi_obsolete.h b/include/linux/scsi_obsolete.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/scsi_obsolete.h Sat May 24 14:40:31 2003 @@ -0,0 +1,106 @@ +/* + * scsi_obsolete.h Copyright (C) 1997 Eric Youngdale + * + */ + +#ifndef _SCSI_OBSOLETE_H +#define _SCSI_OBSOLETE_H + +/* + * These are the return codes for the abort and reset functions. The mid-level + * code uses these to decide what to do next. Each of the low level abort + * and reset functions must correctly indicate what it has done. + * The descriptions are written from the point of view of the mid-level code, + * so that the return code is telling the mid-level drivers exactly what + * the low level driver has already done, and what remains to be done. + */ + +/* We did not do anything. + * Wait some more for this command to complete, and if this does not work, + * try something more serious. */ +#define SCSI_ABORT_SNOOZE 0 + +/* This means that we were able to abort the command. We have already + * called the mid-level done function, and do not expect an interrupt that + * will lead to another call to the mid-level done function for this command */ +#define SCSI_ABORT_SUCCESS 1 + +/* We called for an abort of this command, and we should get an interrupt + * when this succeeds. Thus we should not restore the timer for this + * command in the mid-level abort function. */ +#define SCSI_ABORT_PENDING 2 + +/* Unable to abort - command is currently on the bus. Grin and bear it. */ +#define SCSI_ABORT_BUSY 3 + +/* The command is not active in the low level code. Command probably + * finished. */ +#define SCSI_ABORT_NOT_RUNNING 4 + +/* Something went wrong. The low level driver will indicate the correct + * error condition when it calls scsi_done, so the mid-level abort function + * can simply wait until this comes through */ +#define SCSI_ABORT_ERROR 5 + +/* We do not know how to reset the bus, or we do not want to. Bummer. + * Anyway, just wait a little more for the command in question, and hope that + * it eventually finishes. If it never finishes, the SCSI device could + * hang, so use this with caution. */ +#define SCSI_RESET_SNOOZE 0 + +/* We do not know how to reset the bus, or we do not want to. Bummer. + * We have given up on this ever completing. The mid-level code will + * request sense information to decide how to proceed from here. */ +#define SCSI_RESET_PUNT 1 + +/* This means that we were able to reset the bus. We have restarted all of + * the commands that should be restarted, and we should be able to continue + * on normally from here. We do not expect any interrupts that will return + * DID_RESET to any of the other commands in the host_queue, and the mid-level + * code does not need to do anything special to keep the commands alive. + * If a hard reset was performed then all outstanding commands on the + * bus have been restarted. */ +#define SCSI_RESET_SUCCESS 2 + +/* We called for a reset of this bus, and we should get an interrupt + * when this succeeds. Each command should get its own status + * passed up to scsi_done, but this has not happened yet. + * If a hard reset was performed, then we expect an interrupt + * for *each* of the outstanding commands that will have the + * effect of restarting the commands. + */ +#define SCSI_RESET_PENDING 3 + +/* We did a reset, but do not expect an interrupt to signal DID_RESET. + * This tells the upper level code to request the sense info, and this + * should keep the command alive. */ +#define SCSI_RESET_WAKEUP 4 + +/* The command is not active in the low level code. Command probably + finished. */ +#define SCSI_RESET_NOT_RUNNING 5 + +/* Something went wrong, and we do not know how to fix it. */ +#define SCSI_RESET_ERROR 6 + +#define SCSI_RESET_SYNCHRONOUS 0x01 +#define SCSI_RESET_ASYNCHRONOUS 0x02 +#define SCSI_RESET_SUGGEST_BUS_RESET 0x04 +#define SCSI_RESET_SUGGEST_HOST_RESET 0x08 +/* + * This is a bitmask that is ored with one of the above codes. + * It tells the mid-level code that we did a hard reset. + */ +#define SCSI_RESET_BUS_RESET 0x100 +/* + * This is a bitmask that is ored with one of the above codes. + * It tells the mid-level code that we did a host adapter reset. + */ +#define SCSI_RESET_HOST_RESET 0x200 +/* + * Used to mask off bits and to obtain the basic action that was + * performed. + */ +#define SCSI_RESET_ACTION 0xff + +#endif /* SCSI_OBSOLETE_H */