diff --git a/[refs] b/[refs] index 33f347ed5db6..7dbf018a6bcd 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: c8b6de16d9434405e5832b8772e4f986ddd5118e +refs/heads/master: 5bb983b0cce9b7b281af15730f7019116dd42568 diff --git a/trunk/Documentation/DocBook/scsi.tmpl b/trunk/Documentation/DocBook/scsi.tmpl index 10a150ae2a7e..f299ab182bbe 100644 --- a/trunk/Documentation/DocBook/scsi.tmpl +++ b/trunk/Documentation/DocBook/scsi.tmpl @@ -12,7 +12,7 @@ Bottomley
- James.Bottomley@hansenpartnership.com + James.Bottomley@steeleye.com
diff --git a/trunk/Documentation/input/input-programming.txt b/trunk/Documentation/input/input-programming.txt index 81905e81585e..47fc86830cd7 100644 --- a/trunk/Documentation/input/input-programming.txt +++ b/trunk/Documentation/input/input-programming.txt @@ -22,7 +22,7 @@ static struct input_dev *button_dev; static void button_interrupt(int irq, void *dummy, struct pt_regs *fp) { - input_report_key(button_dev, BTN_0, inb(BUTTON_PORT) & 1); + input_report_key(button_dev, BTN_1, inb(BUTTON_PORT) & 1); input_sync(button_dev); } diff --git a/trunk/Documentation/scsi/ChangeLog.arcmsr b/trunk/Documentation/scsi/ChangeLog.arcmsr index de2bcacfa870..cd8403a33ee6 100644 --- a/trunk/Documentation/scsi/ChangeLog.arcmsr +++ b/trunk/Documentation/scsi/ChangeLog.arcmsr @@ -68,45 +68,4 @@ ** 2. modify the arcmsr_pci_slot_reset function ** 3. modify the arcmsr_pci_ers_disconnect_forepart function ** 4. modify the arcmsr_pci_ers_need_reset_forepart function -** 1.20.00.15 09/27/2007 Erich Chen & Nick Cheng -** 1. add arcmsr_enable_eoi_mode() on adapter Type B -** 2. add readl(reg->iop2drv_doorbell_reg) in arcmsr_handle_hbb_isr() -** in case of the doorbell interrupt clearance is cached -** 1.20.00.15 10/01/2007 Erich Chen & Nick Cheng -** 1. modify acb->devstate[i][j] -** as ARECA_RAID_GOOD instead of -** ARECA_RAID_GONE in arcmsr_alloc_ccb_pool -** 1.20.00.15 11/06/2007 Erich Chen & Nick Cheng -** 1. add conditional declaration for -** arcmsr_pci_error_detected() and -** arcmsr_pci_slot_reset -** 1.20.00.15 11/23/2007 Erich Chen & Nick Cheng -** 1.check if the sg list member number -** exceeds arcmsr default limit in arcmsr_build_ccb() -** 2.change the returned value type of arcmsr_build_ccb() -** from "void" to "int" -** 3.add the conditional check if arcmsr_build_ccb() -** returns FAILED -** 1.20.00.15 12/04/2007 Erich Chen & Nick Cheng -** 1. modify arcmsr_drain_donequeue() to ignore unknown -** command and let kernel process command timeout. -** This could handle IO request violating max. segments -** while Linux XFS over DM-CRYPT. -** Thanks to Milan Broz's comments -** 1.20.00.15 12/24/2007 Erich Chen & Nick Cheng -** 1.fix the portability problems -** 2.fix type B where we should _not_ iounmap() acb->pmu; -** it's not ioremapped. -** 3.add return -ENOMEM if ioremap() fails -** 4.transfer IS_SG64_ADDR w/ cpu_to_le32() -** in arcmsr_build_ccb -** 5. modify acb->devstate[i][j] as ARECA_RAID_GONE instead of -** ARECA_RAID_GOOD in arcmsr_alloc_ccb_pool() -** 6.fix arcmsr_cdb->Context as (unsigned long)arcmsr_cdb -** 7.add the checking state of -** (outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT) == 0 -** in arcmsr_handle_hba_isr -** 8.replace pci_alloc_consistent()/pci_free_consistent() with kmalloc()/kfree() in arcmsr_iop_message_xfer() -** 9. fix the release of dma memory for type B in arcmsr_free_ccb_pool() -** 10.fix the arcmsr_polling_hbb_ccbdone() ************************************************************************** diff --git a/trunk/Documentation/scsi/scsi_mid_low_api.txt b/trunk/Documentation/scsi/scsi_mid_low_api.txt index a6d5354639b2..6f70f2b9327e 100644 --- a/trunk/Documentation/scsi/scsi_mid_low_api.txt +++ b/trunk/Documentation/scsi/scsi_mid_low_api.txt @@ -1407,7 +1407,7 @@ Credits ======= The following people have contributed to this document: Mike Anderson - James Bottomley + James Bottomley Patrick Mansfield Christoph Hellwig Doug Ledford diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 2cdb591ac080..aefd23f892ba 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -2150,14 +2150,6 @@ M: acme@ghostprotocols.net L: netdev@vger.kernel.org S: Maintained -IPWIRELES DRIVER -P: Jiri Kosina -M: jkosina@suse.cz -P: David Sterba -M: dsterba@suse.cz -S: Maintained -T: git://git.kernel.org/pub/scm/linux/kernel/git/jikos/ipwireless_cs.git - IRDA SUBSYSTEM P: Samuel Ortiz M: samuel@sortiz.org diff --git a/trunk/arch/arm/mach-pxa/tosa.c b/trunk/arch/arm/mach-pxa/tosa.c index f99112d50b41..9b26fa5edad6 100644 --- a/trunk/arch/arm/mach-pxa/tosa.c +++ b/trunk/arch/arm/mach-pxa/tosa.c @@ -21,8 +21,6 @@ #include #include #include -#include -#include #include #include @@ -248,46 +246,6 @@ static struct platform_device tosakbd_device = { .id = -1, }; -static struct gpio_keys_button tosa_gpio_keys[] = { - { - .type = EV_PWR, - .code = KEY_SUSPEND, - .gpio = TOSA_GPIO_ON_KEY, - .desc = "On key", - .wakeup = 1, - .active_low = 1, - }, - { - .type = EV_KEY, - .code = TOSA_KEY_RECORD, - .gpio = TOSA_GPIO_RECORD_BTN, - .desc = "Record Button", - .wakeup = 1, - .active_low = 1, - }, - { - .type = EV_KEY, - .code = TOSA_KEY_SYNC, - .gpio = TOSA_GPIO_SYNC, - .desc = "Sync Button", - .wakeup = 1, - .active_low = 1, - }, -}; - -static struct gpio_keys_platform_data tosa_gpio_keys_platform_data = { - .buttons = tosa_gpio_keys, - .nbuttons = ARRAY_SIZE(tosa_gpio_keys), -}; - -static struct platform_device tosa_gpio_keys_device = { - .name = "gpio-keys", - .id = -1, - .dev = { - .platform_data = &tosa_gpio_keys_platform_data, - }, -}; - /* * Tosa LEDs */ @@ -300,7 +258,6 @@ static struct platform_device *devices[] __initdata = { &tosascoop_device, &tosascoop_jc_device, &tosakbd_device, - &tosa_gpio_keys_device, &tosaled_device, }; diff --git a/trunk/arch/m68k/kernel/process.c b/trunk/arch/m68k/kernel/process.c index f85b928ffac4..3ee918695215 100644 --- a/trunk/arch/m68k/kernel/process.c +++ b/trunk/arch/m68k/kernel/process.c @@ -335,7 +335,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump) if (dump->start_stack < TASK_SIZE) dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; - dump->u_ar0 = offsetof(struct user, regs); + dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump); sw = ((struct switch_stack *)regs) - 1; dump->regs.d1 = regs->d1; dump->regs.d2 = regs->d2; diff --git a/trunk/arch/powerpc/kernel/asm-offsets.c b/trunk/arch/powerpc/kernel/asm-offsets.c index 4b749c416464..e6e49289f788 100644 --- a/trunk/arch/powerpc/kernel/asm-offsets.c +++ b/trunk/arch/powerpc/kernel/asm-offsets.c @@ -313,7 +313,7 @@ int main(void) DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); DEFINE(NSEC_PER_SEC, NSEC_PER_SEC); - DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC); + DEFINE(CLOCK_REALTIME_RES, (KTIME_MONOTONIC_RES).tv64); #ifdef CONFIG_BUG DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry)); diff --git a/trunk/drivers/base/firmware_class.c b/trunk/drivers/base/firmware_class.c index 4a1b9bfc5471..0295855a3eef 100644 --- a/trunk/drivers/base/firmware_class.c +++ b/trunk/drivers/base/firmware_class.c @@ -292,8 +292,7 @@ firmware_class_timeout(u_long data) static inline void fw_setup_device_id(struct device *f_dev, struct device *dev) { - /* XXX warning we should watch out for name collisions */ - strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE); + snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id); } static int fw_register_device(struct device **dev_p, const char *fw_name, diff --git a/trunk/drivers/char/drm/i915_drv.h b/trunk/drivers/char/drm/i915_drv.h index f8308bfb2613..37bbf6729b4e 100644 --- a/trunk/drivers/char/drm/i915_drv.h +++ b/trunk/drivers/char/drm/i915_drv.h @@ -187,7 +187,7 @@ typedef struct drm_i915_private { u32 saveSWF2[3]; u8 saveMSR; u8 saveSR[8]; - u8 saveGR[25]; + u8 saveGR[24]; u8 saveAR_INDEX; u8 saveAR[20]; u8 saveDACMASK; diff --git a/trunk/drivers/char/keyboard.c b/trunk/drivers/char/keyboard.c index 4dbd3425e928..fc54d234507a 100644 --- a/trunk/drivers/char/keyboard.c +++ b/trunk/drivers/char/keyboard.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -193,7 +194,7 @@ int getkeycode(unsigned int scancode) int error = -ENODEV; list_for_each_entry(handle, &kbd_handler.h_list, h_node) { - error = input_get_keycode(handle->dev, scancode, &keycode); + error = handle->dev->getkeycode(handle->dev, scancode, &keycode); if (!error) return keycode; } @@ -207,7 +208,7 @@ int setkeycode(unsigned int scancode, unsigned int keycode) int error = -ENODEV; list_for_each_entry(handle, &kbd_handler.h_list, h_node) { - error = input_set_keycode(handle->dev, scancode, keycode); + error = handle->dev->setkeycode(handle->dev, scancode, keycode); if (!error) break; } diff --git a/trunk/drivers/char/pcmcia/Kconfig b/trunk/drivers/char/pcmcia/Kconfig index 00b8a84b0319..f25facd97bb4 100644 --- a/trunk/drivers/char/pcmcia/Kconfig +++ b/trunk/drivers/char/pcmcia/Kconfig @@ -43,14 +43,5 @@ config CARDMAN_4040 (http://www.omnikey.com/), or a current development version of OpenCT (http://www.opensc.org/). -config IPWIRELESS - tristate "IPWireless 3G UMTS PCMCIA card support" - depends on PCMCIA - select PPP - help - This is a driver for 3G UMTS PCMCIA card from IPWireless company. In - some countries (for example Czech Republic, T-Mobile ISP) this card - is shipped for service called UMTS 4G. - endmenu diff --git a/trunk/drivers/char/pcmcia/Makefile b/trunk/drivers/char/pcmcia/Makefile index be8f287aa398..0aae20985d57 100644 --- a/trunk/drivers/char/pcmcia/Makefile +++ b/trunk/drivers/char/pcmcia/Makefile @@ -4,8 +4,6 @@ # Makefile for the Linux PCMCIA char device drivers. # -obj-y += ipwireless/ - obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o obj-$(CONFIG_CARDMAN_4000) += cm4000_cs.o obj-$(CONFIG_CARDMAN_4040) += cm4040_cs.o diff --git a/trunk/drivers/char/pcmcia/ipwireless/Makefile b/trunk/drivers/char/pcmcia/ipwireless/Makefile deleted file mode 100644 index b71eb593643d..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# drivers/char/pcmcia/ipwireless/Makefile -# -# Makefile for the IPWireless driver -# - -obj-$(CONFIG_IPWIRELESS) += ipwireless.o - -ipwireless-objs := hardware.o main.o network.o tty.o - diff --git a/trunk/drivers/char/pcmcia/ipwireless/hardware.c b/trunk/drivers/char/pcmcia/ipwireless/hardware.c deleted file mode 100644 index 1f978ff87fa8..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/hardware.c +++ /dev/null @@ -1,1787 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#include -#include -#include -#include -#include -#include - -#include "hardware.h" -#include "setup_protocol.h" -#include "network.h" -#include "main.h" - -static void ipw_send_setup_packet(struct ipw_hardware *hw); -static void handle_received_SETUP_packet(struct ipw_hardware *ipw, - unsigned int address, - unsigned char *data, int len, - int is_last); -static void ipwireless_setup_timer(unsigned long data); -static void handle_received_CTRL_packet(struct ipw_hardware *hw, - unsigned int channel_idx, unsigned char *data, int len); - -/*#define TIMING_DIAGNOSTICS*/ - -#ifdef TIMING_DIAGNOSTICS - -static struct timing_stats { - unsigned long last_report_time; - unsigned long read_time; - unsigned long write_time; - unsigned long read_bytes; - unsigned long write_bytes; - unsigned long start_time; -}; - -static void start_timing(void) -{ - timing_stats.start_time = jiffies; -} - -static void end_read_timing(unsigned length) -{ - timing_stats.read_time += (jiffies - start_time); - timing_stats.read_bytes += length + 2; - report_timing(); -} - -static void end_write_timing(unsigned length) -{ - timing_stats.write_time += (jiffies - start_time); - timing_stats.write_bytes += length + 2; - report_timing(); -} - -static void report_timing(void) -{ - unsigned long since = jiffies - timing_stats.last_report_time; - - /* If it's been more than one second... */ - if (since >= HZ) { - int first = (timing_stats.last_report_time == 0); - - timing_stats.last_report_time = jiffies; - if (!first) - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": %u us elapsed - read %lu bytes in %u us, " - "wrote %lu bytes in %u us\n", - jiffies_to_usecs(since), - timing_stats.read_bytes, - jiffies_to_usecs(timing_stats.read_time), - timing_stats.write_bytes, - jiffies_to_usecs(timing_stats.write_time)); - - timing_stats.read_time = 0; - timing_stats.write_time = 0; - timing_stats.read_bytes = 0; - timing_stats.write_bytes = 0; - } -} -#else -static void start_timing(void) { } -static void end_read_timing(unsigned length) { } -static void end_write_timing(unsigned length) { } -#endif - -/* Imported IPW definitions */ - -#define LL_MTU_V1 318 -#define LL_MTU_V2 250 -#define LL_MTU_MAX (LL_MTU_V1 > LL_MTU_V2 ? LL_MTU_V1 : LL_MTU_V2) - -#define PRIO_DATA 2 -#define PRIO_CTRL 1 -#define PRIO_SETUP 0 - -/* Addresses */ -#define ADDR_SETUP_PROT 0 - -/* Protocol ids */ -enum { - /* Identifier for the Com Data protocol */ - TL_PROTOCOLID_COM_DATA = 0, - - /* Identifier for the Com Control protocol */ - TL_PROTOCOLID_COM_CTRL = 1, - - /* Identifier for the Setup protocol */ - TL_PROTOCOLID_SETUP = 2 -}; - -/* Number of bytes in NL packet header (cannot do - * sizeof(nl_packet_header) since it's a bitfield) */ -#define NL_FIRST_PACKET_HEADER_SIZE 3 - -/* Number of bytes in NL packet header (cannot do - * sizeof(nl_packet_header) since it's a bitfield) */ -#define NL_FOLLOWING_PACKET_HEADER_SIZE 1 - -struct nl_first_packet_header { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char packet_rank:2; - unsigned char address:3; - unsigned char protocol:3; -#else - unsigned char protocol:3; - unsigned char address:3; - unsigned char packet_rank:2; -#endif - unsigned char length_lsb; - unsigned char length_msb; -}; - -struct nl_packet_header { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char packet_rank:2; - unsigned char address:3; - unsigned char protocol:3; -#else - unsigned char protocol:3; - unsigned char address:3; - unsigned char packet_rank:2; -#endif -}; - -/* Value of 'packet_rank' above */ -#define NL_INTERMEDIATE_PACKET 0x0 -#define NL_LAST_PACKET 0x1 -#define NL_FIRST_PACKET 0x2 - -union nl_packet { - /* Network packet header of the first packet (a special case) */ - struct nl_first_packet_header hdr_first; - /* Network packet header of the following packets (if any) */ - struct nl_packet_header hdr; - /* Complete network packet (header + data) */ - unsigned char rawpkt[LL_MTU_MAX]; -} __attribute__ ((__packed__)); - -#define HW_VERSION_UNKNOWN -1 -#define HW_VERSION_1 1 -#define HW_VERSION_2 2 - -/* IPW I/O ports */ -#define IOIER 0x00 /* Interrupt Enable Register */ -#define IOIR 0x02 /* Interrupt Source/ACK register */ -#define IODCR 0x04 /* Data Control Register */ -#define IODRR 0x06 /* Data Read Register */ -#define IODWR 0x08 /* Data Write Register */ -#define IOESR 0x0A /* Embedded Driver Status Register */ -#define IORXR 0x0C /* Rx Fifo Register (Host to Embedded) */ -#define IOTXR 0x0E /* Tx Fifo Register (Embedded to Host) */ - -/* I/O ports and bit definitions for version 1 of the hardware */ - -/* IER bits*/ -#define IER_RXENABLED 0x1 -#define IER_TXENABLED 0x2 - -/* ISR bits */ -#define IR_RXINTR 0x1 -#define IR_TXINTR 0x2 - -/* DCR bits */ -#define DCR_RXDONE 0x1 -#define DCR_TXDONE 0x2 -#define DCR_RXRESET 0x4 -#define DCR_TXRESET 0x8 - -/* I/O ports and bit definitions for version 2 of the hardware */ - -struct MEMCCR { - unsigned short reg_config_option; /* PCCOR: Configuration Option Register */ - unsigned short reg_config_and_status; /* PCCSR: Configuration and Status Register */ - unsigned short reg_pin_replacement; /* PCPRR: Pin Replacemant Register */ - unsigned short reg_socket_and_copy; /* PCSCR: Socket and Copy Register */ - unsigned short reg_ext_status; /* PCESR: Extendend Status Register */ - unsigned short reg_io_base; /* PCIOB: I/O Base Register */ -}; - -struct MEMINFREG { - unsigned short memreg_tx_old; /* TX Register (R/W) */ - unsigned short pad1; - unsigned short memreg_rx_done; /* RXDone Register (R/W) */ - unsigned short pad2; - unsigned short memreg_rx; /* RX Register (R/W) */ - unsigned short pad3; - unsigned short memreg_pc_interrupt_ack; /* PC intr Ack Register (W) */ - unsigned short pad4; - unsigned long memreg_card_present;/* Mask for Host to check (R) for - * CARD_PRESENT_VALUE */ - unsigned short memreg_tx_new; /* TX2 (new) Register (R/W) */ -}; - -#define IODMADPR 0x00 /* DMA Data Port Register (R/W) */ - -#define CARD_PRESENT_VALUE (0xBEEFCAFEUL) - -#define MEMTX_TX 0x0001 -#define MEMRX_RX 0x0001 -#define MEMRX_RX_DONE 0x0001 -#define MEMRX_PCINTACKK 0x0001 -#define MEMRX_MEMSPURIOUSINT 0x0001 - -#define NL_NUM_OF_PRIORITIES 3 -#define NL_NUM_OF_PROTOCOLS 3 -#define NL_NUM_OF_ADDRESSES NO_OF_IPW_CHANNELS - -struct ipw_hardware { - unsigned int base_port; - short hw_version; - unsigned short ll_mtu; - spinlock_t spinlock; - - int initializing; - int init_loops; - struct timer_list setup_timer; - - int tx_ready; - struct list_head tx_queue[NL_NUM_OF_PRIORITIES]; - /* True if any packets are queued for transmission */ - int tx_queued; - - int rx_bytes_queued; - struct list_head rx_queue; - /* Pool of rx_packet structures that are not currently used. */ - struct list_head rx_pool; - int rx_pool_size; - /* True if reception of data is blocked while userspace processes it. */ - int blocking_rx; - /* True if there is RX data ready on the hardware. */ - int rx_ready; - unsigned short last_memtx_serial; - /* - * Newer versions of the V2 card firmware send serial numbers in the - * MemTX register. 'serial_number_detected' is set true when we detect - * a non-zero serial number (indicating the new firmware). Thereafter, - * the driver can safely ignore the Timer Recovery re-sends to avoid - * out-of-sync problems. - */ - int serial_number_detected; - struct work_struct work_rx; - - /* True if we are to send the set-up data to the hardware. */ - int to_setup; - - /* Card has been removed */ - int removed; - /* Saved irq value when we disable the interrupt. */ - int irq; - /* True if this driver is shutting down. */ - int shutting_down; - /* Modem control lines */ - unsigned int control_lines[NL_NUM_OF_ADDRESSES]; - struct ipw_rx_packet *packet_assembler[NL_NUM_OF_ADDRESSES]; - - struct tasklet_struct tasklet; - - /* The handle for the network layer, for the sending of events to it. */ - struct ipw_network *network; - struct MEMINFREG __iomem *memory_info_regs; - struct MEMCCR __iomem *memregs_CCR; - void (*reboot_callback) (void *data); - void *reboot_callback_data; - - unsigned short __iomem *memreg_tx; -}; - -/* - * Packet info structure for tx packets. - * Note: not all the fields defined here are required for all protocols - */ -struct ipw_tx_packet { - struct list_head queue; - /* channel idx + 1 */ - unsigned char dest_addr; - /* SETUP, CTRL or DATA */ - unsigned char protocol; - /* Length of data block, which starts at the end of this structure */ - unsigned short length; - /* Sending state */ - /* Offset of where we've sent up to so far */ - unsigned long offset; - /* Count of packet fragments, starting at 0 */ - int fragment_count; - - /* Called after packet is sent and before is freed */ - void (*packet_callback) (void *cb_data, unsigned int packet_length); - void *callback_data; -}; - -/* Signals from DTE */ -#define COMCTRL_RTS 0 -#define COMCTRL_DTR 1 - -/* Signals from DCE */ -#define COMCTRL_CTS 2 -#define COMCTRL_DCD 3 -#define COMCTRL_DSR 4 -#define COMCTRL_RI 5 - -struct ipw_control_packet_body { - /* DTE signal or DCE signal */ - unsigned char sig_no; - /* 0: set signal, 1: clear signal */ - unsigned char value; -} __attribute__ ((__packed__)); - -struct ipw_control_packet { - struct ipw_tx_packet header; - struct ipw_control_packet_body body; -}; - -struct ipw_rx_packet { - struct list_head queue; - unsigned int capacity; - unsigned int length; - unsigned int protocol; - unsigned int channel_idx; -}; - -#ifdef IPWIRELESS_STATE_DEBUG -int ipwireless_dump_hardware_state(char *p, size_t limit, - struct ipw_hardware *hw) -{ - return snprintf(p, limit, - "debug: initializing=%d\n" - "debug: tx_ready=%d\n" - "debug: tx_queued=%d\n" - "debug: rx_ready=%d\n" - "debug: rx_bytes_queued=%d\n" - "debug: blocking_rx=%d\n" - "debug: removed=%d\n" - "debug: hardware.shutting_down=%d\n" - "debug: to_setup=%d\n", - hw->initializing, - hw->tx_ready, - hw->tx_queued, - hw->rx_ready, - hw->rx_bytes_queued, - hw->blocking_rx, - hw->removed, - hw->shutting_down, - hw->to_setup); -} -#endif - -static char *data_type(const unsigned char *buf, unsigned length) -{ - struct nl_packet_header *hdr = (struct nl_packet_header *) buf; - - if (length == 0) - return " "; - - if (hdr->packet_rank & NL_FIRST_PACKET) { - switch (hdr->protocol) { - case TL_PROTOCOLID_COM_DATA: return "DATA "; - case TL_PROTOCOLID_COM_CTRL: return "CTRL "; - case TL_PROTOCOLID_SETUP: return "SETUP"; - default: return "???? "; - } - } else - return " "; -} - -#define DUMP_MAX_BYTES 64 - -static void dump_data_bytes(const char *type, const unsigned char *data, - unsigned length) -{ - char prefix[56]; - - sprintf(prefix, IPWIRELESS_PCCARD_NAME ": %s %s ", - type, data_type(data, length)); - print_hex_dump_bytes(prefix, 0, (void *)data, - length < DUMP_MAX_BYTES ? length : DUMP_MAX_BYTES); -} - -static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data, - unsigned length) -{ - int i; - unsigned long flags; - - start_timing(); - - if (length == 0) - return 0; - - if (length > hw->ll_mtu) - return -1; - - if (ipwireless_debug) - dump_data_bytes("send", data, length); - - spin_lock_irqsave(&hw->spinlock, flags); - - if (hw->hw_version == HW_VERSION_1) { - outw((unsigned short) length, hw->base_port + IODWR); - - for (i = 0; i < length; i += 2) { - unsigned short d = data[i]; - __le16 raw_data; - - if (likely(i + 1 < length)) - d |= data[i + 1] << 8; - raw_data = cpu_to_le16(d); - outw(raw_data, hw->base_port + IODWR); - } - - outw(DCR_TXDONE, hw->base_port + IODCR); - } else if (hw->hw_version == HW_VERSION_2) { - outw((unsigned short) length, hw->base_port + IODMADPR); - - for (i = 0; i < length; i += 2) { - unsigned short d = data[i]; - __le16 raw_data; - - if ((i + 1 < length)) - d |= data[i + 1] << 8; - raw_data = cpu_to_le16(d); - outw(raw_data, hw->base_port + IODMADPR); - } - while ((i & 3) != 2) { - outw((unsigned short) 0xDEAD, hw->base_port + IODMADPR); - i += 2; - } - writew(MEMRX_RX, &hw->memory_info_regs->memreg_rx); - } - - spin_unlock_irqrestore(&hw->spinlock, flags); - - end_write_timing(length); - - return 0; -} - -static int do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet) -{ - unsigned short fragment_data_len; - unsigned short data_left = packet->length - packet->offset; - unsigned short header_size; - union nl_packet pkt; - - header_size = - (packet->fragment_count == 0) - ? NL_FIRST_PACKET_HEADER_SIZE - : NL_FOLLOWING_PACKET_HEADER_SIZE; - fragment_data_len = hw->ll_mtu - header_size; - if (data_left < fragment_data_len) - fragment_data_len = data_left; - - pkt.hdr_first.protocol = packet->protocol; - pkt.hdr_first.address = packet->dest_addr; - pkt.hdr_first.packet_rank = 0; - - /* First packet? */ - if (packet->fragment_count == 0) { - pkt.hdr_first.packet_rank |= NL_FIRST_PACKET; - pkt.hdr_first.length_lsb = (unsigned char) packet->length; - pkt.hdr_first.length_msb = - (unsigned char) (packet->length >> 8); - } - - memcpy(pkt.rawpkt + header_size, - ((unsigned char *) packet) + sizeof(struct ipw_tx_packet) + - packet->offset, fragment_data_len); - packet->offset += fragment_data_len; - packet->fragment_count++; - - /* Last packet? (May also be first packet.) */ - if (packet->offset == packet->length) - pkt.hdr_first.packet_rank |= NL_LAST_PACKET; - do_send_fragment(hw, pkt.rawpkt, header_size + fragment_data_len); - - /* If this packet has unsent data, then re-queue it. */ - if (packet->offset < packet->length) { - /* - * Re-queue it at the head of the highest priority queue so - * it goes before all other packets - */ - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - list_add(&packet->queue, &hw->tx_queue[0]); - spin_unlock_irqrestore(&hw->spinlock, flags); - } else { - if (packet->packet_callback) - packet->packet_callback(packet->callback_data, - packet->length); - kfree(packet); - } - - return 0; -} - -static void ipw_setup_hardware(struct ipw_hardware *hw) -{ - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - if (hw->hw_version == HW_VERSION_1) { - /* Reset RX FIFO */ - outw(DCR_RXRESET, hw->base_port + IODCR); - /* SB: Reset TX FIFO */ - outw(DCR_TXRESET, hw->base_port + IODCR); - - /* Enable TX and RX interrupts. */ - outw(IER_TXENABLED | IER_RXENABLED, hw->base_port + IOIER); - } else { - /* - * Set INTRACK bit (bit 0), which means we must explicitly - * acknowledge interrupts by clearing bit 2 of reg_config_and_status. - */ - unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status); - - csr |= 1; - writew(csr, &hw->memregs_CCR->reg_config_and_status); - } - spin_unlock_irqrestore(&hw->spinlock, flags); -} - -/* - * If 'packet' is NULL, then this function allocates a new packet, setting its - * length to 0 and ensuring it has the specified minimum amount of free space. - * - * If 'packet' is not NULL, then this function enlarges it if it doesn't - * have the specified minimum amount of free space. - * - */ -static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw, - struct ipw_rx_packet *packet, - int minimum_free_space) -{ - - if (!packet) { - unsigned long flags; - - /* - * If this is the first fragment, then we will need to fetch a - * packet to put it in. - */ - spin_lock_irqsave(&hw->spinlock, flags); - /* If we have one in our pool, then pull it out. */ - if (!list_empty(&hw->rx_pool)) { - packet = list_first_entry(&hw->rx_pool, - struct ipw_rx_packet, queue); - list_del(&packet->queue); - hw->rx_pool_size--; - spin_unlock_irqrestore(&hw->spinlock, flags); - } else { - /* Otherwise allocate a new one. */ - static int min_capacity = 256; - int new_capacity; - - spin_unlock_irqrestore(&hw->spinlock, flags); - new_capacity = - minimum_free_space > min_capacity - ? minimum_free_space - : min_capacity; - packet = kmalloc(sizeof(struct ipw_rx_packet) - + new_capacity, GFP_ATOMIC); - if (!packet) - return NULL; - packet->capacity = new_capacity; - } - packet->length = 0; - } - - /* - * If this packet does not have sufficient capacity for the data we - * want to add, then make it bigger. - */ - if (packet->length + minimum_free_space > packet->capacity) { - struct ipw_rx_packet *old_packet = packet; - - packet = kmalloc(sizeof(struct ipw_rx_packet) + - old_packet->length + minimum_free_space, - GFP_ATOMIC); - if (!packet) - return NULL; - memcpy(packet, old_packet, - sizeof(struct ipw_rx_packet) - + old_packet->length); - packet->capacity = old_packet->length + minimum_free_space; - kfree(old_packet); - } - - return packet; -} - -static void pool_free(struct ipw_hardware *hw, struct ipw_rx_packet *packet) -{ - if (hw->rx_pool_size > 6) - kfree(packet); - else { - hw->rx_pool_size++; - list_add_tail(&packet->queue, &hw->rx_pool); - } -} - -static void queue_received_packet(struct ipw_hardware *hw, - unsigned int protocol, unsigned int address, - unsigned char *data, int length, int is_last) -{ - unsigned int channel_idx = address - 1; - struct ipw_rx_packet *packet = NULL; - unsigned long flags; - - /* Discard packet if channel index is out of range. */ - if (channel_idx >= NL_NUM_OF_ADDRESSES) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": data packet has bad address %u\n", address); - return; - } - - /* - * ->packet_assembler is safe to touch unlocked, this is the only place - */ - if (protocol == TL_PROTOCOLID_COM_DATA) { - struct ipw_rx_packet **assem = - &hw->packet_assembler[channel_idx]; - - /* - * Create a new packet, or assembler already contains one - * enlarge it by 'length' bytes. - */ - (*assem) = pool_allocate(hw, *assem, length); - if (!(*assem)) { - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": no memory for incomming data packet, dropped!\n"); - return; - } - (*assem)->protocol = protocol; - (*assem)->channel_idx = channel_idx; - - /* Append this packet data onto existing data. */ - memcpy((unsigned char *)(*assem) + - sizeof(struct ipw_rx_packet) - + (*assem)->length, data, length); - (*assem)->length += length; - if (is_last) { - packet = *assem; - *assem = NULL; - /* Count queued DATA bytes only */ - spin_lock_irqsave(&hw->spinlock, flags); - hw->rx_bytes_queued += packet->length; - spin_unlock_irqrestore(&hw->spinlock, flags); - } - } else { - /* If it's a CTRL packet, don't assemble, just queue it. */ - packet = pool_allocate(hw, NULL, length); - if (!packet) { - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": no memory for incomming ctrl packet, dropped!\n"); - return; - } - packet->protocol = protocol; - packet->channel_idx = channel_idx; - memcpy((unsigned char *)packet + sizeof(struct ipw_rx_packet), - data, length); - packet->length = length; - } - - /* - * If this is the last packet, then send the assembled packet on to the - * network layer. - */ - if (packet) { - spin_lock_irqsave(&hw->spinlock, flags); - list_add_tail(&packet->queue, &hw->rx_queue); - /* Block reception of incoming packets if queue is full. */ - hw->blocking_rx = - hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE; - - spin_unlock_irqrestore(&hw->spinlock, flags); - schedule_work(&hw->work_rx); - } -} - -/* - * Workqueue callback - */ -static void ipw_receive_data_work(struct work_struct *work_rx) -{ - struct ipw_hardware *hw = - container_of(work_rx, struct ipw_hardware, work_rx); - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - while (!list_empty(&hw->rx_queue)) { - struct ipw_rx_packet *packet = - list_first_entry(&hw->rx_queue, - struct ipw_rx_packet, queue); - - if (hw->shutting_down) - break; - list_del(&packet->queue); - - /* - * Note: ipwireless_network_packet_received must be called in a - * process context (i.e. via schedule_work) because the tty - * output code can sleep in the tty_flip_buffer_push call. - */ - if (packet->protocol == TL_PROTOCOLID_COM_DATA) { - if (hw->network != NULL) { - /* If the network hasn't been disconnected. */ - spin_unlock_irqrestore(&hw->spinlock, flags); - /* - * This must run unlocked due to tty processing - * and mutex locking - */ - ipwireless_network_packet_received( - hw->network, - packet->channel_idx, - (unsigned char *)packet - + sizeof(struct ipw_rx_packet), - packet->length); - spin_lock_irqsave(&hw->spinlock, flags); - } - /* Count queued DATA bytes only */ - hw->rx_bytes_queued -= packet->length; - } else { - /* - * This is safe to be called locked, callchain does - * not block - */ - handle_received_CTRL_packet(hw, packet->channel_idx, - (unsigned char *)packet - + sizeof(struct ipw_rx_packet), - packet->length); - } - pool_free(hw, packet); - /* - * Unblock reception of incoming packets if queue is no longer - * full. - */ - hw->blocking_rx = - hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE; - if (hw->shutting_down) - break; - } - spin_unlock_irqrestore(&hw->spinlock, flags); -} - -static void handle_received_CTRL_packet(struct ipw_hardware *hw, - unsigned int channel_idx, - unsigned char *data, int len) -{ - struct ipw_control_packet_body *body = - (struct ipw_control_packet_body *) data; - unsigned int changed_mask; - - if (len != sizeof(struct ipw_control_packet_body)) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": control packet was %d bytes - wrong size!\n", - len); - return; - } - - switch (body->sig_no) { - case COMCTRL_CTS: - changed_mask = IPW_CONTROL_LINE_CTS; - break; - case COMCTRL_DCD: - changed_mask = IPW_CONTROL_LINE_DCD; - break; - case COMCTRL_DSR: - changed_mask = IPW_CONTROL_LINE_DSR; - break; - case COMCTRL_RI: - changed_mask = IPW_CONTROL_LINE_RI; - break; - default: - changed_mask = 0; - } - - if (changed_mask != 0) { - if (body->value) - hw->control_lines[channel_idx] |= changed_mask; - else - hw->control_lines[channel_idx] &= ~changed_mask; - if (hw->network) - ipwireless_network_notify_control_line_change( - hw->network, - channel_idx, - hw->control_lines[channel_idx], - changed_mask); - } -} - -static void handle_received_packet(struct ipw_hardware *hw, - union nl_packet *packet, - unsigned short len) -{ - unsigned int protocol = packet->hdr.protocol; - unsigned int address = packet->hdr.address; - unsigned int header_length; - unsigned char *data; - unsigned int data_len; - int is_last = packet->hdr.packet_rank & NL_LAST_PACKET; - - if (packet->hdr.packet_rank & NL_FIRST_PACKET) - header_length = NL_FIRST_PACKET_HEADER_SIZE; - else - header_length = NL_FOLLOWING_PACKET_HEADER_SIZE; - - data = packet->rawpkt + header_length; - data_len = len - header_length; - switch (protocol) { - case TL_PROTOCOLID_COM_DATA: - case TL_PROTOCOLID_COM_CTRL: - queue_received_packet(hw, protocol, address, data, data_len, - is_last); - break; - case TL_PROTOCOLID_SETUP: - handle_received_SETUP_packet(hw, address, data, data_len, - is_last); - break; - } -} - -static void acknowledge_data_read(struct ipw_hardware *hw) -{ - if (hw->hw_version == HW_VERSION_1) - outw(DCR_RXDONE, hw->base_port + IODCR); - else - writew(MEMRX_PCINTACKK, - &hw->memory_info_regs->memreg_pc_interrupt_ack); -} - -/* - * Retrieve a packet from the IPW hardware. - */ -static void do_receive_packet(struct ipw_hardware *hw) -{ - unsigned len; - unsigned int i; - unsigned char pkt[LL_MTU_MAX]; - - start_timing(); - - if (hw->hw_version == HW_VERSION_1) { - len = inw(hw->base_port + IODRR); - if (len > hw->ll_mtu) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": received a packet of %u bytes - " - "longer than the MTU!\n", len); - outw(DCR_RXDONE | DCR_RXRESET, hw->base_port + IODCR); - return; - } - - for (i = 0; i < len; i += 2) { - __le16 raw_data = inw(hw->base_port + IODRR); - unsigned short data = le16_to_cpu(raw_data); - - pkt[i] = (unsigned char) data; - pkt[i + 1] = (unsigned char) (data >> 8); - } - } else { - len = inw(hw->base_port + IODMADPR); - if (len > hw->ll_mtu) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": received a packet of %u bytes - " - "longer than the MTU!\n", len); - writew(MEMRX_PCINTACKK, - &hw->memory_info_regs->memreg_pc_interrupt_ack); - return; - } - - for (i = 0; i < len; i += 2) { - __le16 raw_data = inw(hw->base_port + IODMADPR); - unsigned short data = le16_to_cpu(raw_data); - - pkt[i] = (unsigned char) data; - pkt[i + 1] = (unsigned char) (data >> 8); - } - - while ((i & 3) != 2) { - inw(hw->base_port + IODMADPR); - i += 2; - } - } - - acknowledge_data_read(hw); - - if (ipwireless_debug) - dump_data_bytes("recv", pkt, len); - - handle_received_packet(hw, (union nl_packet *) pkt, len); - - end_read_timing(len); -} - -static int get_current_packet_priority(struct ipw_hardware *hw) -{ - /* - * If we're initializing, don't send anything of higher priority than - * PRIO_SETUP. The network layer therefore need not care about - * hardware initialization - any of its stuff will simply be queued - * until setup is complete. - */ - return (hw->to_setup || hw->initializing - ? PRIO_SETUP + 1 : - NL_NUM_OF_PRIORITIES); -} - -/* - * return 1 if something has been received from hw - */ -static int get_packets_from_hw(struct ipw_hardware *hw) -{ - int received = 0; - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - while (hw->rx_ready && !hw->blocking_rx) { - received = 1; - hw->rx_ready--; - spin_unlock_irqrestore(&hw->spinlock, flags); - - do_receive_packet(hw); - - spin_lock_irqsave(&hw->spinlock, flags); - } - spin_unlock_irqrestore(&hw->spinlock, flags); - - return received; -} - -/* - * Send pending packet up to given priority, prioritize SETUP data until - * hardware is fully setup. - * - * return 1 if more packets can be sent - */ -static int send_pending_packet(struct ipw_hardware *hw, int priority_limit) -{ - int more_to_send = 0; - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - if (hw->tx_queued && hw->tx_ready != 0) { - int priority; - struct ipw_tx_packet *packet = NULL; - - hw->tx_ready--; - - /* Pick a packet */ - for (priority = 0; priority < priority_limit; priority++) { - if (!list_empty(&hw->tx_queue[priority])) { - packet = list_first_entry( - &hw->tx_queue[priority], - struct ipw_tx_packet, - queue); - - list_del(&packet->queue); - - break; - } - } - if (!packet) { - hw->tx_queued = 0; - spin_unlock_irqrestore(&hw->spinlock, flags); - return 0; - } - spin_unlock_irqrestore(&hw->spinlock, flags); - - /* Send */ - do_send_packet(hw, packet); - - /* Check if more to send */ - spin_lock_irqsave(&hw->spinlock, flags); - for (priority = 0; priority < priority_limit; priority++) - if (!list_empty(&hw->tx_queue[priority])) { - more_to_send = 1; - break; - } - - if (!more_to_send) - hw->tx_queued = 0; - } - spin_unlock_irqrestore(&hw->spinlock, flags); - - return more_to_send; -} - -/* - * Send and receive all queued packets. - */ -static void ipwireless_do_tasklet(unsigned long hw_) -{ - struct ipw_hardware *hw = (struct ipw_hardware *) hw_; - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - if (hw->shutting_down) { - spin_unlock_irqrestore(&hw->spinlock, flags); - return; - } - - if (hw->to_setup == 1) { - /* - * Initial setup data sent to hardware - */ - hw->to_setup = 2; - spin_unlock_irqrestore(&hw->spinlock, flags); - - ipw_setup_hardware(hw); - ipw_send_setup_packet(hw); - - send_pending_packet(hw, PRIO_SETUP + 1); - get_packets_from_hw(hw); - } else { - int priority_limit = get_current_packet_priority(hw); - int again; - - spin_unlock_irqrestore(&hw->spinlock, flags); - - do { - again = send_pending_packet(hw, priority_limit); - again |= get_packets_from_hw(hw); - } while (again); - } -} - -/* - * return true if the card is physically present. - */ -static int is_card_present(struct ipw_hardware *hw) -{ - if (hw->hw_version == HW_VERSION_1) - return inw(hw->base_port + IOIR) != 0xFFFF; - else - return readl(&hw->memory_info_regs->memreg_card_present) == - CARD_PRESENT_VALUE; -} - -static irqreturn_t ipwireless_handle_v1_interrupt(int irq, - struct ipw_hardware *hw) -{ - unsigned short irqn; - - irqn = inw(hw->base_port + IOIR); - - /* Check if card is present */ - if (irqn == 0xFFFF) - return IRQ_NONE; - else if (irqn != 0) { - unsigned short ack = 0; - unsigned long flags; - - /* Transmit complete. */ - if (irqn & IR_TXINTR) { - ack |= IR_TXINTR; - spin_lock_irqsave(&hw->spinlock, flags); - hw->tx_ready++; - spin_unlock_irqrestore(&hw->spinlock, flags); - } - /* Received data */ - if (irqn & IR_RXINTR) { - ack |= IR_RXINTR; - spin_lock_irqsave(&hw->spinlock, flags); - hw->rx_ready++; - spin_unlock_irqrestore(&hw->spinlock, flags); - } - if (ack != 0) { - outw(ack, hw->base_port + IOIR); - tasklet_schedule(&hw->tasklet); - } - return IRQ_HANDLED; - } - return IRQ_NONE; -} - -static void acknowledge_pcmcia_interrupt(struct ipw_hardware *hw) -{ - unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status); - - csr &= 0xfffd; - writew(csr, &hw->memregs_CCR->reg_config_and_status); -} - -static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq, - struct ipw_hardware *hw) -{ - int tx = 0; - int rx = 0; - int rx_repeat = 0; - int try_mem_tx_old; - unsigned long flags; - - do { - - unsigned short memtx = readw(hw->memreg_tx); - unsigned short memtx_serial; - unsigned short memrxdone = - readw(&hw->memory_info_regs->memreg_rx_done); - - try_mem_tx_old = 0; - - /* check whether the interrupt was generated by ipwireless card */ - if (!(memtx & MEMTX_TX) && !(memrxdone & MEMRX_RX_DONE)) { - - /* check if the card uses memreg_tx_old register */ - if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { - memtx = readw(&hw->memory_info_regs->memreg_tx_old); - if (memtx & MEMTX_TX) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": Using memreg_tx_old\n"); - hw->memreg_tx = - &hw->memory_info_regs->memreg_tx_old; - } else { - return IRQ_NONE; - } - } else { - return IRQ_NONE; - } - } - - /* - * See if the card is physically present. Note that while it is - * powering up, it appears not to be present. - */ - if (!is_card_present(hw)) { - acknowledge_pcmcia_interrupt(hw); - return IRQ_HANDLED; - } - - memtx_serial = memtx & (unsigned short) 0xff00; - if (memtx & MEMTX_TX) { - writew(memtx_serial, hw->memreg_tx); - - if (hw->serial_number_detected) { - if (memtx_serial != hw->last_memtx_serial) { - hw->last_memtx_serial = memtx_serial; - spin_lock_irqsave(&hw->spinlock, flags); - hw->rx_ready++; - spin_unlock_irqrestore(&hw->spinlock, flags); - rx = 1; - } else - /* Ignore 'Timer Recovery' duplicates. */ - rx_repeat = 1; - } else { - /* - * If a non-zero serial number is seen, then enable - * serial number checking. - */ - if (memtx_serial != 0) { - hw->serial_number_detected = 1; - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME - ": memreg_tx serial num detected\n"); - - spin_lock_irqsave(&hw->spinlock, flags); - hw->rx_ready++; - spin_unlock_irqrestore(&hw->spinlock, flags); - } - rx = 1; - } - } - if (memrxdone & MEMRX_RX_DONE) { - writew(0, &hw->memory_info_regs->memreg_rx_done); - spin_lock_irqsave(&hw->spinlock, flags); - hw->tx_ready++; - spin_unlock_irqrestore(&hw->spinlock, flags); - tx = 1; - } - if (tx) - writew(MEMRX_PCINTACKK, - &hw->memory_info_regs->memreg_pc_interrupt_ack); - - acknowledge_pcmcia_interrupt(hw); - - if (tx || rx) - tasklet_schedule(&hw->tasklet); - else if (!rx_repeat) { - if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { - if (hw->serial_number_detected) - printk(KERN_WARNING IPWIRELESS_PCCARD_NAME - ": spurious interrupt - new_tx mode\n"); - else { - printk(KERN_WARNING IPWIRELESS_PCCARD_NAME - ": no valid memreg_tx value - " - "switching to the old memreg_tx\n"); - hw->memreg_tx = - &hw->memory_info_regs->memreg_tx_old; - try_mem_tx_old = 1; - } - } else - printk(KERN_WARNING IPWIRELESS_PCCARD_NAME - ": spurious interrupt - old_tx mode\n"); - } - - } while (try_mem_tx_old == 1); - - return IRQ_HANDLED; -} - -irqreturn_t ipwireless_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct ipw_hardware *hw = dev_id; - - if (hw->hw_version == HW_VERSION_1) - return ipwireless_handle_v1_interrupt(irq, hw); - else - return ipwireless_handle_v2_v3_interrupt(irq, hw); -} - -static void flush_packets_to_hw(struct ipw_hardware *hw) -{ - int priority_limit; - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - priority_limit = get_current_packet_priority(hw); - spin_unlock_irqrestore(&hw->spinlock, flags); - - while (send_pending_packet(hw, priority_limit)); -} - -static void send_packet(struct ipw_hardware *hw, int priority, - struct ipw_tx_packet *packet) -{ - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - list_add_tail(&packet->queue, &hw->tx_queue[priority]); - hw->tx_queued = 1; - spin_unlock_irqrestore(&hw->spinlock, flags); - - flush_packets_to_hw(hw); -} - -/* Create data packet, non-atomic allocation */ -static void *alloc_data_packet(int data_size, - unsigned char dest_addr, - unsigned char protocol) -{ - struct ipw_tx_packet *packet = kzalloc( - sizeof(struct ipw_tx_packet) + data_size, - GFP_ATOMIC); - - if (!packet) - return NULL; - - INIT_LIST_HEAD(&packet->queue); - packet->dest_addr = dest_addr; - packet->protocol = protocol; - packet->length = data_size; - - return packet; -} - -static void *alloc_ctrl_packet(int header_size, - unsigned char dest_addr, - unsigned char protocol, - unsigned char sig_no) -{ - /* - * sig_no is located right after ipw_tx_packet struct in every - * CTRL or SETUP packets, we can use ipw_control_packet as a - * common struct - */ - struct ipw_control_packet *packet = kzalloc(header_size, GFP_ATOMIC); - - if (!packet) - return NULL; - - INIT_LIST_HEAD(&packet->header.queue); - packet->header.dest_addr = dest_addr; - packet->header.protocol = protocol; - packet->header.length = header_size - sizeof(struct ipw_tx_packet); - packet->body.sig_no = sig_no; - - return packet; -} - -int ipwireless_send_packet(struct ipw_hardware *hw, unsigned int channel_idx, - unsigned char *data, unsigned int length, - void (*callback) (void *cb, unsigned int length), - void *callback_data) -{ - struct ipw_tx_packet *packet; - - packet = alloc_data_packet(length, - (unsigned char) (channel_idx + 1), - TL_PROTOCOLID_COM_DATA); - if (!packet) - return -ENOMEM; - packet->packet_callback = callback; - packet->callback_data = callback_data; - memcpy((unsigned char *) packet + - sizeof(struct ipw_tx_packet), data, length); - - send_packet(hw, PRIO_DATA, packet); - return 0; -} - -static int set_control_line(struct ipw_hardware *hw, int prio, - unsigned int channel_idx, int line, int state) -{ - struct ipw_control_packet *packet; - int protocolid = TL_PROTOCOLID_COM_CTRL; - - if (prio == PRIO_SETUP) - protocolid = TL_PROTOCOLID_SETUP; - - packet = alloc_ctrl_packet(sizeof(struct ipw_control_packet), - (unsigned char) (channel_idx + 1), - protocolid, line); - if (!packet) - return -ENOMEM; - packet->header.length = sizeof(struct ipw_control_packet_body); - packet->body.value = (unsigned char) (state == 0 ? 0 : 1); - send_packet(hw, prio, &packet->header); - return 0; -} - - -static int set_DTR(struct ipw_hardware *hw, int priority, - unsigned int channel_idx, int state) -{ - if (state != 0) - hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_DTR; - else - hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_DTR; - - return set_control_line(hw, priority, channel_idx, COMCTRL_DTR, state); -} - -static int set_RTS(struct ipw_hardware *hw, int priority, - unsigned int channel_idx, int state) -{ - if (state != 0) - hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_RTS; - else - hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_RTS; - - return set_control_line(hw, priority, channel_idx, COMCTRL_RTS, state); -} - -int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx, - int state) -{ - return set_DTR(hw, PRIO_CTRL, channel_idx, state); -} - -int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx, - int state) -{ - return set_RTS(hw, PRIO_CTRL, channel_idx, state); -} - -struct ipw_setup_get_version_query_packet { - struct ipw_tx_packet header; - struct tl_setup_get_version_qry body; -}; - -struct ipw_setup_config_packet { - struct ipw_tx_packet header; - struct tl_setup_config_msg body; -}; - -struct ipw_setup_config_done_packet { - struct ipw_tx_packet header; - struct tl_setup_config_done_msg body; -}; - -struct ipw_setup_open_packet { - struct ipw_tx_packet header; - struct tl_setup_open_msg body; -}; - -struct ipw_setup_info_packet { - struct ipw_tx_packet header; - struct tl_setup_info_msg body; -}; - -struct ipw_setup_reboot_msg_ack { - struct ipw_tx_packet header; - struct TlSetupRebootMsgAck body; -}; - -/* This handles the actual initialization of the card */ -static void __handle_setup_get_version_rsp(struct ipw_hardware *hw) -{ - struct ipw_setup_config_packet *config_packet; - struct ipw_setup_config_done_packet *config_done_packet; - struct ipw_setup_open_packet *open_packet; - struct ipw_setup_info_packet *info_packet; - int port; - unsigned int channel_idx; - - /* generate config packet */ - for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) { - config_packet = alloc_ctrl_packet( - sizeof(struct ipw_setup_config_packet), - ADDR_SETUP_PROT, - TL_PROTOCOLID_SETUP, - TL_SETUP_SIGNO_CONFIG_MSG); - if (!config_packet) - goto exit_nomem; - config_packet->header.length = sizeof(struct tl_setup_config_msg); - config_packet->body.port_no = port; - config_packet->body.prio_data = PRIO_DATA; - config_packet->body.prio_ctrl = PRIO_CTRL; - send_packet(hw, PRIO_SETUP, &config_packet->header); - } - config_done_packet = alloc_ctrl_packet( - sizeof(struct ipw_setup_config_done_packet), - ADDR_SETUP_PROT, - TL_PROTOCOLID_SETUP, - TL_SETUP_SIGNO_CONFIG_DONE_MSG); - if (!config_done_packet) - goto exit_nomem; - config_done_packet->header.length = sizeof(struct tl_setup_config_done_msg); - send_packet(hw, PRIO_SETUP, &config_done_packet->header); - - /* generate open packet */ - for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) { - open_packet = alloc_ctrl_packet( - sizeof(struct ipw_setup_open_packet), - ADDR_SETUP_PROT, - TL_PROTOCOLID_SETUP, - TL_SETUP_SIGNO_OPEN_MSG); - if (!open_packet) - goto exit_nomem; - open_packet->header.length = sizeof(struct tl_setup_open_msg); - open_packet->body.port_no = port; - send_packet(hw, PRIO_SETUP, &open_packet->header); - } - for (channel_idx = 0; - channel_idx < NL_NUM_OF_ADDRESSES; channel_idx++) { - int ret; - - ret = set_DTR(hw, PRIO_SETUP, channel_idx, - (hw->control_lines[channel_idx] & - IPW_CONTROL_LINE_DTR) != 0); - if (ret) { - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": error setting DTR (%d)\n", ret); - return; - } - - set_RTS(hw, PRIO_SETUP, channel_idx, - (hw->control_lines [channel_idx] & - IPW_CONTROL_LINE_RTS) != 0); - if (ret) { - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": error setting RTS (%d)\n", ret); - return; - } - } - /* - * For NDIS we assume that we are using sync PPP frames, for COM async. - * This driver uses NDIS mode too. We don't bother with translation - * from async -> sync PPP. - */ - info_packet = alloc_ctrl_packet(sizeof(struct ipw_setup_info_packet), - ADDR_SETUP_PROT, - TL_PROTOCOLID_SETUP, - TL_SETUP_SIGNO_INFO_MSG); - if (!info_packet) - goto exit_nomem; - info_packet->header.length = sizeof(struct tl_setup_info_msg); - info_packet->body.driver_type = NDISWAN_DRIVER; - info_packet->body.major_version = NDISWAN_DRIVER_MAJOR_VERSION; - info_packet->body.minor_version = NDISWAN_DRIVER_MINOR_VERSION; - send_packet(hw, PRIO_SETUP, &info_packet->header); - - /* Initialization is now complete, so we clear the 'to_setup' flag */ - hw->to_setup = 0; - - return; - -exit_nomem: - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": not enough memory to alloc control packet\n"); - hw->to_setup = -1; -} - -static void handle_setup_get_version_rsp(struct ipw_hardware *hw, - unsigned char vers_no) -{ - del_timer(&hw->setup_timer); - hw->initializing = 0; - printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": card is ready.\n"); - - if (vers_no == TL_SETUP_VERSION) - __handle_setup_get_version_rsp(hw); - else - printk(KERN_ERR - IPWIRELESS_PCCARD_NAME - ": invalid hardware version no %u\n", - (unsigned int) vers_no); -} - -static void ipw_send_setup_packet(struct ipw_hardware *hw) -{ - struct ipw_setup_get_version_query_packet *ver_packet; - - ver_packet = alloc_ctrl_packet( - sizeof(struct ipw_setup_get_version_query_packet), - ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, - TL_SETUP_SIGNO_GET_VERSION_QRY); - ver_packet->header.length = sizeof(struct tl_setup_get_version_qry); - - /* - * Response is handled in handle_received_SETUP_packet - */ - send_packet(hw, PRIO_SETUP, &ver_packet->header); -} - -static void handle_received_SETUP_packet(struct ipw_hardware *hw, - unsigned int address, - unsigned char *data, int len, - int is_last) -{ - union ipw_setup_rx_msg *rx_msg = (union ipw_setup_rx_msg *) data; - - if (address != ADDR_SETUP_PROT) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": setup packet has bad address %d\n", address); - return; - } - - switch (rx_msg->sig_no) { - case TL_SETUP_SIGNO_GET_VERSION_RSP: - if (hw->to_setup) - handle_setup_get_version_rsp(hw, - rx_msg->version_rsp_msg.version); - break; - - case TL_SETUP_SIGNO_OPEN_MSG: - if (ipwireless_debug) { - unsigned int channel_idx = rx_msg->open_msg.port_no - 1; - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": OPEN_MSG [channel %u] reply received\n", - channel_idx); - } - break; - - case TL_SETUP_SIGNO_INFO_MSG_ACK: - if (ipwireless_debug) - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME - ": card successfully configured as NDISWAN\n"); - break; - - case TL_SETUP_SIGNO_REBOOT_MSG: - if (hw->to_setup) - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME - ": Setup not completed - ignoring reboot msg\n"); - else { - struct ipw_setup_reboot_msg_ack *packet; - - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME - ": Acknowledging REBOOT message\n"); - packet = alloc_ctrl_packet( - sizeof(struct ipw_setup_reboot_msg_ack), - ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, - TL_SETUP_SIGNO_REBOOT_MSG_ACK); - packet->header.length = - sizeof(struct TlSetupRebootMsgAck); - send_packet(hw, PRIO_SETUP, &packet->header); - if (hw->reboot_callback) - hw->reboot_callback(hw->reboot_callback_data); - } - break; - - default: - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": unknown setup message %u received\n", - (unsigned int) rx_msg->sig_no); - } -} - -static void do_close_hardware(struct ipw_hardware *hw) -{ - unsigned int irqn; - - if (hw->hw_version == HW_VERSION_1) { - /* Disable TX and RX interrupts. */ - outw(0, hw->base_port + IOIER); - - /* Acknowledge any outstanding interrupt requests */ - irqn = inw(hw->base_port + IOIR); - if (irqn & IR_TXINTR) - outw(IR_TXINTR, hw->base_port + IOIR); - if (irqn & IR_RXINTR) - outw(IR_RXINTR, hw->base_port + IOIR); - - synchronize_irq(hw->irq); - } -} - -struct ipw_hardware *ipwireless_hardware_create(void) -{ - int i; - struct ipw_hardware *hw = - kzalloc(sizeof(struct ipw_hardware), GFP_KERNEL); - - if (!hw) - return NULL; - - hw->irq = -1; - hw->initializing = 1; - hw->tx_ready = 1; - hw->rx_bytes_queued = 0; - hw->rx_pool_size = 0; - hw->last_memtx_serial = (unsigned short) 0xffff; - for (i = 0; i < NL_NUM_OF_PRIORITIES; i++) - INIT_LIST_HEAD(&hw->tx_queue[i]); - - INIT_LIST_HEAD(&hw->rx_queue); - INIT_LIST_HEAD(&hw->rx_pool); - spin_lock_init(&hw->spinlock); - tasklet_init(&hw->tasklet, ipwireless_do_tasklet, (unsigned long) hw); - INIT_WORK(&hw->work_rx, ipw_receive_data_work); - setup_timer(&hw->setup_timer, ipwireless_setup_timer, - (unsigned long) hw); - - return hw; -} - -void ipwireless_init_hardware_v1(struct ipw_hardware *hw, - unsigned int base_port, - void __iomem *attr_memory, - void __iomem *common_memory, - int is_v2_card, - void (*reboot_callback) (void *data), - void *reboot_callback_data) -{ - if (hw->removed) { - hw->removed = 0; - enable_irq(hw->irq); - } - hw->base_port = base_port; - hw->hw_version = is_v2_card ? HW_VERSION_2 : HW_VERSION_1; - hw->ll_mtu = hw->hw_version == HW_VERSION_1 ? LL_MTU_V1 : LL_MTU_V2; - hw->memregs_CCR = (struct MEMCCR __iomem *) - ((unsigned short __iomem *) attr_memory + 0x200); - hw->memory_info_regs = (struct MEMINFREG __iomem *) common_memory; - hw->memreg_tx = &hw->memory_info_regs->memreg_tx_new; - hw->reboot_callback = reboot_callback; - hw->reboot_callback_data = reboot_callback_data; -} - -void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw) -{ - hw->initializing = 1; - hw->init_loops = 0; - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": waiting for card to start up...\n"); - ipwireless_setup_timer((unsigned long) hw); -} - -static void ipwireless_setup_timer(unsigned long data) -{ - struct ipw_hardware *hw = (struct ipw_hardware *) data; - - hw->init_loops++; - - if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY && - hw->hw_version == HW_VERSION_2 && - hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": failed to startup using TX2, trying TX\n"); - - hw->memreg_tx = &hw->memory_info_regs->memreg_tx_old; - hw->init_loops = 0; - } - /* Give up after a certain number of retries */ - if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": card failed to start up!\n"); - hw->initializing = 0; - } else { - /* Do not attempt to write to the board if it is not present. */ - if (is_card_present(hw)) { - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - hw->to_setup = 1; - hw->tx_ready = 1; - spin_unlock_irqrestore(&hw->spinlock, flags); - tasklet_schedule(&hw->tasklet); - } - - mod_timer(&hw->setup_timer, - jiffies + msecs_to_jiffies(TL_SETUP_VERSION_QRY_TMO)); - } -} - -/* - * Stop any interrupts from executing so that, once this function returns, - * other layers of the driver can be sure they won't get any more callbacks. - * Thus must be called on a proper process context. - */ -void ipwireless_stop_interrupts(struct ipw_hardware *hw) -{ - if (!hw->shutting_down) { - /* Tell everyone we are going down. */ - hw->shutting_down = 1; - del_timer(&hw->setup_timer); - - /* Prevent the hardware from sending any more interrupts */ - do_close_hardware(hw); - } -} - -void ipwireless_hardware_free(struct ipw_hardware *hw) -{ - int i; - struct ipw_rx_packet *rp, *rq; - struct ipw_tx_packet *tp, *tq; - - ipwireless_stop_interrupts(hw); - - flush_scheduled_work(); - - for (i = 0; i < NL_NUM_OF_ADDRESSES; i++) - if (hw->packet_assembler[i] != NULL) - kfree(hw->packet_assembler[i]); - - for (i = 0; i < NL_NUM_OF_PRIORITIES; i++) - list_for_each_entry_safe(tp, tq, &hw->tx_queue[i], queue) { - list_del(&tp->queue); - kfree(tp); - } - - list_for_each_entry_safe(rp, rq, &hw->rx_queue, queue) { - list_del(&rp->queue); - kfree(rp); - } - - list_for_each_entry_safe(rp, rq, &hw->rx_pool, queue) { - list_del(&rp->queue); - kfree(rp); - } - kfree(hw); -} - -/* - * Associate the specified network with this hardware, so it will receive events - * from it. - */ -void ipwireless_associate_network(struct ipw_hardware *hw, - struct ipw_network *network) -{ - hw->network = network; -} diff --git a/trunk/drivers/char/pcmcia/ipwireless/hardware.h b/trunk/drivers/char/pcmcia/ipwireless/hardware.h deleted file mode 100644 index c83190ffb0e7..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/hardware.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#ifndef _IPWIRELESS_CS_HARDWARE_H_ -#define _IPWIRELESS_CS_HARDWARE_H_ - -#include -#include -#include - -#define IPW_CONTROL_LINE_CTS 0x0001 -#define IPW_CONTROL_LINE_DCD 0x0002 -#define IPW_CONTROL_LINE_DSR 0x0004 -#define IPW_CONTROL_LINE_RI 0x0008 -#define IPW_CONTROL_LINE_DTR 0x0010 -#define IPW_CONTROL_LINE_RTS 0x0020 - -struct ipw_hardware; -struct ipw_network; - -struct ipw_hardware *ipwireless_hardware_create(void); -void ipwireless_hardware_free(struct ipw_hardware *hw); -irqreturn_t ipwireless_interrupt(int irq, void *dev_id, struct pt_regs *regs); -int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx, - int state); -int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx, - int state); -int ipwireless_send_packet(struct ipw_hardware *hw, - unsigned int channel_idx, - unsigned char *data, - unsigned int length, - void (*packet_sent_callback) (void *cb, - unsigned int length), - void *sent_cb_data); -void ipwireless_associate_network(struct ipw_hardware *hw, - struct ipw_network *net); -void ipwireless_stop_interrupts(struct ipw_hardware *hw); -void ipwireless_init_hardware_v1(struct ipw_hardware *hw, - unsigned int base_port, - void __iomem *attr_memory, - void __iomem *common_memory, - int is_v2_card, - void (*reboot_cb) (void *data), - void *reboot_cb_data); -void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw); -void ipwireless_sleep(unsigned int tenths); -int ipwireless_dump_hardware_state(char *p, size_t limit, - struct ipw_hardware *hw); - -#endif diff --git a/trunk/drivers/char/pcmcia/ipwireless/main.c b/trunk/drivers/char/pcmcia/ipwireless/main.c deleted file mode 100644 index 00c7f8407e3e..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/main.c +++ /dev/null @@ -1,501 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#include "hardware.h" -#include "network.h" -#include "main.h" -#include "tty.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -static struct pcmcia_device_id ipw_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100), - PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, ipw_ids); - -static void ipwireless_detach(struct pcmcia_device *link); - -/* - * Module params - */ -/* Debug mode: more verbose, print sent/recv bytes */ -int ipwireless_debug; -int ipwireless_loopback; -int ipwireless_out_queue = 1; - -module_param_named(debug, ipwireless_debug, int, 0); -module_param_named(loopback, ipwireless_loopback, int, 0); -module_param_named(out_queue, ipwireless_out_queue, int, 0); -MODULE_PARM_DESC(debug, "switch on debug messages [0]"); -MODULE_PARM_DESC(loopback, - "debug: enable ras_raw channel [0]"); -MODULE_PARM_DESC(out_queue, "debug: set size of outgoing queue [1]"); - -/* Executes in process context. */ -static void signalled_reboot_work(struct work_struct *work_reboot) -{ - struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev, - work_reboot); - struct pcmcia_device *link = ipw->link; - int ret = pccard_reset_card(link->socket); - - if (ret != CS_SUCCESS) - cs_error(link, ResetCard, ret); -} - -static void signalled_reboot_callback(void *callback_data) -{ - struct ipw_dev *ipw = (struct ipw_dev *) callback_data; - - /* Delegate to process context. */ - schedule_work(&ipw->work_reboot); -} - -static int config_ipwireless(struct ipw_dev *ipw) -{ - struct pcmcia_device *link = ipw->link; - int ret; - config_info_t conf; - tuple_t tuple; - unsigned short buf[64]; - cisparse_t parse; - unsigned short cor_value; - win_req_t request_attr_memory; - win_req_t request_common_memory; - memreq_t memreq_attr_memory; - memreq_t memreq_common_memory; - - ipw->is_v2_card = 0; - - tuple.Attributes = 0; - tuple.TupleData = (cisdata_t *) buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - - tuple.DesiredTuple = RETURN_FIRST_TUPLE; - - ret = pcmcia_get_first_tuple(link, &tuple); - - while (ret == 0) { - ret = pcmcia_get_tuple_data(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetTupleData, ret); - goto exit0; - } - ret = pcmcia_get_next_tuple(link, &tuple); - } - - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - - ret = pcmcia_get_first_tuple(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetFirstTuple, ret); - goto exit0; - } - - ret = pcmcia_get_tuple_data(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetTupleData, ret); - goto exit0; - } - - ret = pcmcia_parse_tuple(link, &tuple, &parse); - - if (ret != CS_SUCCESS) { - cs_error(link, ParseTuple, ret); - goto exit0; - } - - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - link->io.BasePort1 = parse.cftable_entry.io.win[0].base; - link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; - link->io.IOAddrLines = 16; - - link->irq.IRQInfo1 = parse.cftable_entry.irq.IRQInfo1; - - /* 0x40 causes it to generate level mode interrupts. */ - /* 0x04 enables IREQ pin. */ - cor_value = parse.cftable_entry.index | 0x44; - link->conf.ConfigIndex = cor_value; - - /* IRQ and I/O settings */ - tuple.DesiredTuple = CISTPL_CONFIG; - - ret = pcmcia_get_first_tuple(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetFirstTuple, ret); - goto exit0; - } - - ret = pcmcia_get_tuple_data(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetTupleData, ret); - goto exit0; - } - - ret = pcmcia_parse_tuple(link, &tuple, &parse); - - if (ret != CS_SUCCESS) { - cs_error(link, GetTupleData, ret); - goto exit0; - } - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - link->conf.IntType = INT_MEMORY_AND_IO; - - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - link->irq.Handler = ipwireless_interrupt; - link->irq.Instance = ipw->hardware; - - ret = pcmcia_request_io(link, &link->io); - - if (ret != CS_SUCCESS) { - cs_error(link, RequestIO, ret); - goto exit0; - } - - /* memory settings */ - - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - - ret = pcmcia_get_first_tuple(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetFirstTuple, ret); - goto exit1; - } - - ret = pcmcia_get_tuple_data(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetTupleData, ret); - goto exit1; - } - - ret = pcmcia_parse_tuple(link, &tuple, &parse); - - if (ret != CS_SUCCESS) { - cs_error(link, ParseTuple, ret); - goto exit1; - } - - if (parse.cftable_entry.mem.nwin > 0) { - request_common_memory.Attributes = - WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; - request_common_memory.Base = - parse.cftable_entry.mem.win[0].host_addr; - request_common_memory.Size = parse.cftable_entry.mem.win[0].len; - if (request_common_memory.Size < 0x1000) - request_common_memory.Size = 0x1000; - request_common_memory.AccessSpeed = 0; - - ret = pcmcia_request_window(&link, &request_common_memory, - &ipw->handle_common_memory); - - if (ret != CS_SUCCESS) { - cs_error(link, RequestWindow, ret); - goto exit1; - } - - memreq_common_memory.CardOffset = - parse.cftable_entry.mem.win[0].card_addr; - memreq_common_memory.Page = 0; - - ret = pcmcia_map_mem_page(ipw->handle_common_memory, - &memreq_common_memory); - - if (ret != CS_SUCCESS) { - cs_error(link, MapMemPage, ret); - goto exit1; - } - - ipw->is_v2_card = - parse.cftable_entry.mem.win[0].len == 0x100; - - ipw->common_memory = ioremap(request_common_memory.Base, - request_common_memory.Size); - - request_attr_memory.Attributes = - WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE; - request_attr_memory.Base = 0; - request_attr_memory.Size = 0; /* this used to be 0x1000 */ - request_attr_memory.AccessSpeed = 0; - - ret = pcmcia_request_window(&link, &request_attr_memory, - &ipw->handle_attr_memory); - - if (ret != CS_SUCCESS) { - cs_error(link, RequestWindow, ret); - goto exit2; - } - - memreq_attr_memory.CardOffset = 0; - memreq_attr_memory.Page = 0; - - ret = pcmcia_map_mem_page(ipw->handle_attr_memory, - &memreq_attr_memory); - - if (ret != CS_SUCCESS) { - cs_error(link, MapMemPage, ret); - goto exit2; - } - - ipw->attr_memory = ioremap(request_attr_memory.Base, - request_attr_memory.Size); - } - - INIT_WORK(&ipw->work_reboot, signalled_reboot_work); - - ipwireless_init_hardware_v1(ipw->hardware, link->io.BasePort1, - ipw->attr_memory, ipw->common_memory, - ipw->is_v2_card, signalled_reboot_callback, - ipw); - - ret = pcmcia_request_irq(link, &link->irq); - - if (ret != CS_SUCCESS) { - cs_error(link, RequestIRQ, ret); - goto exit3; - } - - /* Look up current Vcc */ - - ret = pcmcia_get_configuration_info(link, &conf); - - if (ret != CS_SUCCESS) { - cs_error(link, GetConfigurationInfo, ret); - goto exit4; - } - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n", - ipw->is_v2_card ? "V2/V3" : "V1"); - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": I/O ports 0x%04x-0x%04x, irq %d\n", - (unsigned int) link->io.BasePort1, - (unsigned int) (link->io.BasePort1 + - link->io.NumPorts1 - 1), - (unsigned int) link->irq.AssignedIRQ); - if (ipw->attr_memory && ipw->common_memory) - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": attr memory 0x%08lx-0x%08lx, " - "common memory 0x%08lx-0x%08lx\n", - request_attr_memory.Base, - request_attr_memory.Base - + request_attr_memory.Size - 1, - request_common_memory.Base, - request_common_memory.Base - + request_common_memory.Size - 1); - - ipw->network = ipwireless_network_create(ipw->hardware); - if (!ipw->network) - goto exit3; - - ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network, - ipw->nodes); - if (!ipw->tty) - goto exit3; - - ipwireless_init_hardware_v2_v3(ipw->hardware); - - /* - * Do the RequestConfiguration last, because it enables interrupts. - * Then we don't get any interrupts before we're ready for them. - */ - ret = pcmcia_request_configuration(link, &link->conf); - - if (ret != CS_SUCCESS) { - cs_error(link, RequestConfiguration, ret); - goto exit4; - } - - link->dev_node = &ipw->nodes[0]; - - return 0; - -exit4: - pcmcia_disable_device(link); -exit3: - if (ipw->attr_memory) { - iounmap(ipw->attr_memory); - pcmcia_release_window(ipw->handle_attr_memory); - pcmcia_disable_device(link); - } -exit2: - if (ipw->common_memory) { - iounmap(ipw->common_memory); - pcmcia_release_window(ipw->handle_common_memory); - } -exit1: - pcmcia_disable_device(link); -exit0: - return -1; -} - -static void release_ipwireless(struct ipw_dev *ipw) -{ - struct pcmcia_device *link = ipw->link; - - pcmcia_disable_device(link); - - if (ipw->common_memory) - iounmap(ipw->common_memory); - if (ipw->attr_memory) - iounmap(ipw->attr_memory); - if (ipw->common_memory) - pcmcia_release_window(ipw->handle_common_memory); - if (ipw->attr_memory) - pcmcia_release_window(ipw->handle_attr_memory); - pcmcia_disable_device(link); -} - -/* - * ipwireless_attach() creates an "instance" of the driver, allocating - * local data structures for one device (one interface). The device - * is registered with Card Services. - * - * The pcmcia_device structure is initialized, but we don't actually - * configure the card at this point -- we wait until we receive a - * card insertion event. - */ -static int ipwireless_attach(struct pcmcia_device *link) -{ - struct ipw_dev *ipw; - int ret; - - ipw = kzalloc(sizeof(struct ipw_dev), GFP_KERNEL); - if (!ipw) - return -ENOMEM; - - ipw->link = link; - link->priv = ipw; - link->irq.Instance = ipw; - - /* Link this device into our device list. */ - link->dev_node = &ipw->nodes[0]; - - ipw->hardware = ipwireless_hardware_create(); - if (!ipw->hardware) { - kfree(ipw); - return -ENOMEM; - } - /* RegisterClient will call config_ipwireless */ - - ret = config_ipwireless(ipw); - - if (ret != 0) { - cs_error(link, RegisterClient, ret); - ipwireless_detach(link); - return ret; - } - - return 0; -} - -/* - * This deletes a driver "instance". The device is de-registered with - * Card Services. If it has been released, all local data structures - * are freed. Otherwise, the structures will be freed when the device - * is released. - */ -static void ipwireless_detach(struct pcmcia_device *link) -{ - struct ipw_dev *ipw = link->priv; - - release_ipwireless(ipw); - - /* Break the link with Card Services */ - if (link) - pcmcia_disable_device(link); - - if (ipw->tty != NULL) - ipwireless_tty_free(ipw->tty); - if (ipw->network != NULL) - ipwireless_network_free(ipw->network); - if (ipw->hardware != NULL) - ipwireless_hardware_free(ipw->hardware); - kfree(ipw); -} - -static struct pcmcia_driver me = { - .owner = THIS_MODULE, - .probe = ipwireless_attach, - .remove = ipwireless_detach, - .drv = { .name = IPWIRELESS_PCCARD_NAME }, - .id_table = ipw_ids -}; - -/* - * Module insertion : initialisation of the module. - * Register the card with cardmgr... - */ -static int __init init_ipwireless(void) -{ - int ret; - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME " " - IPWIRELESS_PCMCIA_VERSION " by " IPWIRELESS_PCMCIA_AUTHOR "\n"); - - ret = ipwireless_tty_init(); - if (ret != 0) - return ret; - - ret = pcmcia_register_driver(&me); - if (ret != 0) - ipwireless_tty_release(); - - return ret; -} - -/* - * Module removal - */ -static void __exit exit_ipwireless(void) -{ - printk(KERN_INFO IPWIRELESS_PCCARD_NAME " " - IPWIRELESS_PCMCIA_VERSION " removed\n"); - - pcmcia_unregister_driver(&me); - ipwireless_tty_release(); -} - -module_init(init_ipwireless); -module_exit(exit_ipwireless); - -MODULE_AUTHOR(IPWIRELESS_PCMCIA_AUTHOR); -MODULE_DESCRIPTION(IPWIRELESS_PCCARD_NAME " " IPWIRELESS_PCMCIA_VERSION); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/char/pcmcia/ipwireless/main.h b/trunk/drivers/char/pcmcia/ipwireless/main.h deleted file mode 100644 index 1bfdcc8d47d6..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/main.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#ifndef _IPWIRELESS_CS_H_ -#define _IPWIRELESS_CS_H_ - -#include -#include - -#include -#include -#include -#include - -#include "hardware.h" - -#define IPWIRELESS_PCCARD_NAME "ipwireless" -#define IPWIRELESS_PCMCIA_VERSION "1.1" -#define IPWIRELESS_PCMCIA_AUTHOR \ - "Stephen Blackheath, Ben Martel, Jiri Kosina and David Sterba" - -#define IPWIRELESS_TX_QUEUE_SIZE 262144 -#define IPWIRELESS_RX_QUEUE_SIZE 262144 - -#define IPWIRELESS_STATE_DEBUG - -struct ipw_hardware; -struct ipw_network; -struct ipw_tty; - -struct ipw_dev { - struct pcmcia_device *link; - int is_v2_card; - window_handle_t handle_attr_memory; - void __iomem *attr_memory; - window_handle_t handle_common_memory; - void __iomem *common_memory; - dev_node_t nodes[2]; - /* Reference to attribute memory, containing CIS data */ - void *attribute_memory; - - /* Hardware context */ - struct ipw_hardware *hardware; - /* Network layer context */ - struct ipw_network *network; - /* TTY device context */ - struct ipw_tty *tty; - struct work_struct work_reboot; -}; - -/* Module parametres */ -extern int ipwireless_debug; -extern int ipwireless_loopback; -extern int ipwireless_out_queue; - -#endif diff --git a/trunk/drivers/char/pcmcia/ipwireless/network.c b/trunk/drivers/char/pcmcia/ipwireless/network.c deleted file mode 100644 index ff35230058d3..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/network.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "network.h" -#include "hardware.h" -#include "main.h" -#include "tty.h" - -#define MAX_OUTGOING_PACKETS_QUEUED ipwireless_out_queue -#define MAX_ASSOCIATED_TTYS 2 - -#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) - -struct ipw_network { - /* Hardware context, used for calls to hardware layer. */ - struct ipw_hardware *hardware; - /* Context for kernel 'generic_ppp' functionality */ - struct ppp_channel *ppp_channel; - /* tty context connected with IPW console */ - struct ipw_tty *associated_ttys[NO_OF_IPW_CHANNELS][MAX_ASSOCIATED_TTYS]; - /* True if ppp needs waking up once we're ready to xmit */ - int ppp_blocked; - /* Number of packets queued up in hardware module. */ - int outgoing_packets_queued; - /* Spinlock to avoid interrupts during shutdown */ - spinlock_t spinlock; - struct mutex close_lock; - - /* PPP ioctl data, not actually used anywere */ - unsigned int flags; - unsigned int rbits; - u32 xaccm[8]; - u32 raccm; - int mru; - - int shutting_down; - unsigned int ras_control_lines; - - struct work_struct work_go_online; - struct work_struct work_go_offline; -}; - - -#ifdef IPWIRELESS_STATE_DEBUG -int ipwireless_dump_network_state(char *p, size_t limit, - struct ipw_network *network) -{ - return snprintf(p, limit, - "debug: ppp_blocked=%d\n" - "debug: outgoing_packets_queued=%d\n" - "debug: network.shutting_down=%d\n", - network->ppp_blocked, - network->outgoing_packets_queued, - network->shutting_down); -} -#endif - -static void notify_packet_sent(void *callback_data, unsigned int packet_length) -{ - struct ipw_network *network = callback_data; - unsigned long flags; - - spin_lock_irqsave(&network->spinlock, flags); - network->outgoing_packets_queued--; - if (network->ppp_channel != NULL) { - if (network->ppp_blocked) { - network->ppp_blocked = 0; - spin_unlock_irqrestore(&network->spinlock, flags); - ppp_output_wakeup(network->ppp_channel); - if (ipwireless_debug) - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": ppp unblocked\n"); - } else - spin_unlock_irqrestore(&network->spinlock, flags); - } else - spin_unlock_irqrestore(&network->spinlock, flags); -} - -/* - * Called by the ppp system when it has a packet to send to the hardware. - */ -static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel, - struct sk_buff *skb) -{ - struct ipw_network *network = ppp_channel->private; - unsigned long flags; - - spin_lock_irqsave(&network->spinlock, flags); - if (network->outgoing_packets_queued < MAX_OUTGOING_PACKETS_QUEUED) { - unsigned char *buf; - static unsigned char header[] = { - PPP_ALLSTATIONS, /* 0xff */ - PPP_UI, /* 0x03 */ - }; - int ret; - - network->outgoing_packets_queued++; - spin_unlock_irqrestore(&network->spinlock, flags); - - /* - * If we have the requested amount of headroom in the skb we - * were handed, then we can add the header efficiently. - */ - if (skb_headroom(skb) >= 2) { - memcpy(skb_push(skb, 2), header, 2); - ret = ipwireless_send_packet(network->hardware, - IPW_CHANNEL_RAS, skb->data, - skb->len, - notify_packet_sent, - network); - if (ret == -1) { - skb_pull(skb, 2); - return 0; - } - } else { - /* Otherwise (rarely) we do it inefficiently. */ - buf = kmalloc(skb->len + 2, GFP_ATOMIC); - if (!buf) - return 0; - memcpy(buf + 2, skb->data, skb->len); - memcpy(buf, header, 2); - ret = ipwireless_send_packet(network->hardware, - IPW_CHANNEL_RAS, buf, - skb->len + 2, - notify_packet_sent, - network); - kfree(buf); - if (ret == -1) - return 0; - } - kfree_skb(skb); - return 1; - } else { - /* - * Otherwise reject the packet, and flag that the ppp system - * needs to be unblocked once we are ready to send. - */ - network->ppp_blocked = 1; - spin_unlock_irqrestore(&network->spinlock, flags); - return 0; - } -} - -/* Handle an ioctl call that has come in via ppp. (copy of ppp_async_ioctl() */ -static int ipwireless_ppp_ioctl(struct ppp_channel *ppp_channel, - unsigned int cmd, unsigned long arg) -{ - struct ipw_network *network = ppp_channel->private; - int err, val; - u32 accm[8]; - int __user *user_arg = (int __user *) arg; - - err = -EFAULT; - switch (cmd) { - case PPPIOCGFLAGS: - val = network->flags | network->rbits; - if (put_user(val, user_arg)) - break; - err = 0; - break; - - case PPPIOCSFLAGS: - if (get_user(val, user_arg)) - break; - network->flags = val & ~SC_RCV_BITS; - network->rbits = val & SC_RCV_BITS; - err = 0; - break; - - case PPPIOCGASYNCMAP: - if (put_user(network->xaccm[0], user_arg)) - break; - err = 0; - break; - - case PPPIOCSASYNCMAP: - if (get_user(network->xaccm[0], user_arg)) - break; - err = 0; - break; - - case PPPIOCGRASYNCMAP: - if (put_user(network->raccm, user_arg)) - break; - err = 0; - break; - - case PPPIOCSRASYNCMAP: - if (get_user(network->raccm, user_arg)) - break; - err = 0; - break; - - case PPPIOCGXASYNCMAP: - if (copy_to_user((void __user *) arg, network->xaccm, - sizeof(network->xaccm))) - break; - err = 0; - break; - - case PPPIOCSXASYNCMAP: - if (copy_from_user(accm, (void __user *) arg, sizeof(accm))) - break; - accm[2] &= ~0x40000000U; /* can't escape 0x5e */ - accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */ - memcpy(network->xaccm, accm, sizeof(network->xaccm)); - err = 0; - break; - - case PPPIOCGMRU: - if (put_user(network->mru, user_arg)) - break; - err = 0; - break; - - case PPPIOCSMRU: - if (get_user(val, user_arg)) - break; - if (val < PPP_MRU) - val = PPP_MRU; - network->mru = val; - err = 0; - break; - - default: - err = -ENOTTY; - } - - return err; -} - -static struct ppp_channel_ops ipwireless_ppp_channel_ops = { - .start_xmit = ipwireless_ppp_start_xmit, - .ioctl = ipwireless_ppp_ioctl -}; - -static void do_go_online(struct work_struct *work_go_online) -{ - struct ipw_network *network = - container_of(work_go_online, struct ipw_network, - work_go_online); - unsigned long flags; - - spin_lock_irqsave(&network->spinlock, flags); - if (!network->ppp_channel) { - struct ppp_channel *channel; - - spin_unlock_irqrestore(&network->spinlock, flags); - channel = kzalloc(sizeof(struct ppp_channel), GFP_KERNEL); - if (!channel) { - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": unable to allocate PPP channel\n"); - return; - } - channel->private = network; - channel->mtu = 16384; /* Wild guess */ - channel->hdrlen = 2; - channel->ops = &ipwireless_ppp_channel_ops; - - network->flags = 0; - network->rbits = 0; - network->mru = PPP_MRU; - memset(network->xaccm, 0, sizeof(network->xaccm)); - network->xaccm[0] = ~0U; - network->xaccm[3] = 0x60000000U; - network->raccm = ~0U; - ppp_register_channel(channel); - spin_lock_irqsave(&network->spinlock, flags); - network->ppp_channel = channel; - } - spin_unlock_irqrestore(&network->spinlock, flags); -} - -static void do_go_offline(struct work_struct *work_go_offline) -{ - struct ipw_network *network = - container_of(work_go_offline, struct ipw_network, - work_go_offline); - unsigned long flags; - - mutex_lock(&network->close_lock); - spin_lock_irqsave(&network->spinlock, flags); - if (network->ppp_channel != NULL) { - struct ppp_channel *channel = network->ppp_channel; - - network->ppp_channel = NULL; - spin_unlock_irqrestore(&network->spinlock, flags); - mutex_unlock(&network->close_lock); - ppp_unregister_channel(channel); - } else { - spin_unlock_irqrestore(&network->spinlock, flags); - mutex_unlock(&network->close_lock); - } -} - -void ipwireless_network_notify_control_line_change(struct ipw_network *network, - unsigned int channel_idx, - unsigned int control_lines, - unsigned int changed_mask) -{ - int i; - - if (channel_idx == IPW_CHANNEL_RAS) - network->ras_control_lines = control_lines; - - for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) { - struct ipw_tty *tty = - network->associated_ttys[channel_idx][i]; - - /* - * If it's associated with a tty (other than the RAS channel - * when we're online), then send the data to that tty. The RAS - * channel's data is handled above - it always goes through - * ppp_generic. - */ - if (tty) - ipwireless_tty_notify_control_line_change(tty, - channel_idx, - control_lines, - changed_mask); - } -} - -/* - * Some versions of firmware stuff packets with 0xff 0x03 (PPP: ALLSTATIONS, UI) - * bytes, which are required on sent packet, but not always present on received - * packets - */ -static struct sk_buff *ipw_packet_received_skb(unsigned char *data, - unsigned int length) -{ - struct sk_buff *skb; - - if (length > 2 && data[0] == PPP_ALLSTATIONS && data[1] == PPP_UI) { - length -= 2; - data += 2; - } - - skb = dev_alloc_skb(length + 4); - skb_reserve(skb, 2); - memcpy(skb_put(skb, length), data, length); - - return skb; -} - -void ipwireless_network_packet_received(struct ipw_network *network, - unsigned int channel_idx, - unsigned char *data, - unsigned int length) -{ - int i; - unsigned long flags; - - for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) { - struct ipw_tty *tty = network->associated_ttys[channel_idx][i]; - - /* - * If it's associated with a tty (other than the RAS channel - * when we're online), then send the data to that tty. The RAS - * channel's data is handled above - it always goes through - * ppp_generic. - */ - if (tty && channel_idx == IPW_CHANNEL_RAS - && (network->ras_control_lines & - IPW_CONTROL_LINE_DCD) != 0 - && ipwireless_tty_is_modem(tty)) { - /* - * If data came in on the RAS channel and this tty is - * the modem tty, and we are online, then we send it to - * the PPP layer. - */ - mutex_lock(&network->close_lock); - spin_lock_irqsave(&network->spinlock, flags); - if (network->ppp_channel != NULL) { - struct sk_buff *skb; - - spin_unlock_irqrestore(&network->spinlock, - flags); - - /* Send the data to the ppp_generic module. */ - skb = ipw_packet_received_skb(data, length); - ppp_input(network->ppp_channel, skb); - } else - spin_unlock_irqrestore(&network->spinlock, - flags); - mutex_unlock(&network->close_lock); - } - /* Otherwise we send it out the tty. */ - else - ipwireless_tty_received(tty, data, length); - } -} - -struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw) -{ - struct ipw_network *network = - kzalloc(sizeof(struct ipw_network), GFP_ATOMIC); - - if (!network) - return NULL; - - spin_lock_init(&network->spinlock); - mutex_init(&network->close_lock); - - network->hardware = hw; - - INIT_WORK(&network->work_go_online, do_go_online); - INIT_WORK(&network->work_go_offline, do_go_offline); - - ipwireless_associate_network(hw, network); - - return network; -} - -void ipwireless_network_free(struct ipw_network *network) -{ - network->shutting_down = 1; - - ipwireless_ppp_close(network); - flush_scheduled_work(); - - ipwireless_stop_interrupts(network->hardware); - ipwireless_associate_network(network->hardware, NULL); - - kfree(network); -} - -void ipwireless_associate_network_tty(struct ipw_network *network, - unsigned int channel_idx, - struct ipw_tty *tty) -{ - int i; - - for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) - if (network->associated_ttys[channel_idx][i] == NULL) { - network->associated_ttys[channel_idx][i] = tty; - break; - } -} - -void ipwireless_disassociate_network_ttys(struct ipw_network *network, - unsigned int channel_idx) -{ - int i; - - for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) - network->associated_ttys[channel_idx][i] = NULL; -} - -void ipwireless_ppp_open(struct ipw_network *network) -{ - if (ipwireless_debug) - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": online\n"); - schedule_work(&network->work_go_online); -} - -void ipwireless_ppp_close(struct ipw_network *network) -{ - /* Disconnect from the wireless network. */ - if (ipwireless_debug) - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": offline\n"); - schedule_work(&network->work_go_offline); -} - -int ipwireless_ppp_channel_index(struct ipw_network *network) -{ - int ret = -1; - unsigned long flags; - - spin_lock_irqsave(&network->spinlock, flags); - if (network->ppp_channel != NULL) - ret = ppp_channel_index(network->ppp_channel); - spin_unlock_irqrestore(&network->spinlock, flags); - - return ret; -} - -int ipwireless_ppp_unit_number(struct ipw_network *network) -{ - int ret = -1; - unsigned long flags; - - spin_lock_irqsave(&network->spinlock, flags); - if (network->ppp_channel != NULL) - ret = ppp_unit_number(network->ppp_channel); - spin_unlock_irqrestore(&network->spinlock, flags); - - return ret; -} diff --git a/trunk/drivers/char/pcmcia/ipwireless/network.h b/trunk/drivers/char/pcmcia/ipwireless/network.h deleted file mode 100644 index b0e1e952fd14..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/network.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#ifndef _IPWIRELESS_CS_NETWORK_H_ -#define _IPWIRELESS_CS_NETWORK_H_ - -#include - -struct ipw_network; -struct ipw_tty; -struct ipw_hardware; - -/* Definitions of the different channels on the PCMCIA UE */ -#define IPW_CHANNEL_RAS 0 -#define IPW_CHANNEL_DIALLER 1 -#define IPW_CHANNEL_CONSOLE 2 -#define NO_OF_IPW_CHANNELS 5 - -void ipwireless_network_notify_control_line_change(struct ipw_network *net, - unsigned int channel_idx, unsigned int control_lines, - unsigned int control_mask); -void ipwireless_network_packet_received(struct ipw_network *net, - unsigned int channel_idx, unsigned char *data, - unsigned int length); -struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw); -void ipwireless_network_free(struct ipw_network *net); -void ipwireless_associate_network_tty(struct ipw_network *net, - unsigned int channel_idx, struct ipw_tty *tty); -void ipwireless_disassociate_network_ttys(struct ipw_network *net, - unsigned int channel_idx); - -void ipwireless_ppp_open(struct ipw_network *net); - -void ipwireless_ppp_close(struct ipw_network *net); -int ipwireless_ppp_channel_index(struct ipw_network *net); -int ipwireless_ppp_unit_number(struct ipw_network *net); - -int ipwireless_dump_network_state(char *p, size_t limit, - struct ipw_network *net); - -#endif diff --git a/trunk/drivers/char/pcmcia/ipwireless/setup_protocol.h b/trunk/drivers/char/pcmcia/ipwireless/setup_protocol.h deleted file mode 100644 index 9d6bcc77c73c..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/setup_protocol.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#ifndef _IPWIRELESS_CS_SETUP_PROTOCOL_H_ -#define _IPWIRELESS_CS_SETUP_PROTOCOL_H_ - -/* Version of the setup protocol and transport protocols */ -#define TL_SETUP_VERSION 1 - -#define TL_SETUP_VERSION_QRY_TMO 1000 -#define TL_SETUP_MAX_VERSION_QRY 30 - -/* Message numbers 0-9 are obsoleted and must not be reused! */ -#define TL_SETUP_SIGNO_GET_VERSION_QRY 10 -#define TL_SETUP_SIGNO_GET_VERSION_RSP 11 -#define TL_SETUP_SIGNO_CONFIG_MSG 12 -#define TL_SETUP_SIGNO_CONFIG_DONE_MSG 13 -#define TL_SETUP_SIGNO_OPEN_MSG 14 -#define TL_SETUP_SIGNO_CLOSE_MSG 15 - -#define TL_SETUP_SIGNO_INFO_MSG 20 -#define TL_SETUP_SIGNO_INFO_MSG_ACK 21 - -#define TL_SETUP_SIGNO_REBOOT_MSG 22 -#define TL_SETUP_SIGNO_REBOOT_MSG_ACK 23 - -/* Synchronous start-messages */ -struct tl_setup_get_version_qry { - unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_QRY */ -} __attribute__ ((__packed__)); - -struct tl_setup_get_version_rsp { - unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_RSP */ - unsigned char version; /* TL_SETUP_VERSION */ -} __attribute__ ((__packed__)); - -struct tl_setup_config_msg { - unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_MSG */ - unsigned char port_no; - unsigned char prio_data; - unsigned char prio_ctrl; -} __attribute__ ((__packed__)); - -struct tl_setup_config_done_msg { - unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_DONE_MSG */ -} __attribute__ ((__packed__)); - -/* Asyncronous messages */ -struct tl_setup_open_msg { - unsigned char sig_no; /* TL_SETUP_SIGNO_OPEN_MSG */ - unsigned char port_no; -} __attribute__ ((__packed__)); - -struct tl_setup_close_msg { - unsigned char sig_no; /* TL_SETUP_SIGNO_CLOSE_MSG */ - unsigned char port_no; -} __attribute__ ((__packed__)); - -/* Driver type - for use in tl_setup_info_msg.driver_type */ -#define COMM_DRIVER 0 -#define NDISWAN_DRIVER 1 -#define NDISWAN_DRIVER_MAJOR_VERSION 2 -#define NDISWAN_DRIVER_MINOR_VERSION 0 - -/* - * It should not matter when this message comes over as we just store the - * results and send the ACK. - */ -struct tl_setup_info_msg { - unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG */ - unsigned char driver_type; - unsigned char major_version; - unsigned char minor_version; -} __attribute__ ((__packed__)); - -struct tl_setup_info_msgAck { - unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG_ACK */ -} __attribute__ ((__packed__)); - -struct TlSetupRebootMsgAck { - unsigned char sig_no; /* TL_SETUP_SIGNO_REBOOT_MSG_ACK */ -} __attribute__ ((__packed__)); - -/* Define a union of all the msgs that the driver can receive from the card.*/ -union ipw_setup_rx_msg { - unsigned char sig_no; - struct tl_setup_get_version_rsp version_rsp_msg; - struct tl_setup_open_msg open_msg; - struct tl_setup_close_msg close_msg; - struct tl_setup_info_msg InfoMsg; - struct tl_setup_info_msgAck info_msg_ack; -} __attribute__ ((__packed__)); - -#endif /* _IPWIRELESS_CS_SETUP_PROTOCOL_H_ */ diff --git a/trunk/drivers/char/pcmcia/ipwireless/tty.c b/trunk/drivers/char/pcmcia/ipwireless/tty.c deleted file mode 100644 index 42f3815c5ce3..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/tty.c +++ /dev/null @@ -1,688 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tty.h" -#include "network.h" -#include "hardware.h" -#include "main.h" - -#define IPWIRELESS_PCMCIA_START (0) -#define IPWIRELESS_PCMCIA_MINORS (24) -#define IPWIRELESS_PCMCIA_MINOR_RANGE (8) - -#define TTYTYPE_MODEM (0) -#define TTYTYPE_MONITOR (1) -#define TTYTYPE_RAS_RAW (2) - -struct ipw_tty { - int index; - struct ipw_hardware *hardware; - unsigned int channel_idx; - unsigned int secondary_channel_idx; - int tty_type; - struct ipw_network *network; - struct tty_struct *linux_tty; - int open_count; - unsigned int control_lines; - struct mutex ipw_tty_mutex; - int tx_bytes_queued; - int closing; -}; - -static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS]; - -static struct tty_driver *ipw_tty_driver; - -static char *tty_type_name(int tty_type) -{ - static char *channel_names[] = { - "modem", - "monitor", - "RAS-raw" - }; - - return channel_names[tty_type]; -} - -static void report_registering(struct ipw_tty *tty) -{ - char *iftype = tty_type_name(tty->tty_type); - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": registering %s device ttyIPWp%d\n", iftype, tty->index); -} - -static void report_deregistering(struct ipw_tty *tty) -{ - char *iftype = tty_type_name(tty->tty_type); - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": deregistering %s device ttyIPWp%d\n", iftype, - tty->index); -} - -static struct ipw_tty *get_tty(int minor) -{ - if (minor < ipw_tty_driver->minor_start - || minor >= ipw_tty_driver->minor_start + - IPWIRELESS_PCMCIA_MINORS) - return NULL; - else { - int minor_offset = minor - ipw_tty_driver->minor_start; - - /* - * The 'ras_raw' channel is only available when 'loopback' mode - * is enabled. - * Number of minor starts with 16 (_RANGE * _RAS_RAW). - */ - if (!ipwireless_loopback && - minor_offset >= - IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW) - return NULL; - - return ttys[minor_offset]; - } -} - -static int ipw_open(struct tty_struct *linux_tty, struct file *filp) -{ - int minor = linux_tty->index; - struct ipw_tty *tty = get_tty(minor); - - if (!tty) - return -ENODEV; - - mutex_lock(&tty->ipw_tty_mutex); - - if (tty->closing) { - mutex_unlock(&tty->ipw_tty_mutex); - return -ENODEV; - } - if (tty->open_count == 0) - tty->tx_bytes_queued = 0; - - tty->open_count++; - - tty->linux_tty = linux_tty; - linux_tty->driver_data = tty; - linux_tty->low_latency = 1; - - if (tty->tty_type == TTYTYPE_MODEM) - ipwireless_ppp_open(tty->network); - - mutex_unlock(&tty->ipw_tty_mutex); - - return 0; -} - -static void do_ipw_close(struct ipw_tty *tty) -{ - tty->open_count--; - - if (tty->open_count == 0) { - struct tty_struct *linux_tty = tty->linux_tty; - - if (linux_tty != NULL) { - tty->linux_tty = NULL; - linux_tty->driver_data = NULL; - - if (tty->tty_type == TTYTYPE_MODEM) - ipwireless_ppp_close(tty->network); - } - } -} - -static void ipw_hangup(struct tty_struct *linux_tty) -{ - struct ipw_tty *tty = linux_tty->driver_data; - - if (!tty) - return; - - mutex_lock(&tty->ipw_tty_mutex); - if (tty->open_count == 0) { - mutex_unlock(&tty->ipw_tty_mutex); - return; - } - - do_ipw_close(tty); - - mutex_unlock(&tty->ipw_tty_mutex); -} - -static void ipw_close(struct tty_struct *linux_tty, struct file *filp) -{ - ipw_hangup(linux_tty); -} - -/* Take data received from hardware, and send it out the tty */ -void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, - unsigned int length) -{ - struct tty_struct *linux_tty; - int work = 0; - - mutex_lock(&tty->ipw_tty_mutex); - linux_tty = tty->linux_tty; - if (linux_tty == NULL) { - mutex_unlock(&tty->ipw_tty_mutex); - return; - } - - if (!tty->open_count) { - mutex_unlock(&tty->ipw_tty_mutex); - return; - } - mutex_unlock(&tty->ipw_tty_mutex); - - work = tty_insert_flip_string(linux_tty, data, length); - - if (work != length) - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME - ": %d chars not inserted to flip buffer!\n", - length - work); - - /* - * This may sleep if ->low_latency is set - */ - if (work) - tty_flip_buffer_push(linux_tty); -} - -static void ipw_write_packet_sent_callback(void *callback_data, - unsigned int packet_length) -{ - struct ipw_tty *tty = callback_data; - - /* - * Packet has been sent, so we subtract the number of bytes from our - * tally of outstanding TX bytes. - */ - tty->tx_bytes_queued -= packet_length; -} - -static int ipw_write(struct tty_struct *linux_tty, - const unsigned char *buf, int count) -{ - struct ipw_tty *tty = linux_tty->driver_data; - int room, ret; - - if (!tty) - return -ENODEV; - - mutex_lock(&tty->ipw_tty_mutex); - if (!tty->open_count) { - mutex_unlock(&tty->ipw_tty_mutex); - return -EINVAL; - } - - room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; - if (room < 0) - room = 0; - /* Don't allow caller to write any more than we have room for */ - if (count > room) - count = room; - - if (count == 0) { - mutex_unlock(&tty->ipw_tty_mutex); - return 0; - } - - ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS, - (unsigned char *) buf, count, - ipw_write_packet_sent_callback, tty); - if (ret == -1) { - mutex_unlock(&tty->ipw_tty_mutex); - return 0; - } - - tty->tx_bytes_queued += count; - mutex_unlock(&tty->ipw_tty_mutex); - - return count; -} - -static int ipw_write_room(struct tty_struct *linux_tty) -{ - struct ipw_tty *tty = linux_tty->driver_data; - int room; - - if (!tty) - return -ENODEV; - - if (!tty->open_count) - return -EINVAL; - - room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; - if (room < 0) - room = 0; - - return room; -} - -static int ipwireless_get_serial_info(struct ipw_tty *tty, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return (-EFAULT); - - memset(&tmp, 0, sizeof(tmp)); - tmp.type = PORT_UNKNOWN; - tmp.line = tty->index; - tmp.port = 0; - tmp.irq = 0; - tmp.flags = 0; - tmp.baud_base = 115200; - tmp.close_delay = 0; - tmp.closing_wait = 0; - tmp.custom_divisor = 0; - tmp.hub6 = 0; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - - return 0; -} - -static int ipw_chars_in_buffer(struct tty_struct *linux_tty) -{ - struct ipw_tty *tty = linux_tty->driver_data; - - if (!tty) - return -ENODEV; - - if (!tty->open_count) - return -EINVAL; - - return tty->tx_bytes_queued; -} - -static int get_control_lines(struct ipw_tty *tty) -{ - unsigned int my = tty->control_lines; - unsigned int out = 0; - - if (my & IPW_CONTROL_LINE_RTS) - out |= TIOCM_RTS; - if (my & IPW_CONTROL_LINE_DTR) - out |= TIOCM_DTR; - if (my & IPW_CONTROL_LINE_CTS) - out |= TIOCM_CTS; - if (my & IPW_CONTROL_LINE_DSR) - out |= TIOCM_DSR; - if (my & IPW_CONTROL_LINE_DCD) - out |= TIOCM_CD; - - return out; -} - -static int set_control_lines(struct ipw_tty *tty, unsigned int set, - unsigned int clear) -{ - int ret; - - if (set & TIOCM_RTS) { - ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 1); - if (ret) - return ret; - if (tty->secondary_channel_idx != -1) { - ret = ipwireless_set_RTS(tty->hardware, - tty->secondary_channel_idx, 1); - if (ret) - return ret; - } - } - if (set & TIOCM_DTR) { - ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 1); - if (ret) - return ret; - if (tty->secondary_channel_idx != -1) { - ret = ipwireless_set_DTR(tty->hardware, - tty->secondary_channel_idx, 1); - if (ret) - return ret; - } - } - if (clear & TIOCM_RTS) { - ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 0); - if (tty->secondary_channel_idx != -1) { - ret = ipwireless_set_RTS(tty->hardware, - tty->secondary_channel_idx, 0); - if (ret) - return ret; - } - } - if (clear & TIOCM_DTR) { - ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 0); - if (tty->secondary_channel_idx != -1) { - ret = ipwireless_set_DTR(tty->hardware, - tty->secondary_channel_idx, 0); - if (ret) - return ret; - } - } - return 0; -} - -static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file) -{ - struct ipw_tty *tty = linux_tty->driver_data; - - if (!tty) - return -ENODEV; - - if (!tty->open_count) - return -EINVAL; - - return get_control_lines(tty); -} - -static int -ipw_tiocmset(struct tty_struct *linux_tty, struct file *file, - unsigned int set, unsigned int clear) -{ - struct ipw_tty *tty = linux_tty->driver_data; - - if (!tty) - return -ENODEV; - - if (!tty->open_count) - return -EINVAL; - - return set_control_lines(tty, set, clear); -} - -static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct ipw_tty *tty = linux_tty->driver_data; - - if (!tty) - return -ENODEV; - - if (!tty->open_count) - return -EINVAL; - - switch (cmd) { - case TIOCGSERIAL: - return ipwireless_get_serial_info(tty, (void __user *) arg); - - case TIOCSSERIAL: - return 0; /* Keeps the PCMCIA scripts happy. */ - } - - if (tty->tty_type == TTYTYPE_MODEM) { - switch (cmd) { - case PPPIOCGCHAN: - { - int chan = ipwireless_ppp_channel_index( - tty->network); - - if (chan < 0) - return -ENODEV; - if (put_user(chan, (int __user *) arg)) - return -EFAULT; - } - return 0; - - case PPPIOCGUNIT: - { - int unit = ipwireless_ppp_unit_number( - tty->network); - - if (unit < 0) - return -ENODEV; - if (put_user(unit, (int __user *) arg)) - return -EFAULT; - } - return 0; - - case TCGETS: - case TCGETA: - return n_tty_ioctl(linux_tty, file, cmd, arg); - - case TCFLSH: - return n_tty_ioctl(linux_tty, file, cmd, arg); - - case FIONREAD: - { - int val = 0; - - if (put_user(val, (int __user *) arg)) - return -EFAULT; - } - return 0; - } - } - - return -ENOIOCTLCMD; -} - -static int add_tty(dev_node_t *nodesp, int j, - struct ipw_hardware *hardware, - struct ipw_network *network, int channel_idx, - int secondary_channel_idx, int tty_type) -{ - ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL); - if (!ttys[j]) - return -ENOMEM; - ttys[j]->index = j; - ttys[j]->hardware = hardware; - ttys[j]->channel_idx = channel_idx; - ttys[j]->secondary_channel_idx = secondary_channel_idx; - ttys[j]->network = network; - ttys[j]->tty_type = tty_type; - mutex_init(&ttys[j]->ipw_tty_mutex); - - tty_register_device(ipw_tty_driver, j, NULL); - ipwireless_associate_network_tty(network, channel_idx, ttys[j]); - - if (secondary_channel_idx != -1) - ipwireless_associate_network_tty(network, - secondary_channel_idx, - ttys[j]); - if (nodesp != NULL) { - sprintf(nodesp->dev_name, "ttyIPWp%d", j); - nodesp->major = ipw_tty_driver->major; - nodesp->minor = j + ipw_tty_driver->minor_start; - } - if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j]) - report_registering(ttys[j]); - return 0; -} - -struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hardware, - struct ipw_network *network, - dev_node_t *nodes) -{ - int i, j; - - for (i = 0; i < IPWIRELESS_PCMCIA_MINOR_RANGE; i++) { - int allfree = 1; - - for (j = i; j < IPWIRELESS_PCMCIA_MINORS; - j += IPWIRELESS_PCMCIA_MINOR_RANGE) - if (ttys[j] != NULL) { - allfree = 0; - break; - } - - if (allfree) { - j = i; - - if (add_tty(&nodes[0], j, hardware, network, - IPW_CHANNEL_DIALLER, IPW_CHANNEL_RAS, - TTYTYPE_MODEM)) - return NULL; - - j += IPWIRELESS_PCMCIA_MINOR_RANGE; - if (add_tty(&nodes[1], j, hardware, network, - IPW_CHANNEL_DIALLER, -1, - TTYTYPE_MONITOR)) - return NULL; - - j += IPWIRELESS_PCMCIA_MINOR_RANGE; - if (add_tty(NULL, j, hardware, network, - IPW_CHANNEL_RAS, -1, - TTYTYPE_RAS_RAW)) - return NULL; - - nodes[0].next = &nodes[1]; - nodes[1].next = NULL; - - return ttys[i]; - } - } - return NULL; -} - -/* - * Must be called before ipwireless_network_free(). - */ -void ipwireless_tty_free(struct ipw_tty *tty) -{ - int j; - struct ipw_network *network = ttys[tty->index]->network; - - for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS; - j += IPWIRELESS_PCMCIA_MINOR_RANGE) { - struct ipw_tty *ttyj = ttys[j]; - - if (ttyj) { - mutex_lock(&ttyj->ipw_tty_mutex); - if (get_tty(j + ipw_tty_driver->minor_start) == ttyj) - report_deregistering(ttyj); - ttyj->closing = 1; - if (ttyj->linux_tty != NULL) { - mutex_unlock(&ttyj->ipw_tty_mutex); - tty_hangup(ttyj->linux_tty); - /* Wait till the tty_hangup has completed */ - flush_scheduled_work(); - mutex_lock(&ttyj->ipw_tty_mutex); - } - while (ttyj->open_count) - do_ipw_close(ttyj); - ipwireless_disassociate_network_ttys(network, - ttyj->channel_idx); - tty_unregister_device(ipw_tty_driver, j); - ttys[j] = NULL; - mutex_unlock(&ttyj->ipw_tty_mutex); - kfree(ttyj); - } - } -} - -static struct tty_operations tty_ops = { - .open = ipw_open, - .close = ipw_close, - .hangup = ipw_hangup, - .write = ipw_write, - .write_room = ipw_write_room, - .ioctl = ipw_ioctl, - .chars_in_buffer = ipw_chars_in_buffer, - .tiocmget = ipw_tiocmget, - .tiocmset = ipw_tiocmset, -}; - -int ipwireless_tty_init(void) -{ - int result; - - ipw_tty_driver = alloc_tty_driver(IPWIRELESS_PCMCIA_MINORS); - if (!ipw_tty_driver) - return -ENOMEM; - - ipw_tty_driver->owner = THIS_MODULE; - ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME; - ipw_tty_driver->name = "ttyIPWp"; - ipw_tty_driver->major = 0; - ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START; - ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL; - ipw_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - ipw_tty_driver->init_termios = tty_std_termios; - ipw_tty_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - ipw_tty_driver->init_termios.c_ispeed = 9600; - ipw_tty_driver->init_termios.c_ospeed = 9600; - tty_set_operations(ipw_tty_driver, &tty_ops); - result = tty_register_driver(ipw_tty_driver); - if (result) { - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": failed to register tty driver\n"); - put_tty_driver(ipw_tty_driver); - return result; - } - - return 0; -} - -void ipwireless_tty_release(void) -{ - int ret; - - ret = tty_unregister_driver(ipw_tty_driver); - put_tty_driver(ipw_tty_driver); - if (ret != 0) - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": tty_unregister_driver failed with code %d\n", ret); -} - -int ipwireless_tty_is_modem(struct ipw_tty *tty) -{ - return tty->tty_type == TTYTYPE_MODEM; -} - -void -ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, - unsigned int channel_idx, - unsigned int control_lines, - unsigned int changed_mask) -{ - unsigned int old_control_lines = tty->control_lines; - - tty->control_lines = (tty->control_lines & ~changed_mask) - | (control_lines & changed_mask); - - /* - * If DCD is de-asserted, we close the tty so pppd can tell that we - * have gone offline. - */ - if ((old_control_lines & IPW_CONTROL_LINE_DCD) - && !(tty->control_lines & IPW_CONTROL_LINE_DCD) - && tty->linux_tty) { - tty_hangup(tty->linux_tty); - } -} - diff --git a/trunk/drivers/char/pcmcia/ipwireless/tty.h b/trunk/drivers/char/pcmcia/ipwireless/tty.h deleted file mode 100644 index b0deb9168b6b..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/tty.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#ifndef _IPWIRELESS_CS_TTY_H_ -#define _IPWIRELESS_CS_TTY_H_ - -#include -#include - -#include -#include -#include -#include - -struct ipw_tty; -struct ipw_network; -struct ipw_hardware; - -int ipwireless_tty_init(void); -void ipwireless_tty_release(void); - -struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hw, - struct ipw_network *net, - dev_node_t *nodes); -void ipwireless_tty_free(struct ipw_tty *tty); -void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, - unsigned int length); -int ipwireless_tty_is_modem(struct ipw_tty *tty); -void ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, - unsigned int channel_idx, - unsigned int control_lines, - unsigned int changed_mask); - -#endif diff --git a/trunk/drivers/input/Kconfig b/trunk/drivers/input/Kconfig index 9dea14db724c..63512d906f02 100644 --- a/trunk/drivers/input/Kconfig +++ b/trunk/drivers/input/Kconfig @@ -137,18 +137,6 @@ config INPUT_EVBUG To compile this driver as a module, choose M here: the module will be called evbug. -config INPUT_APMPOWER - tristate "Input Power Event -> APM Bridge" if EMBEDDED - depends on INPUT && APM_EMULATION - ---help--- - Say Y here if you want suspend key events to trigger a user - requested suspend through APM. This is useful on embedded - systems where such behviour is desired without userspace - interaction. If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called apm-power. - comment "Input Device Drivers" source "drivers/input/keyboard/Kconfig" diff --git a/trunk/drivers/input/Makefile b/trunk/drivers/input/Makefile index 2ae87b19caa8..99af903bd3ce 100644 --- a/trunk/drivers/input/Makefile +++ b/trunk/drivers/input/Makefile @@ -22,4 +22,3 @@ obj-$(CONFIG_INPUT_TABLET) += tablet/ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ obj-$(CONFIG_INPUT_MISC) += misc/ -obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o diff --git a/trunk/drivers/input/apm-power.c b/trunk/drivers/input/apm-power.c deleted file mode 100644 index c36d110b349a..000000000000 --- a/trunk/drivers/input/apm-power.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Input Power Event -> APM Bridge - * - * Copyright (c) 2007 Richard Purdie - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static void system_power_event(unsigned int keycode) -{ - switch (keycode) { - case KEY_SUSPEND: - apm_queue_event(APM_USER_SUSPEND); - - printk(KERN_INFO "apm-power: Requesting system suspend...\n"); - break; - default: - break; - } -} - -static void apmpower_event(struct input_handle *handle, unsigned int type, - unsigned int code, int value) -{ - /* only react on key down events */ - if (value != 1) - return; - - switch (type) { - case EV_PWR: - system_power_event(code); - break; - - default: - break; - } -} - -static int apmpower_connect(struct input_handler *handler, - struct input_dev *dev, - const struct input_device_id *id) -{ - struct input_handle *handle; - int error; - - handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); - if (!handle) - return -ENOMEM; - - handle->dev = dev; - handle->handler = handler; - handle->name = "apm-power"; - - handler->private = handle; - - error = input_register_handle(handle); - if (error) { - printk(KERN_ERR - "apm-power: Failed to register input power handler, " - "error %d\n", error); - kfree(handle); - return error; - } - - error = input_open_device(handle); - if (error) { - printk(KERN_ERR - "apm-power: Failed to open input power device, " - "error %d\n", error); - input_unregister_handle(handle); - kfree(handle); - return error; - } - - return 0; -} - -static void apmpower_disconnect(struct input_handle *handler) -{ - struct input_handle *handle = handler->private; - - input_close_device(handle); - kfree(handle); -} - -static const struct input_device_id apmpower_ids[] = { - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT, - .evbit = { BIT_MASK(EV_PWR) }, - }, - { }, -}; - -MODULE_DEVICE_TABLE(input, apmpower_ids); - -static struct input_handler apmpower_handler = { - .event = apmpower_event, - .connect = apmpower_connect, - .disconnect = apmpower_disconnect, - .name = "apm-power", - .id_table = apmpower_ids, -}; - -static int __init apmpower_init(void) -{ - return input_register_handler(&apmpower_handler); -} - -static void __exit apmpower_exit(void) -{ - input_unregister_handler(&apmpower_handler); -} - -module_init(apmpower_init); -module_exit(apmpower_exit); - -MODULE_AUTHOR("Richard Purdie "); -MODULE_DESCRIPTION("Input Power Event -> APM Bridge"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/input/evdev.c b/trunk/drivers/input/evdev.c index 0727b0a12557..e5b4e9bfbdc5 100644 --- a/trunk/drivers/input/evdev.c +++ b/trunk/drivers/input/evdev.c @@ -617,7 +617,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, if (get_user(t, ip)) return -EFAULT; - error = input_get_keycode(dev, t, &v); + error = dev->getkeycode(dev, t, &v); if (error) return error; @@ -630,7 +630,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, if (get_user(t, ip) || get_user(v, ip + 1)) return -EFAULT; - return input_set_keycode(dev, t, v); + return dev->setkeycode(dev, t, v); case EVIOCSFF: if (copy_from_user(&effect, p, sizeof(effect))) @@ -683,7 +683,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, case EV_FF: bits = dev->ffbit; len = FF_MAX; break; case EV_SW: bits = dev->swbit; len = SW_MAX; break; default: return -EINVAL; - } + } return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); } diff --git a/trunk/drivers/input/input-polldev.c b/trunk/drivers/input/input-polldev.c index 490918a5d192..92b359894e81 100644 --- a/trunk/drivers/input/input-polldev.c +++ b/trunk/drivers/input/input-polldev.c @@ -60,21 +60,17 @@ static void input_polled_device_work(struct work_struct *work) { struct input_polled_dev *dev = container_of(work, struct input_polled_dev, work.work); - unsigned long delay; dev->poll(dev); - - delay = msecs_to_jiffies(dev->poll_interval); - if (delay >= HZ) - delay = round_jiffies_relative(delay); - - queue_delayed_work(polldev_wq, &dev->work, delay); + queue_delayed_work(polldev_wq, &dev->work, + msecs_to_jiffies(dev->poll_interval)); } static int input_open_polled_device(struct input_dev *input) { struct input_polled_dev *dev = input->private; int error; + unsigned long ticks; error = input_polldev_start_workqueue(); if (error) @@ -83,8 +79,10 @@ static int input_open_polled_device(struct input_dev *input) if (dev->flush) dev->flush(dev); - queue_delayed_work(polldev_wq, &dev->work, - msecs_to_jiffies(dev->poll_interval)); + ticks = msecs_to_jiffies(dev->poll_interval); + if (ticks >= HZ) + ticks = round_jiffies(ticks); + queue_delayed_work(polldev_wq, &dev->work, ticks); return 0; } @@ -93,7 +91,7 @@ static void input_close_polled_device(struct input_dev *input) { struct input_polled_dev *dev = input->private; - cancel_delayed_work_sync(&dev->work); + cancel_rearming_delayed_workqueue(polldev_wq, &dev->work); input_polldev_stop_workqueue(); } diff --git a/trunk/drivers/input/input.c b/trunk/drivers/input/input.c index f02c242c3114..a0be978501ff 100644 --- a/trunk/drivers/input/input.c +++ b/trunk/drivers/input/input.c @@ -493,7 +493,7 @@ static void input_disconnect_device(struct input_dev *dev) if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { for (code = 0; code <= KEY_MAX; code++) { if (is_event_supported(code, dev->keybit, KEY_MAX) && - __test_and_clear_bit(code, dev->key)) { + test_bit(code, dev->key)) { input_pass_event(dev, EV_KEY, code, 0); } } @@ -526,7 +526,7 @@ static int input_default_getkeycode(struct input_dev *dev, if (!dev->keycodesize) return -EINVAL; - if (scancode >= dev->keycodemax) + if (scancode < 0 || scancode >= dev->keycodemax) return -EINVAL; *keycode = input_fetch_keycode(dev, scancode); @@ -540,7 +540,10 @@ static int input_default_setkeycode(struct input_dev *dev, int old_keycode; int i; - if (scancode >= dev->keycodemax) + if (scancode < 0 || scancode >= dev->keycodemax) + return -EINVAL; + + if (keycode < 0 || keycode > KEY_MAX) return -EINVAL; if (!dev->keycodesize) @@ -583,75 +586,6 @@ static int input_default_setkeycode(struct input_dev *dev, return 0; } -/** - * input_get_keycode - retrieve keycode currently mapped to a given scancode - * @dev: input device which keymap is being queried - * @scancode: scancode (or its equivalent for device in question) for which - * keycode is needed - * @keycode: result - * - * This function should be called by anyone interested in retrieving current - * keymap. Presently keyboard and evdev handlers use it. - */ -int input_get_keycode(struct input_dev *dev, int scancode, int *keycode) -{ - if (scancode < 0) - return -EINVAL; - - return dev->getkeycode(dev, scancode, keycode); -} -EXPORT_SYMBOL(input_get_keycode); - -/** - * input_get_keycode - assign new keycode to a given scancode - * @dev: input device which keymap is being updated - * @scancode: scancode (or its equivalent for device in question) - * @keycode: new keycode to be assigned to the scancode - * - * This function should be called by anyone needing to update current - * keymap. Presently keyboard and evdev handlers use it. - */ -int input_set_keycode(struct input_dev *dev, int scancode, int keycode) -{ - unsigned long flags; - int old_keycode; - int retval; - - if (scancode < 0) - return -EINVAL; - - if (keycode < 0 || keycode > KEY_MAX) - return -EINVAL; - - spin_lock_irqsave(&dev->event_lock, flags); - - retval = dev->getkeycode(dev, scancode, &old_keycode); - if (retval) - goto out; - - retval = dev->setkeycode(dev, scancode, keycode); - if (retval) - goto out; - - /* - * Simulate keyup event if keycode is not present - * in the keymap anymore - */ - if (test_bit(EV_KEY, dev->evbit) && - !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && - __test_and_clear_bit(old_keycode, dev->key)) { - - input_pass_event(dev, EV_KEY, old_keycode, 0); - if (dev->sync) - input_pass_event(dev, EV_SYN, SYN_REPORT, 1); - } - - out: - spin_unlock_irqrestore(&dev->event_lock, flags); - - return retval; -} -EXPORT_SYMBOL(input_set_keycode); #define MATCH_BIT(bit, max) \ for (i = 0; i < BITS_TO_LONGS(max); i++) \ @@ -821,7 +755,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v) return 0; } -static const struct seq_operations input_devices_seq_ops = { +static struct seq_operations input_devices_seq_ops = { .start = input_devices_seq_start, .next = input_devices_seq_next, .stop = input_devices_seq_stop, @@ -874,7 +808,7 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v) return 0; } -static const struct seq_operations input_handlers_seq_ops = { +static struct seq_operations input_handlers_seq_ops = { .start = input_handlers_seq_start, .next = input_handlers_seq_next, .stop = input_handlers_seq_stop, @@ -1395,6 +1329,9 @@ int input_register_device(struct input_dev *dev) snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); + if (dev->cdev.dev) + dev->dev.parent = dev->cdev.dev; + error = device_add(&dev->dev); if (error) return error; diff --git a/trunk/drivers/input/joystick/amijoy.c b/trunk/drivers/input/joystick/amijoy.c index deb9f825f92c..5cf9f3610e67 100644 --- a/trunk/drivers/input/joystick/amijoy.c +++ b/trunk/drivers/input/joystick/amijoy.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/input/joystick/analog.c b/trunk/drivers/input/joystick/analog.c index f32e031dcb27..15739880afc6 100644 --- a/trunk/drivers/input/joystick/analog.c +++ b/trunk/drivers/input/joystick/analog.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/input/joystick/db9.c b/trunk/drivers/input/joystick/db9.c index 960e501c60c8..a6ca9d5e252f 100644 --- a/trunk/drivers/input/joystick/db9.c +++ b/trunk/drivers/input/joystick/db9.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/input/joystick/gamecon.c b/trunk/drivers/input/joystick/gamecon.c index 07a32aff5a31..df2a9d02ca6c 100644 --- a/trunk/drivers/input/joystick/gamecon.c +++ b/trunk/drivers/input/joystick/gamecon.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/input/joystick/iforce/iforce-main.c b/trunk/drivers/input/joystick/iforce/iforce-main.c index a2517fa72eb8..6f826b37d9aa 100644 --- a/trunk/drivers/input/joystick/iforce/iforce-main.c +++ b/trunk/drivers/input/joystick/iforce/iforce-main.c @@ -85,7 +85,7 @@ static struct iforce_device iforce_device[] = { static int iforce_playback(struct input_dev *dev, int effect_id, int value) { - struct iforce *iforce = input_get_drvdata(dev); + struct iforce* iforce = dev->private; struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id]; if (value > 0) @@ -99,7 +99,7 @@ static int iforce_playback(struct input_dev *dev, int effect_id, int value) static void iforce_set_gain(struct input_dev *dev, u16 gain) { - struct iforce *iforce = input_get_drvdata(dev); + struct iforce* iforce = dev->private; unsigned char data[3]; data[0] = gain >> 9; @@ -108,7 +108,7 @@ static void iforce_set_gain(struct input_dev *dev, u16 gain) static void iforce_set_autocenter(struct input_dev *dev, u16 magnitude) { - struct iforce *iforce = input_get_drvdata(dev); + struct iforce* iforce = dev->private; unsigned char data[3]; data[0] = 0x03; @@ -126,7 +126,7 @@ static void iforce_set_autocenter(struct input_dev *dev, u16 magnitude) */ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) { - struct iforce *iforce = input_get_drvdata(dev); + struct iforce* iforce = dev->private; struct iforce_core_effect *core_effect = &iforce->core_effects[effect->id]; int ret; @@ -173,7 +173,7 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, */ static int iforce_erase_effect(struct input_dev *dev, int effect_id) { - struct iforce *iforce = input_get_drvdata(dev); + struct iforce *iforce = dev->private; struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id]; int err = 0; @@ -191,7 +191,7 @@ static int iforce_erase_effect(struct input_dev *dev, int effect_id) static int iforce_open(struct input_dev *dev) { - struct iforce *iforce = input_get_drvdata(dev); + struct iforce *iforce = dev->private; switch (iforce->bus) { #ifdef CONFIG_JOYSTICK_IFORCE_USB @@ -213,7 +213,7 @@ static int iforce_open(struct input_dev *dev) static void iforce_release(struct input_dev *dev) { - struct iforce *iforce = input_get_drvdata(dev); + struct iforce *iforce = dev->private; int i; if (test_bit(EV_FF, dev->evbit)) { @@ -298,8 +298,7 @@ int iforce_init_device(struct iforce *iforce) #endif } - input_set_drvdata(input_dev, iforce); - + input_dev->private = iforce; input_dev->name = "Unknown I-Force device"; input_dev->open = iforce_open; input_dev->close = iforce_release; diff --git a/trunk/drivers/input/joystick/turbografx.c b/trunk/drivers/input/joystick/turbografx.c index 989483f53160..bbebd4e2ad7f 100644 --- a/trunk/drivers/input/joystick/turbografx.c +++ b/trunk/drivers/input/joystick/turbografx.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/input/joystick/xpad.c b/trunk/drivers/input/joystick/xpad.c index 0380597249bb..6e9d75bd2b15 100644 --- a/trunk/drivers/input/joystick/xpad.c +++ b/trunk/drivers/input/joystick/xpad.c @@ -75,6 +75,7 @@ #include #include #include +#include #include #define DRIVER_VERSION "v0.0.6" diff --git a/trunk/drivers/input/keyboard/Kconfig b/trunk/drivers/input/keyboard/Kconfig index 8ea709be3306..086d58c0ccbe 100644 --- a/trunk/drivers/input/keyboard/Kconfig +++ b/trunk/drivers/input/keyboard/Kconfig @@ -154,27 +154,6 @@ config KEYBOARD_SPITZ To compile this driver as a module, choose M here: the module will be called spitzkbd. -config KEYBOARD_TOSA - tristate "Tosa keyboard" - depends on MACH_TOSA - default y - help - Say Y here to enable the keyboard on the Sharp Zaurus SL-6000x (Tosa) - - To compile this driver as a module, choose M here: the - module will be called tosakbd. - -config KEYBOARD_TOSA_USE_EXT_KEYCODES - bool "Tosa keyboard: use extended keycodes" - depends on KEYBOARD_TOSA - default n - help - Say Y here to enable the tosa keyboard driver to generate extended - (>= 127) keycodes. Be aware, that they can't be correctly interpreted - by either console keyboard driver or by Kdrive keybd driver. - - Say Y only if you know, what you are doing! - config KEYBOARD_AMIGA tristate "Amiga keyboard" depends on AMIGA @@ -260,13 +239,13 @@ config KEYBOARD_OMAP module will be called omap-keypad. config KEYBOARD_PXA27x - tristate "PXA27x/PXA3xx keypad support" - depends on PXA27x || PXA3xx + tristate "PXA27x keyboard support" + depends on PXA27x help - Enable support for PXA27x/PXA3xx keypad controller + Enable support for PXA27x matrix keyboard controller To compile this driver as a module, choose M here: the - module will be called pxa27x_keypad. + module will be called pxa27x_keyboard. config KEYBOARD_AAED2000 tristate "AAED-2000 keyboard" diff --git a/trunk/drivers/input/keyboard/Makefile b/trunk/drivers/input/keyboard/Makefile index e741f4031012..e97455fdcc83 100644 --- a/trunk/drivers/input/keyboard/Makefile +++ b/trunk/drivers/input/keyboard/Makefile @@ -15,11 +15,10 @@ obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o -obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o -obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o +obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o diff --git a/trunk/drivers/input/keyboard/atkbd.c b/trunk/drivers/input/keyboard/atkbd.c index 4a95adc4cc78..b39c5b31e620 100644 --- a/trunk/drivers/input/keyboard/atkbd.c +++ b/trunk/drivers/input/keyboard/atkbd.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -27,7 +28,6 @@ #include #include #include -#include #define DRIVER_DESC "AT and PS/2 keyboard driver" @@ -201,7 +201,6 @@ struct atkbd { unsigned short id; unsigned char keycode[512]; - DECLARE_BITMAP(force_release_mask, 512); unsigned char set; unsigned char translated; unsigned char extra; @@ -226,11 +225,6 @@ struct atkbd { unsigned long event_mask; }; -/* - * System-specific ketymap fixup routine - */ -static void (*atkbd_platform_fixup)(struct atkbd *); - static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, ssize_t (*handler)(struct atkbd *, char *)); static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, @@ -355,7 +349,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, struct atkbd *atkbd = serio_get_drvdata(serio); struct input_dev *dev = atkbd->dev; unsigned int code = data; - int scroll = 0, hscroll = 0, click = -1; + int scroll = 0, hscroll = 0, click = -1, add_release_event = 0; int value; unsigned char keycode; @@ -420,6 +414,14 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, "Some program might be trying access hardware directly.\n", data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); goto out; + case ATKBD_RET_HANGEUL: + case ATKBD_RET_HANJA: + /* + * These keys do not report release and thus need to be + * flagged properly + */ + add_release_event = 1; + break; case ATKBD_RET_ERR: atkbd->err_count++; #ifdef ATKBD_DEBUG @@ -489,7 +491,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, input_event(dev, EV_KEY, keycode, value); input_sync(dev); - if (value && test_bit(code, atkbd->force_release_mask)) { + if (value && add_release_event) { input_report_key(dev, keycode, 0); input_sync(dev); } @@ -822,6 +824,7 @@ static void atkbd_disconnect(struct serio *serio) atkbd_disable(atkbd); /* make sure we don't have a command in flight */ + synchronize_sched(); /* Allow atkbd_interrupt()s to complete. */ flush_scheduled_work(); sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group); @@ -831,22 +834,6 @@ static void atkbd_disconnect(struct serio *serio) kfree(atkbd); } -/* - * Most special keys (Fn+F?) on Dell Latitudes do not generate release - * events so we have to do it ourselves. - */ -static void atkbd_latitude_keymap_fixup(struct atkbd *atkbd) -{ - const unsigned int forced_release_keys[] = { - 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, - }; - int i; - - if (atkbd->set == 2) - for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++) - __set_bit(forced_release_keys[i], - atkbd->force_release_mask); -} /* * atkbd_set_keycode_table() initializes keyboard's keycode table @@ -855,20 +842,17 @@ static void atkbd_latitude_keymap_fixup(struct atkbd *atkbd) static void atkbd_set_keycode_table(struct atkbd *atkbd) { - unsigned int scancode; int i, j; memset(atkbd->keycode, 0, sizeof(atkbd->keycode)); - bitmap_zero(atkbd->force_release_mask, 512); if (atkbd->translated) { for (i = 0; i < 128; i++) { - scancode = atkbd_unxlate_table[i]; - atkbd->keycode[i] = atkbd_set2_keycode[scancode]; - atkbd->keycode[i | 0x80] = atkbd_set2_keycode[scancode | 0x80]; + atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; + atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; if (atkbd->scroll) for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++) - if ((scancode | 0x80) == atkbd_scroll_keys[j].set2) + if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j].set2) atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode; } } else if (atkbd->set == 3) { @@ -877,29 +861,12 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd) memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); if (atkbd->scroll) - for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) { - scancode = atkbd_scroll_keys[i].set2; - atkbd->keycode[scancode] = atkbd_scroll_keys[i].keycode; - } + for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) + atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode; } -/* - * HANGEUL and HANJA keys do not send release events so we need to - * generate such events ourselves - */ - scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL); - atkbd->keycode[scancode] = KEY_HANGEUL; - __set_bit(scancode, atkbd->force_release_mask); - - scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA); - atkbd->keycode[scancode] = KEY_HANJA; - __set_bit(scancode, atkbd->force_release_mask); - -/* - * Perform additional fixups - */ - if (atkbd_platform_fixup) - atkbd_platform_fixup(atkbd); + atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL)] = KEY_HANGUEL; + atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA)] = KEY_HANJA; } /* @@ -1434,29 +1401,9 @@ static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf) return sprintf(buf, "%lu\n", atkbd->err_count); } -static int __init atkbd_setup_fixup(const struct dmi_system_id *id) -{ - atkbd_platform_fixup = id->driver_data; - return 0; -} - -static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { - { - .ident = "Dell Latitude series", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), - }, - .callback = atkbd_setup_fixup, - .driver_data = atkbd_latitude_keymap_fixup, - }, - { } -}; static int __init atkbd_init(void) { - dmi_check_system(atkbd_dmi_quirk_table); - return serio_register_driver(&atkbd_drv); } diff --git a/trunk/drivers/input/keyboard/lkkbd.c b/trunk/drivers/input/keyboard/lkkbd.c index 32e2c2605d95..1b08f4e79dd2 100644 --- a/trunk/drivers/input/keyboard/lkkbd.c +++ b/trunk/drivers/input/keyboard/lkkbd.c @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/input/keyboard/pxa27x_keyboard.c b/trunk/drivers/input/keyboard/pxa27x_keyboard.c new file mode 100644 index 000000000000..bdd64ee4c5c8 --- /dev/null +++ b/trunk/drivers/input/keyboard/pxa27x_keyboard.c @@ -0,0 +1,274 @@ +/* + * linux/drivers/input/keyboard/pxa27x_keyboard.c + * + * Driver for the pxa27x matrix keyboard controller. + * + * Created: Feb 22, 2007 + * Author: Rodolfo Giometti + * + * Based on a previous implementations by Kevin O'Connor + * and Alex Osborne and + * on some suggestions by Nicolas Pitre . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#define DRIVER_NAME "pxa27x-keyboard" + +#define KPASMKP(col) (col/2 == 0 ? KPASMKP0 : \ + col/2 == 1 ? KPASMKP1 : \ + col/2 == 2 ? KPASMKP2 : KPASMKP3) +#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2))) + +static struct clk *pxakbd_clk; + +static irqreturn_t pxakbd_irq_handler(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data; + struct input_dev *input_dev = platform_get_drvdata(pdev); + unsigned long kpc = KPC; + int p, row, col, rel; + + if (kpc & KPC_DI) { + unsigned long kpdk = KPDK; + + if (!(kpdk & KPDK_DKP)) { + /* better luck next time */ + } else if (kpc & KPC_REE0) { + unsigned long kprec = KPREC; + KPREC = 0x7f; + + if (kprec & KPREC_OF0) + rel = (kprec & 0xff) + 0x7f; + else if (kprec & KPREC_UF0) + rel = (kprec & 0xff) - 0x7f - 0xff; + else + rel = (kprec & 0xff) - 0x7f; + + if (rel) { + input_report_rel(input_dev, REL_WHEEL, rel); + input_sync(input_dev); + } + } + } + + if (kpc & KPC_MI) { + /* report the status of every button */ + for (row = 0; row < pdata->nr_rows; row++) { + for (col = 0; col < pdata->nr_cols; col++) { + p = KPASMKP(col) & KPASMKPx_MKC(row, col) ? + 1 : 0; + pr_debug("keycode %x - pressed %x\n", + pdata->keycodes[row][col], p); + input_report_key(input_dev, + pdata->keycodes[row][col], p); + } + } + input_sync(input_dev); + } + + return IRQ_HANDLED; +} + +static int pxakbd_open(struct input_dev *dev) +{ + /* Set keypad control register */ + KPC |= (KPC_ASACT | + KPC_MS_ALL | + (2 << 6) | KPC_REE0 | KPC_DK_DEB_SEL | + KPC_ME | KPC_MIE | KPC_DE | KPC_DIE); + + KPC &= ~KPC_AS; /* disable automatic scan */ + KPC &= ~KPC_IMKP; /* do not ignore multiple keypresses */ + + /* Set rotary count to mid-point value */ + KPREC = 0x7F; + + /* Enable unit clock */ + clk_enable(pxakbd_clk); + + return 0; +} + +static void pxakbd_close(struct input_dev *dev) +{ + /* Disable clock unit */ + clk_disable(pxakbd_clk); +} + +#ifdef CONFIG_PM +static int pxakbd_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data; + + /* Save controller status */ + pdata->reg_kpc = KPC; + pdata->reg_kprec = KPREC; + + return 0; +} + +static int pxakbd_resume(struct platform_device *pdev) +{ + struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data; + struct input_dev *input_dev = platform_get_drvdata(pdev); + + mutex_lock(&input_dev->mutex); + + if (input_dev->users) { + /* Restore controller status */ + KPC = pdata->reg_kpc; + KPREC = pdata->reg_kprec; + + /* Enable unit clock */ + clk_disable(pxakbd_clk); + clk_enable(pxakbd_clk); + } + + mutex_unlock(&input_dev->mutex); + + return 0; +} +#else +#define pxakbd_suspend NULL +#define pxakbd_resume NULL +#endif + +static int __devinit pxakbd_probe(struct platform_device *pdev) +{ + struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data; + struct input_dev *input_dev; + int i, row, col, error; + + pxakbd_clk = clk_get(&pdev->dev, "KBDCLK"); + if (IS_ERR(pxakbd_clk)) { + error = PTR_ERR(pxakbd_clk); + goto err_clk; + } + + /* Create and register the input driver. */ + input_dev = input_allocate_device(); + if (!input_dev) { + printk(KERN_ERR "Cannot request keypad device\n"); + error = -ENOMEM; + goto err_alloc; + } + + input_dev->name = DRIVER_NAME; + input_dev->id.bustype = BUS_HOST; + input_dev->open = pxakbd_open; + input_dev->close = pxakbd_close; + input_dev->dev.parent = &pdev->dev; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | + BIT_MASK(EV_REL); + input_dev->relbit[BIT_WORD(REL_WHEEL)] = BIT_MASK(REL_WHEEL); + for (row = 0; row < pdata->nr_rows; row++) { + for (col = 0; col < pdata->nr_cols; col++) { + int code = pdata->keycodes[row][col]; + if (code > 0) + set_bit(code, input_dev->keybit); + } + } + + error = request_irq(IRQ_KEYPAD, pxakbd_irq_handler, IRQF_DISABLED, + DRIVER_NAME, pdev); + if (error) { + printk(KERN_ERR "Cannot request keypad IRQ\n"); + goto err_free_dev; + } + + platform_set_drvdata(pdev, input_dev); + + /* Register the input device */ + error = input_register_device(input_dev); + if (error) + goto err_free_irq; + + /* Setup GPIOs. */ + for (i = 0; i < pdata->nr_rows + pdata->nr_cols; i++) + pxa_gpio_mode(pdata->gpio_modes[i]); + + /* + * Store rows/cols info into keyboard registers. + */ + + KPC |= (pdata->nr_rows - 1) << 26; + KPC |= (pdata->nr_cols - 1) << 23; + + for (col = 0; col < pdata->nr_cols; col++) + KPC |= KPC_MS0 << col; + + return 0; + + err_free_irq: + platform_set_drvdata(pdev, NULL); + free_irq(IRQ_KEYPAD, pdev); + err_free_dev: + input_free_device(input_dev); + err_alloc: + clk_put(pxakbd_clk); + err_clk: + return error; +} + +static int __devexit pxakbd_remove(struct platform_device *pdev) +{ + struct input_dev *input_dev = platform_get_drvdata(pdev); + + input_unregister_device(input_dev); + free_irq(IRQ_KEYPAD, pdev); + clk_put(pxakbd_clk); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver pxakbd_driver = { + .probe = pxakbd_probe, + .remove = __devexit_p(pxakbd_remove), + .suspend = pxakbd_suspend, + .resume = pxakbd_resume, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init pxakbd_init(void) +{ + return platform_driver_register(&pxakbd_driver); +} + +static void __exit pxakbd_exit(void) +{ + platform_driver_unregister(&pxakbd_driver); +} + +module_init(pxakbd_init); +module_exit(pxakbd_exit); + +MODULE_DESCRIPTION("PXA27x Matrix Keyboard Driver"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/input/keyboard/pxa27x_keypad.c b/trunk/drivers/input/keyboard/pxa27x_keypad.c deleted file mode 100644 index 6224c2fb3b65..000000000000 --- a/trunk/drivers/input/keyboard/pxa27x_keypad.c +++ /dev/null @@ -1,572 +0,0 @@ -/* - * linux/drivers/input/keyboard/pxa27x_keypad.c - * - * Driver for the pxa27x matrix keyboard controller. - * - * Created: Feb 22, 2007 - * Author: Rodolfo Giometti - * - * Based on a previous implementations by Kevin O'Connor - * and Alex Osborne and - * on some suggestions by Nicolas Pitre . - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -/* - * Keypad Controller registers - */ -#define KPC 0x0000 /* Keypad Control register */ -#define KPDK 0x0008 /* Keypad Direct Key register */ -#define KPREC 0x0010 /* Keypad Rotary Encoder register */ -#define KPMK 0x0018 /* Keypad Matrix Key register */ -#define KPAS 0x0020 /* Keypad Automatic Scan register */ - -/* Keypad Automatic Scan Multiple Key Presser register 0-3 */ -#define KPASMKP0 0x0028 -#define KPASMKP1 0x0030 -#define KPASMKP2 0x0038 -#define KPASMKP3 0x0040 -#define KPKDI 0x0048 - -/* bit definitions */ -#define KPC_MKRN(n) ((((n) & 0x7) - 1) << 26) /* matrix key row number */ -#define KPC_MKCN(n) ((((n) & 0x7) - 1) << 23) /* matrix key column number */ -#define KPC_DKN(n) ((((n) & 0x7) - 1) << 6) /* direct key number */ - -#define KPC_AS (0x1 << 30) /* Automatic Scan bit */ -#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */ -#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */ -#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */ - -#define KPC_MS(n) (0x1 << (13 + (n))) /* Matrix scan line 'n' */ -#define KPC_MS_ALL (0xff << 13) - -#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */ -#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */ -#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */ -#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */ -#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */ -#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */ -#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */ -#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */ -#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */ - -#define KPDK_DKP (0x1 << 31) -#define KPDK_DK(n) ((n) & 0xff) - -#define KPREC_OF1 (0x1 << 31) -#define kPREC_UF1 (0x1 << 30) -#define KPREC_OF0 (0x1 << 15) -#define KPREC_UF0 (0x1 << 14) - -#define KPREC_RECOUNT0(n) ((n) & 0xff) -#define KPREC_RECOUNT1(n) (((n) >> 16) & 0xff) - -#define KPMK_MKP (0x1 << 31) -#define KPAS_SO (0x1 << 31) -#define KPASMKPx_SO (0x1 << 31) - -#define KPAS_MUKP(n) (((n) >> 26) & 0x1f) -#define KPAS_RP(n) (((n) >> 4) & 0xf) -#define KPAS_CP(n) ((n) & 0xf) - -#define KPASMKP_MKC_MASK (0xff) - -#define keypad_readl(off) __raw_readl(keypad->mmio_base + (off)) -#define keypad_writel(off, v) __raw_writel((v), keypad->mmio_base + (off)) - -#define MAX_MATRIX_KEY_NUM (8 * 8) - -struct pxa27x_keypad { - struct pxa27x_keypad_platform_data *pdata; - - struct clk *clk; - struct input_dev *input_dev; - void __iomem *mmio_base; - - /* matrix key code map */ - unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM]; - - /* state row bits of each column scan */ - uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS]; - uint32_t direct_key_state; - - unsigned int direct_key_mask; - - int rotary_rel_code[2]; - int rotary_up_key[2]; - int rotary_down_key[2]; -}; - -static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) -{ - struct pxa27x_keypad_platform_data *pdata = keypad->pdata; - struct input_dev *input_dev = keypad->input_dev; - unsigned int *key; - int i; - - key = &pdata->matrix_key_map[0]; - for (i = 0; i < pdata->matrix_key_map_size; i++, key++) { - int row = ((*key) >> 28) & 0xf; - int col = ((*key) >> 24) & 0xf; - int code = (*key) & 0xffffff; - - keypad->matrix_keycodes[(row << 3) + col] = code; - set_bit(code, input_dev->keybit); - } - - keypad->rotary_up_key[0] = pdata->rotary0_up_key; - keypad->rotary_up_key[1] = pdata->rotary1_up_key; - keypad->rotary_down_key[0] = pdata->rotary0_down_key; - keypad->rotary_down_key[1] = pdata->rotary1_down_key; - keypad->rotary_rel_code[0] = pdata->rotary0_rel_code; - keypad->rotary_rel_code[1] = pdata->rotary1_rel_code; - - if (pdata->rotary0_up_key && pdata->rotary0_down_key) { - set_bit(pdata->rotary0_up_key, input_dev->keybit); - set_bit(pdata->rotary0_down_key, input_dev->keybit); - } else - set_bit(pdata->rotary0_rel_code, input_dev->relbit); - - if (pdata->rotary1_up_key && pdata->rotary1_down_key) { - set_bit(pdata->rotary1_up_key, input_dev->keybit); - set_bit(pdata->rotary1_down_key, input_dev->keybit); - } else - set_bit(pdata->rotary1_rel_code, input_dev->relbit); -} - -static inline unsigned int lookup_matrix_keycode( - struct pxa27x_keypad *keypad, int row, int col) -{ - return keypad->matrix_keycodes[(row << 3) + col]; -} - -static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) -{ - struct pxa27x_keypad_platform_data *pdata = keypad->pdata; - int row, col, num_keys_pressed = 0; - uint32_t new_state[MAX_MATRIX_KEY_COLS]; - uint32_t kpas = keypad_readl(KPAS); - - num_keys_pressed = KPAS_MUKP(kpas); - - memset(new_state, 0, sizeof(new_state)); - - if (num_keys_pressed == 0) - goto scan; - - if (num_keys_pressed == 1) { - col = KPAS_CP(kpas); - row = KPAS_RP(kpas); - - /* if invalid row/col, treat as no key pressed */ - if (col >= pdata->matrix_key_cols || - row >= pdata->matrix_key_rows) - goto scan; - - new_state[col] = (1 << row); - goto scan; - } - - if (num_keys_pressed > 1) { - uint32_t kpasmkp0 = keypad_readl(KPASMKP0); - uint32_t kpasmkp1 = keypad_readl(KPASMKP1); - uint32_t kpasmkp2 = keypad_readl(KPASMKP2); - uint32_t kpasmkp3 = keypad_readl(KPASMKP3); - - new_state[0] = kpasmkp0 & KPASMKP_MKC_MASK; - new_state[1] = (kpasmkp0 >> 16) & KPASMKP_MKC_MASK; - new_state[2] = kpasmkp1 & KPASMKP_MKC_MASK; - new_state[3] = (kpasmkp1 >> 16) & KPASMKP_MKC_MASK; - new_state[4] = kpasmkp2 & KPASMKP_MKC_MASK; - new_state[5] = (kpasmkp2 >> 16) & KPASMKP_MKC_MASK; - new_state[6] = kpasmkp3 & KPASMKP_MKC_MASK; - new_state[7] = (kpasmkp3 >> 16) & KPASMKP_MKC_MASK; - } -scan: - for (col = 0; col < pdata->matrix_key_cols; col++) { - uint32_t bits_changed; - - bits_changed = keypad->matrix_key_state[col] ^ new_state[col]; - if (bits_changed == 0) - continue; - - for (row = 0; row < pdata->matrix_key_rows; row++) { - if ((bits_changed & (1 << row)) == 0) - continue; - - input_report_key(keypad->input_dev, - lookup_matrix_keycode(keypad, row, col), - new_state[col] & (1 << row)); - } - } - input_sync(keypad->input_dev); - memcpy(keypad->matrix_key_state, new_state, sizeof(new_state)); -} - -#define DEFAULT_KPREC (0x007f007f) - -static inline int rotary_delta(uint32_t kprec) -{ - if (kprec & KPREC_OF0) - return (kprec & 0xff) + 0x7f; - else if (kprec & KPREC_UF0) - return (kprec & 0xff) - 0x7f - 0xff; - else - return (kprec & 0xff) - 0x7f; -} - -static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta) -{ - struct input_dev *dev = keypad->input_dev; - - if (delta == 0) - return; - - if (keypad->rotary_up_key[r] && keypad->rotary_down_key[r]) { - int keycode = (delta > 0) ? keypad->rotary_up_key[r] : - keypad->rotary_down_key[r]; - - /* simulate a press-n-release */ - input_report_key(dev, keycode, 1); - input_sync(dev); - input_report_key(dev, keycode, 0); - input_sync(dev); - } else { - input_report_rel(dev, keypad->rotary_rel_code[r], delta); - input_sync(dev); - } -} - -static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad) -{ - struct pxa27x_keypad_platform_data *pdata = keypad->pdata; - uint32_t kprec; - - /* read and reset to default count value */ - kprec = keypad_readl(KPREC); - keypad_writel(KPREC, DEFAULT_KPREC); - - if (pdata->enable_rotary0) - report_rotary_event(keypad, 0, rotary_delta(kprec)); - - if (pdata->enable_rotary1) - report_rotary_event(keypad, 1, rotary_delta(kprec >> 16)); -} - -static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) -{ - struct pxa27x_keypad_platform_data *pdata = keypad->pdata; - unsigned int new_state; - uint32_t kpdk, bits_changed; - int i; - - kpdk = keypad_readl(KPDK); - - if (pdata->enable_rotary0 || pdata->enable_rotary1) - pxa27x_keypad_scan_rotary(keypad); - - if (pdata->direct_key_map == NULL) - return; - - new_state = KPDK_DK(kpdk) & keypad->direct_key_mask; - bits_changed = keypad->direct_key_state ^ new_state; - - if (bits_changed == 0) - return; - - for (i = 0; i < pdata->direct_key_num; i++) { - if (bits_changed & (1 << i)) - input_report_key(keypad->input_dev, - pdata->direct_key_map[i], - (new_state & (1 << i))); - } - input_sync(keypad->input_dev); - keypad->direct_key_state = new_state; -} - -static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id) -{ - struct pxa27x_keypad *keypad = dev_id; - unsigned long kpc = keypad_readl(KPC); - - if (kpc & KPC_DI) - pxa27x_keypad_scan_direct(keypad); - - if (kpc & KPC_MI) - pxa27x_keypad_scan_matrix(keypad); - - return IRQ_HANDLED; -} - -static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) -{ - struct pxa27x_keypad_platform_data *pdata = keypad->pdata; - unsigned int mask = 0, direct_key_num = 0; - unsigned long kpc = 0; - - /* enable matrix keys with automatic scan */ - if (pdata->matrix_key_rows && pdata->matrix_key_cols) { - kpc |= KPC_ASACT | KPC_MIE | KPC_ME | KPC_MS_ALL; - kpc |= KPC_MKRN(pdata->matrix_key_rows) | - KPC_MKCN(pdata->matrix_key_cols); - } - - /* enable rotary key, debounce interval same as direct keys */ - if (pdata->enable_rotary0) { - mask |= 0x03; - direct_key_num = 2; - kpc |= KPC_REE0; - } - - if (pdata->enable_rotary1) { - mask |= 0x0c; - direct_key_num = 4; - kpc |= KPC_REE1; - } - - if (pdata->direct_key_num > direct_key_num) - direct_key_num = pdata->direct_key_num; - - keypad->direct_key_mask = ((2 << direct_key_num) - 1) & ~mask; - - /* enable direct key */ - if (direct_key_num) - kpc |= KPC_DE | KPC_DIE | KPC_DKN(direct_key_num); - - keypad_writel(KPC, kpc | KPC_RE_ZERO_DEB); - keypad_writel(KPREC, DEFAULT_KPREC); - keypad_writel(KPKDI, pdata->debounce_interval); -} - -static int pxa27x_keypad_open(struct input_dev *dev) -{ - struct pxa27x_keypad *keypad = input_get_drvdata(dev); - - /* Enable unit clock */ - clk_enable(keypad->clk); - pxa27x_keypad_config(keypad); - - return 0; -} - -static void pxa27x_keypad_close(struct input_dev *dev) -{ - struct pxa27x_keypad *keypad = input_get_drvdata(dev); - - /* Disable clock unit */ - clk_disable(keypad->clk); -} - -#ifdef CONFIG_PM -static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); - - clk_disable(keypad->clk); - return 0; -} - -static int pxa27x_keypad_resume(struct platform_device *pdev) -{ - struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); - struct input_dev *input_dev = keypad->input_dev; - - mutex_lock(&input_dev->mutex); - - if (input_dev->users) { - /* Enable unit clock */ - clk_enable(keypad->clk); - pxa27x_keypad_config(keypad); - } - - mutex_unlock(&input_dev->mutex); - - return 0; -} -#else -#define pxa27x_keypad_suspend NULL -#define pxa27x_keypad_resume NULL -#endif - -#define res_size(res) ((res)->end - (res)->start + 1) - -static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) -{ - struct pxa27x_keypad *keypad; - struct input_dev *input_dev; - struct resource *res; - int irq, error; - - keypad = kzalloc(sizeof(struct pxa27x_keypad), GFP_KERNEL); - if (keypad == NULL) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); - return -ENOMEM; - } - - keypad->pdata = pdev->dev.platform_data; - if (keypad->pdata == NULL) { - dev_err(&pdev->dev, "no platform data defined\n"); - error = -EINVAL; - goto failed_free; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "failed to get keypad irq\n"); - error = -ENXIO; - goto failed_free; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "failed to get I/O memory\n"); - error = -ENXIO; - goto failed_free; - } - - res = request_mem_region(res->start, res_size(res), pdev->name); - if (res == NULL) { - dev_err(&pdev->dev, "failed to request I/O memory\n"); - error = -EBUSY; - goto failed_free; - } - - keypad->mmio_base = ioremap(res->start, res_size(res)); - if (keypad->mmio_base == NULL) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); - error = -ENXIO; - goto failed_free_mem; - } - - keypad->clk = clk_get(&pdev->dev, "KBDCLK"); - if (IS_ERR(keypad->clk)) { - dev_err(&pdev->dev, "failed to get keypad clock\n"); - error = PTR_ERR(keypad->clk); - goto failed_free_io; - } - - /* Create and register the input driver. */ - input_dev = input_allocate_device(); - if (!input_dev) { - dev_err(&pdev->dev, "failed to allocate input device\n"); - error = -ENOMEM; - goto failed_put_clk; - } - - input_dev->name = pdev->name; - input_dev->id.bustype = BUS_HOST; - input_dev->open = pxa27x_keypad_open; - input_dev->close = pxa27x_keypad_close; - input_dev->dev.parent = &pdev->dev; - - keypad->input_dev = input_dev; - input_set_drvdata(input_dev, keypad); - - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | - BIT_MASK(EV_REL); - - pxa27x_keypad_build_keycode(keypad); - platform_set_drvdata(pdev, keypad); - - error = request_irq(irq, pxa27x_keypad_irq_handler, IRQF_DISABLED, - pdev->name, keypad); - if (error) { - dev_err(&pdev->dev, "failed to request IRQ\n"); - goto failed_free_dev; - } - - /* Register the input device */ - error = input_register_device(input_dev); - if (error) { - dev_err(&pdev->dev, "failed to register input device\n"); - goto failed_free_irq; - } - - return 0; - -failed_free_irq: - free_irq(irq, pdev); - platform_set_drvdata(pdev, NULL); -failed_free_dev: - input_free_device(input_dev); -failed_put_clk: - clk_put(keypad->clk); -failed_free_io: - iounmap(keypad->mmio_base); -failed_free_mem: - release_mem_region(res->start, res_size(res)); -failed_free: - kfree(keypad); - return error; -} - -static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) -{ - struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); - struct resource *res; - - free_irq(platform_get_irq(pdev, 0), pdev); - - clk_disable(keypad->clk); - clk_put(keypad->clk); - - input_unregister_device(keypad->input_dev); - input_free_device(keypad->input_dev); - - iounmap(keypad->mmio_base); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res_size(res)); - - platform_set_drvdata(pdev, NULL); - kfree(keypad); - return 0; -} - -static struct platform_driver pxa27x_keypad_driver = { - .probe = pxa27x_keypad_probe, - .remove = __devexit_p(pxa27x_keypad_remove), - .suspend = pxa27x_keypad_suspend, - .resume = pxa27x_keypad_resume, - .driver = { - .name = "pxa27x-keypad", - }, -}; - -static int __init pxa27x_keypad_init(void) -{ - return platform_driver_register(&pxa27x_keypad_driver); -} - -static void __exit pxa27x_keypad_exit(void) -{ - platform_driver_unregister(&pxa27x_keypad_driver); -} - -module_init(pxa27x_keypad_init); -module_exit(pxa27x_keypad_exit); - -MODULE_DESCRIPTION("PXA27x Keypad Controller Driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/input/keyboard/tosakbd.c b/trunk/drivers/input/keyboard/tosakbd.c deleted file mode 100644 index 3884d1e3f070..000000000000 --- a/trunk/drivers/input/keyboard/tosakbd.c +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Keyboard driver for Sharp Tosa models (SL-6000x) - * - * Copyright (c) 2005 Dirk Opfer - * Copyright (c) 2007 Dmitry Baryshkov - * - * Based on xtkbd.c/locomkbd.c/corgikbd.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#define KB_ROWMASK(r) (1 << (r)) -#define SCANCODE(r, c) (((r)<<4) + (c) + 1) -#define NR_SCANCODES SCANCODE(TOSA_KEY_SENSE_NUM - 1, TOSA_KEY_STROBE_NUM - 1) + 1 - -#define SCAN_INTERVAL (HZ/10) - -#define KB_DISCHARGE_DELAY 10 -#define KB_ACTIVATE_DELAY 10 - -static unsigned int tosakbd_keycode[NR_SCANCODES] = { -0, -0, KEY_W, 0, 0, 0, KEY_K, KEY_BACKSPACE, KEY_P, -0, 0, 0, 0, 0, 0, 0, 0, -KEY_Q, KEY_E, KEY_T, KEY_Y, 0, KEY_O, KEY_I, KEY_COMMA, -0, 0, 0, 0, 0, 0, 0, 0, -KEY_A, KEY_D, KEY_G, KEY_U, 0, KEY_L, KEY_ENTER, KEY_DOT, -0, 0, 0, 0, 0, 0, 0, 0, -KEY_Z, KEY_C, KEY_V, KEY_J, TOSA_KEY_ADDRESSBOOK, TOSA_KEY_CANCEL, TOSA_KEY_CENTER, TOSA_KEY_OK, -KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, 0, -KEY_S, KEY_R, KEY_B, KEY_N, TOSA_KEY_CALENDAR, TOSA_KEY_HOMEPAGE, KEY_LEFTCTRL, TOSA_KEY_LIGHT, -0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, -KEY_TAB, KEY_SLASH, KEY_H, KEY_M, TOSA_KEY_MENU, 0, KEY_UP, 0, -0, 0, TOSA_KEY_FN, 0, 0, 0, 0, 0, -KEY_X, KEY_F, KEY_SPACE, KEY_APOSTROPHE, TOSA_KEY_MAIL, KEY_LEFT, KEY_DOWN, KEY_RIGHT, -0, 0, 0, -}; - -struct tosakbd { - unsigned int keycode[ARRAY_SIZE(tosakbd_keycode)]; - struct input_dev *input; - - spinlock_t lock; /* protect kbd scanning */ - struct timer_list timer; -}; - - -/* Helper functions for reading the keyboard matrix - * Note: We should really be using pxa_gpio_mode to alter GPDR but it - * requires a function call per GPIO bit which is excessive - * when we need to access 12 bits at once, multiple times. - * These functions must be called within local_irq_save()/local_irq_restore() - * or similar. - */ -#define GET_ROWS_STATUS(c) ((GPLR2 & TOSA_GPIO_ALL_SENSE_BIT) >> TOSA_GPIO_ALL_SENSE_RSHIFT) - -static inline void tosakbd_discharge_all(void) -{ - /* STROBE All HiZ */ - GPCR1 = TOSA_GPIO_HIGH_STROBE_BIT; - GPDR1 &= ~TOSA_GPIO_HIGH_STROBE_BIT; - GPCR2 = TOSA_GPIO_LOW_STROBE_BIT; - GPDR2 &= ~TOSA_GPIO_LOW_STROBE_BIT; -} - -static inline void tosakbd_activate_all(void) -{ - /* STROBE ALL -> High */ - GPSR1 = TOSA_GPIO_HIGH_STROBE_BIT; - GPDR1 |= TOSA_GPIO_HIGH_STROBE_BIT; - GPSR2 = TOSA_GPIO_LOW_STROBE_BIT; - GPDR2 |= TOSA_GPIO_LOW_STROBE_BIT; - - udelay(KB_DISCHARGE_DELAY); - - /* STATE CLEAR */ - GEDR2 |= TOSA_GPIO_ALL_SENSE_BIT; -} - -static inline void tosakbd_activate_col(int col) -{ - if (col <= 5) { - /* STROBE col -> High, not col -> HiZ */ - GPSR1 = TOSA_GPIO_STROBE_BIT(col); - GPDR1 = (GPDR1 & ~TOSA_GPIO_HIGH_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col); - } else { - /* STROBE col -> High, not col -> HiZ */ - GPSR2 = TOSA_GPIO_STROBE_BIT(col); - GPDR2 = (GPDR2 & ~TOSA_GPIO_LOW_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col); - } -} - -static inline void tosakbd_reset_col(int col) -{ - if (col <= 5) { - /* STROBE col -> Low */ - GPCR1 = TOSA_GPIO_STROBE_BIT(col); - /* STROBE col -> out, not col -> HiZ */ - GPDR1 = (GPDR1 & ~TOSA_GPIO_HIGH_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col); - } else { - /* STROBE col -> Low */ - GPCR2 = TOSA_GPIO_STROBE_BIT(col); - /* STROBE col -> out, not col -> HiZ */ - GPDR2 = (GPDR2 & ~TOSA_GPIO_LOW_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col); - } -} -/* - * The tosa keyboard only generates interrupts when a key is pressed. - * So when a key is pressed, we enable a timer. This timer scans the - * keyboard, and this is how we detect when the key is released. - */ - -/* Scan the hardware keyboard and push any changes up through the input layer */ -static void tosakbd_scankeyboard(struct platform_device *dev) -{ - struct tosakbd *tosakbd = platform_get_drvdata(dev); - unsigned int row, col, rowd; - unsigned long flags; - unsigned int num_pressed = 0; - - spin_lock_irqsave(&tosakbd->lock, flags); - - for (col = 0; col < TOSA_KEY_STROBE_NUM; col++) { - /* - * Discharge the output driver capacitatance - * in the keyboard matrix. (Yes it is significant..) - */ - tosakbd_discharge_all(); - udelay(KB_DISCHARGE_DELAY); - - tosakbd_activate_col(col); - udelay(KB_ACTIVATE_DELAY); - - rowd = GET_ROWS_STATUS(col); - - for (row = 0; row < TOSA_KEY_SENSE_NUM; row++) { - unsigned int scancode, pressed; - scancode = SCANCODE(row, col); - pressed = rowd & KB_ROWMASK(row); - - if (pressed && !tosakbd->keycode[scancode]) - dev_warn(&dev->dev, - "unhandled scancode: 0x%02x\n", - scancode); - - input_report_key(tosakbd->input, - tosakbd->keycode[scancode], - pressed); - if (pressed) - num_pressed++; - } - - tosakbd_reset_col(col); - } - - tosakbd_activate_all(); - - input_sync(tosakbd->input); - - /* if any keys are pressed, enable the timer */ - if (num_pressed) - mod_timer(&tosakbd->timer, jiffies + SCAN_INTERVAL); - - spin_unlock_irqrestore(&tosakbd->lock, flags); -} - -/* - * tosa keyboard interrupt handler. - */ -static irqreturn_t tosakbd_interrupt(int irq, void *__dev) -{ - struct platform_device *dev = __dev; - struct tosakbd *tosakbd = platform_get_drvdata(dev); - - if (!timer_pending(&tosakbd->timer)) { - /** wait chattering delay **/ - udelay(20); - tosakbd_scankeyboard(dev); - } - - return IRQ_HANDLED; -} - -/* - * tosa timer checking for released keys - */ -static void tosakbd_timer_callback(unsigned long __dev) -{ - struct platform_device *dev = (struct platform_device *)__dev; - tosakbd_scankeyboard(dev); -} - -#ifdef CONFIG_PM -static int tosakbd_suspend(struct platform_device *dev, pm_message_t state) -{ - struct tosakbd *tosakbd = platform_get_drvdata(dev); - - del_timer_sync(&tosakbd->timer); - - return 0; -} - -static int tosakbd_resume(struct platform_device *dev) -{ - tosakbd_scankeyboard(dev); - - return 0; -} -#else -#define tosakbd_suspend NULL -#define tosakbd_resume NULL -#endif - -static int __devinit tosakbd_probe(struct platform_device *pdev) { - - int i; - struct tosakbd *tosakbd; - struct input_dev *input_dev; - int error; - - tosakbd = kzalloc(sizeof(struct tosakbd), GFP_KERNEL); - if (!tosakbd) - return -ENOMEM; - - input_dev = input_allocate_device(); - if (!input_dev) { - kfree(tosakbd); - return -ENOMEM; - } - - platform_set_drvdata(pdev, tosakbd); - - spin_lock_init(&tosakbd->lock); - - /* Init Keyboard rescan timer */ - init_timer(&tosakbd->timer); - tosakbd->timer.function = tosakbd_timer_callback; - tosakbd->timer.data = (unsigned long) pdev; - - tosakbd->input = input_dev; - - input_set_drvdata(input_dev, tosakbd); - input_dev->name = "Tosa Keyboard"; - input_dev->phys = "tosakbd/input0"; - input_dev->dev.parent = &pdev->dev; - - input_dev->id.bustype = BUS_HOST; - input_dev->id.vendor = 0x0001; - input_dev->id.product = 0x0001; - input_dev->id.version = 0x0100; - - input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - input_dev->keycode = tosakbd->keycode; - input_dev->keycodesize = sizeof(unsigned int); - input_dev->keycodemax = ARRAY_SIZE(tosakbd_keycode); - - memcpy(tosakbd->keycode, tosakbd_keycode, sizeof(tosakbd_keycode)); - - for (i = 0; i < ARRAY_SIZE(tosakbd_keycode); i++) - __set_bit(tosakbd->keycode[i], input_dev->keybit); - clear_bit(0, input_dev->keybit); - - /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ - for (i = 0; i < TOSA_KEY_SENSE_NUM; i++) { - int gpio = TOSA_GPIO_KEY_SENSE(i); - int irq; - error = gpio_request(gpio, "tosakbd"); - if (error < 0) { - printk(KERN_ERR "tosakbd: failed to request GPIO %d, " - " error %d\n", gpio, error); - goto fail; - } - - error = gpio_direction_input(TOSA_GPIO_KEY_SENSE(i)); - if (error < 0) { - printk(KERN_ERR "tosakbd: failed to configure input" - " direction for GPIO %d, error %d\n", - gpio, error); - gpio_free(gpio); - goto fail; - } - - irq = gpio_to_irq(gpio); - if (irq < 0) { - error = irq; - printk(KERN_ERR "gpio-keys: Unable to get irq number" - " for GPIO %d, error %d\n", - gpio, error); - gpio_free(gpio); - goto fail; - } - - error = request_irq(irq, tosakbd_interrupt, - IRQF_DISABLED | IRQF_TRIGGER_RISING, - "tosakbd", pdev); - - if (error) { - printk("tosakbd: Can't get IRQ: %d: error %d!\n", - irq, error); - gpio_free(gpio); - goto fail; - } - } - - /* Set Strobe lines as outputs - set high */ - for (i = 0; i < TOSA_KEY_STROBE_NUM; i++) { - int gpio = TOSA_GPIO_KEY_STROBE(i); - error = gpio_request(gpio, "tosakbd"); - if (error < 0) { - printk(KERN_ERR "tosakbd: failed to request GPIO %d, " - " error %d\n", gpio, error); - goto fail2; - } - - error = gpio_direction_output(gpio, 1); - if (error < 0) { - printk(KERN_ERR "tosakbd: failed to configure input" - " direction for GPIO %d, error %d\n", - gpio, error); - gpio_free(gpio); - goto fail; - } - - } - - error = input_register_device(input_dev); - if (error) { - printk(KERN_ERR "tosakbd: Unable to register input device, " - "error: %d\n", error); - goto fail; - } - - printk(KERN_INFO "input: Tosa Keyboard Registered\n"); - - return 0; - -fail2: - while (--i >= 0) - gpio_free(TOSA_GPIO_KEY_STROBE(i)); - - i = TOSA_KEY_SENSE_NUM; -fail: - while (--i >= 0) { - free_irq(gpio_to_irq(TOSA_GPIO_KEY_SENSE(i)), pdev); - gpio_free(TOSA_GPIO_KEY_SENSE(i)); - } - - platform_set_drvdata(pdev, NULL); - input_free_device(input_dev); - kfree(tosakbd); - - return error; -} - -static int __devexit tosakbd_remove(struct platform_device *dev) { - - int i; - struct tosakbd *tosakbd = platform_get_drvdata(dev); - - for (i = 0; i < TOSA_KEY_STROBE_NUM; i++) - gpio_free(TOSA_GPIO_KEY_STROBE(i)); - - for (i = 0; i < TOSA_KEY_SENSE_NUM; i++) { - free_irq(gpio_to_irq(TOSA_GPIO_KEY_SENSE(i)), dev); - gpio_free(TOSA_GPIO_KEY_SENSE(i)); - } - - del_timer_sync(&tosakbd->timer); - - input_unregister_device(tosakbd->input); - - kfree(tosakbd); - - return 0; -} - -static struct platform_driver tosakbd_driver = { - .probe = tosakbd_probe, - .remove = __devexit_p(tosakbd_remove), - .suspend = tosakbd_suspend, - .resume = tosakbd_resume, - .driver = { - .name = "tosa-keyboard", - }, -}; - -static int __devinit tosakbd_init(void) -{ - return platform_driver_register(&tosakbd_driver); -} - -static void __exit tosakbd_exit(void) -{ - platform_driver_unregister(&tosakbd_driver); -} - -module_init(tosakbd_init); -module_exit(tosakbd_exit); - -MODULE_AUTHOR("Dirk Opfer "); -MODULE_DESCRIPTION("Tosa Keyboard Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/input/misc/Kconfig b/trunk/drivers/input/misc/Kconfig index 8b10d9f23bef..8f5c7b90187d 100644 --- a/trunk/drivers/input/misc/Kconfig +++ b/trunk/drivers/input/misc/Kconfig @@ -40,20 +40,6 @@ config INPUT_M68K_BEEP tristate "M68k Beeper support" depends on M68K -config INPUT_APANEL - tristate "Fujitsu Lifebook Application Panel buttons" - depends on X86 - select I2C_I801 - select INPUT_POLLDEV - select CHECK_SIGNATURE - help - Say Y here for support of the Application Panel buttons, used on - Fujitsu Lifebook. These are attached to the mainboard through - an SMBus interface managed by the I2C Intel ICH (i801) driver. - - To compile this driver as a module, choose M here: the module will - be called apanel. - config INPUT_IXP4XX_BEEPER tristate "IXP4XX Beeper support" depends on ARCH_IXP4XX diff --git a/trunk/drivers/input/misc/Makefile b/trunk/drivers/input/misc/Makefile index ebd39f291d25..3585b5038418 100644 --- a/trunk/drivers/input/misc/Makefile +++ b/trunk/drivers/input/misc/Makefile @@ -18,4 +18,3 @@ obj-$(CONFIG_INPUT_POWERMATE) += powermate.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o -obj-$(CONFIG_INPUT_APANEL) += apanel.o diff --git a/trunk/drivers/input/misc/apanel.c b/trunk/drivers/input/misc/apanel.c deleted file mode 100644 index 9531d8c7444f..000000000000 --- a/trunk/drivers/input/misc/apanel.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Fujitsu Lifebook Application Panel button drive - * - * Copyright (C) 2007 Stephen Hemminger - * Copyright (C) 2001-2003 Jochen Eisinger - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * Many Fujitsu Lifebook laptops have a small panel of buttons that are - * accessible via the i2c/smbus interface. This driver polls those - * buttons and generates input events. - * - * For more details see: - * http://apanel.sourceforge.net/tech.php - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define APANEL_NAME "Fujitsu Application Panel" -#define APANEL_VERSION "1.3.1" -#define APANEL "apanel" - -/* How often we poll keys - msecs */ -#define POLL_INTERVAL_DEFAULT 1000 - -/* Magic constants in BIOS that tell about buttons */ -enum apanel_devid { - APANEL_DEV_NONE = 0, - APANEL_DEV_APPBTN = 1, - APANEL_DEV_CDBTN = 2, - APANEL_DEV_LCD = 3, - APANEL_DEV_LED = 4, - - APANEL_DEV_MAX, -}; - -enum apanel_chip { - CHIP_NONE = 0, - CHIP_OZ992C = 1, - CHIP_OZ163T = 2, - CHIP_OZ711M3 = 4, -}; - -/* Result of BIOS snooping/probing -- what features are supported */ -static enum apanel_chip device_chip[APANEL_DEV_MAX]; - -#define MAX_PANEL_KEYS 12 - -struct apanel { - struct input_polled_dev *ipdev; - struct i2c_client client; - unsigned short keymap[MAX_PANEL_KEYS]; - u16 nkeys; - u16 led_bits; - struct work_struct led_work; - struct led_classdev mail_led; -}; - - -static int apanel_probe(struct i2c_adapter *, int, int); - -/* for now, we only support one address */ -static unsigned short normal_i2c[] = {0, I2C_CLIENT_END}; -static unsigned short ignore = I2C_CLIENT_END; -static struct i2c_client_address_data addr_data = { - .normal_i2c = normal_i2c, - .probe = &ignore, - .ignore = &ignore, -}; - -static void report_key(struct input_dev *input, unsigned keycode) -{ - pr_debug(APANEL ": report key %#x\n", keycode); - input_report_key(input, keycode, 1); - input_sync(input); - - input_report_key(input, keycode, 0); - input_sync(input); -} - -/* Poll for key changes - * - * Read Application keys via SMI - * A (0x4), B (0x8), Internet (0x2), Email (0x1). - * - * CD keys: - * Forward (0x100), Rewind (0x200), Stop (0x400), Pause (0x800) - */ -static void apanel_poll(struct input_polled_dev *ipdev) -{ - struct apanel *ap = ipdev->private; - struct input_dev *idev = ipdev->input; - u8 cmd = device_chip[APANEL_DEV_APPBTN] == CHIP_OZ992C ? 0 : 8; - s32 data; - int i; - - data = i2c_smbus_read_word_data(&ap->client, cmd); - if (data < 0) - return; /* ignore errors (due to ACPI??) */ - - /* write back to clear latch */ - i2c_smbus_write_word_data(&ap->client, cmd, 0); - - if (!data) - return; - - dev_dbg(&idev->dev, APANEL ": data %#x\n", data); - for (i = 0; i < idev->keycodemax; i++) - if ((1u << i) & data) - report_key(idev, ap->keymap[i]); -} - -/* Track state changes of LED */ -static void led_update(struct work_struct *work) -{ - struct apanel *ap = container_of(work, struct apanel, led_work); - - i2c_smbus_write_word_data(&ap->client, 0x10, ap->led_bits); -} - -static void mail_led_set(struct led_classdev *led, - enum led_brightness value) -{ - struct apanel *ap = container_of(led, struct apanel, mail_led); - - if (value != LED_OFF) - ap->led_bits |= 0x8000; - else - ap->led_bits &= ~0x8000; - - schedule_work(&ap->led_work); -} - -static int apanel_detach_client(struct i2c_client *client) -{ - struct apanel *ap = i2c_get_clientdata(client); - - if (device_chip[APANEL_DEV_LED] != CHIP_NONE) - led_classdev_unregister(&ap->mail_led); - - input_unregister_polled_device(ap->ipdev); - i2c_detach_client(&ap->client); - input_free_polled_device(ap->ipdev); - - return 0; -} - -/* Function is invoked for every i2c adapter. */ -static int apanel_attach_adapter(struct i2c_adapter *adap) -{ - dev_dbg(&adap->dev, APANEL ": attach adapter id=%d\n", adap->id); - - /* Our device is connected only to i801 on laptop */ - if (adap->id != I2C_HW_SMBUS_I801) - return -ENODEV; - - return i2c_probe(adap, &addr_data, apanel_probe); -} - -static void apanel_shutdown(struct i2c_client *client) -{ - apanel_detach_client(client); -} - -static struct i2c_driver apanel_driver = { - .driver = { - .name = APANEL, - }, - .attach_adapter = &apanel_attach_adapter, - .detach_client = &apanel_detach_client, - .shutdown = &apanel_shutdown, -}; - -static struct apanel apanel = { - .client = { - .driver = &apanel_driver, - .name = APANEL, - }, - .keymap = { - [0] = KEY_MAIL, - [1] = KEY_WWW, - [2] = KEY_PROG2, - [3] = KEY_PROG1, - - [8] = KEY_FORWARD, - [9] = KEY_REWIND, - [10] = KEY_STOPCD, - [11] = KEY_PLAYPAUSE, - - }, - .mail_led = { - .name = "mail:blue", - .brightness_set = mail_led_set, - }, -}; - -/* NB: Only one panel on the i2c. */ -static int apanel_probe(struct i2c_adapter *bus, int address, int kind) -{ - struct apanel *ap; - struct input_polled_dev *ipdev; - struct input_dev *idev; - u8 cmd = device_chip[APANEL_DEV_APPBTN] == CHIP_OZ992C ? 0 : 8; - int i, err = -ENOMEM; - - dev_dbg(&bus->dev, APANEL ": probe adapter %p addr %d kind %d\n", - bus, address, kind); - - ap = &apanel; - - ipdev = input_allocate_polled_device(); - if (!ipdev) - goto out1; - - ap->ipdev = ipdev; - ap->client.adapter = bus; - ap->client.addr = address; - - i2c_set_clientdata(&ap->client, ap); - - err = i2c_attach_client(&ap->client); - if (err) - goto out2; - - err = i2c_smbus_write_word_data(&ap->client, cmd, 0); - if (err) { - dev_warn(&ap->client.dev, APANEL ": smbus write error %d\n", - err); - goto out3; - } - - ipdev->poll = apanel_poll; - ipdev->poll_interval = POLL_INTERVAL_DEFAULT; - ipdev->private = ap; - - idev = ipdev->input; - idev->name = APANEL_NAME " buttons"; - idev->phys = "apanel/input0"; - idev->id.bustype = BUS_HOST; - idev->dev.parent = &ap->client.dev; - - set_bit(EV_KEY, idev->evbit); - - idev->keycode = ap->keymap; - idev->keycodesize = sizeof(ap->keymap[0]); - idev->keycodemax = (device_chip[APANEL_DEV_CDBTN] != CHIP_NONE) ? 12 : 4; - - for (i = 0; i < idev->keycodemax; i++) - if (ap->keymap[i]) - set_bit(ap->keymap[i], idev->keybit); - - err = input_register_polled_device(ipdev); - if (err) - goto out3; - - INIT_WORK(&ap->led_work, led_update); - if (device_chip[APANEL_DEV_LED] != CHIP_NONE) { - err = led_classdev_register(&ap->client.dev, &ap->mail_led); - if (err) - goto out4; - } - - return 0; -out4: - input_unregister_polled_device(ipdev); -out3: - i2c_detach_client(&ap->client); -out2: - input_free_polled_device(ipdev); -out1: - return err; -} - -/* Scan the system ROM for the signature "FJKEYINF" */ -static __init const void __iomem *bios_signature(const void __iomem *bios) -{ - ssize_t offset; - const unsigned char signature[] = "FJKEYINF"; - - for (offset = 0; offset < 0x10000; offset += 0x10) { - if (check_signature(bios + offset, signature, - sizeof(signature)-1)) - return bios + offset; - } - pr_notice(APANEL ": Fujitsu BIOS signature '%s' not found...\n", - signature); - return NULL; -} - -static int __init apanel_init(void) -{ - void __iomem *bios; - const void __iomem *p; - u8 devno; - int found = 0; - - bios = ioremap(0xF0000, 0x10000); /* Can't fail */ - - p = bios_signature(bios); - if (!p) { - iounmap(bios); - return -ENODEV; - } - - /* just use the first address */ - p += 8; - normal_i2c[0] = readb(p+3) >> 1; - - for ( ; (devno = readb(p)) & 0x7f; p += 4) { - unsigned char method, slave, chip; - - method = readb(p + 1); - chip = readb(p + 2); - slave = readb(p + 3) >> 1; - - if (slave != normal_i2c[0]) { - pr_notice(APANEL ": only one SMBus slave " - "address supported, skiping device...\n"); - continue; - } - - /* translate alternative device numbers */ - switch (devno) { - case 6: - devno = APANEL_DEV_APPBTN; - break; - case 7: - devno = APANEL_DEV_LED; - break; - } - - if (devno >= APANEL_DEV_MAX) - pr_notice(APANEL ": unknown device %u found\n", devno); - else if (device_chip[devno] != CHIP_NONE) - pr_warning(APANEL ": duplicate entry for devno %u\n", devno); - - else if (method != 1 && method != 2 && method != 4) { - pr_notice(APANEL ": unknown method %u for devno %u\n", - method, devno); - } else { - device_chip[devno] = (enum apanel_chip) chip; - ++found; - } - } - iounmap(bios); - - if (found == 0) { - pr_info(APANEL ": no input devices reported by BIOS\n"); - return -EIO; - } - - return i2c_add_driver(&apanel_driver); -} -module_init(apanel_init); - -static void __exit apanel_cleanup(void) -{ - i2c_del_driver(&apanel_driver); -} -module_exit(apanel_cleanup); - -MODULE_AUTHOR("Stephen Hemminger "); -MODULE_DESCRIPTION(APANEL_NAME " driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(APANEL_VERSION); - -MODULE_ALIAS("dmi:*:svnFUJITSU:pnLifeBook*:pvr*:rvnFUJITSU:*"); -MODULE_ALIAS("dmi:*:svnFUJITSU:pnLifebook*:pvr*:rvnFUJITSU:*"); diff --git a/trunk/drivers/input/misc/ati_remote.c b/trunk/drivers/input/misc/ati_remote.c index f3b86c2b0797..3a7937481ad8 100644 --- a/trunk/drivers/input/misc/ati_remote.c +++ b/trunk/drivers/input/misc/ati_remote.c @@ -90,6 +90,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/input/misc/atlas_btns.c b/trunk/drivers/input/misc/atlas_btns.c index 1b871917340a..4e3ad657ed80 100644 --- a/trunk/drivers/input/misc/atlas_btns.c +++ b/trunk/drivers/input/misc/atlas_btns.c @@ -29,10 +29,9 @@ #include #include -#define ACPI_ATLAS_NAME "Atlas ACPI" -#define ACPI_ATLAS_CLASS "Atlas" +#define ACPI_ATLAS_NAME "Atlas ACPI" +#define ACPI_ATLAS_CLASS "Atlas" -static unsigned short atlas_keymap[16]; static struct input_dev *input_dev; /* button handling code */ @@ -51,15 +50,12 @@ static acpi_status acpi_atlas_button_handler(u32 function, void *handler_context, void *region_context) { acpi_status status; + int keycode; if (function == ACPI_WRITE) { - int code = address & 0x0f; - int key_down = !(address & 0x10); - - input_event(input_dev, EV_MSC, MSC_SCAN, code); - input_report_key(input_dev, atlas_keymap[code], key_down); + keycode = KEY_F1 + (address & 0x0F); + input_report_key(input_dev, keycode, !(address & 0x10)); input_sync(input_dev); - status = 0; } else { printk(KERN_WARNING "atlas: shrugged on unexpected function" @@ -74,7 +70,6 @@ static acpi_status acpi_atlas_button_handler(u32 function, static int atlas_acpi_button_add(struct acpi_device *device) { acpi_status status; - int i; int err; input_dev = input_allocate_device(); @@ -86,19 +81,17 @@ static int atlas_acpi_button_add(struct acpi_device *device) input_dev->name = "Atlas ACPI button driver"; input_dev->phys = "ASIM0000/atlas/input0"; input_dev->id.bustype = BUS_HOST; - input_dev->keycode = atlas_keymap; - input_dev->keycodesize = sizeof(unsigned short); - input_dev->keycodemax = ARRAY_SIZE(atlas_keymap); - - input_set_capability(input_dev, EV_MSC, MSC_SCAN); - __set_bit(EV_KEY, input_dev->evbit); - for (i = 0; i < ARRAY_SIZE(atlas_keymap); i++) { - if (i < 9) { - atlas_keymap[i] = KEY_F1 + i; - __set_bit(KEY_F1 + i, input_dev->keybit); - } else - atlas_keymap[i] = KEY_RESERVED; - } + input_dev->evbit[BIT_WORD(EV_KEY)] = BIT_MASK(EV_KEY); + + set_bit(KEY_F1, input_dev->keybit); + set_bit(KEY_F2, input_dev->keybit); + set_bit(KEY_F3, input_dev->keybit); + set_bit(KEY_F4, input_dev->keybit); + set_bit(KEY_F5, input_dev->keybit); + set_bit(KEY_F6, input_dev->keybit); + set_bit(KEY_F7, input_dev->keybit); + set_bit(KEY_F8, input_dev->keybit); + set_bit(KEY_F9, input_dev->keybit); err = input_register_device(input_dev); if (err) { diff --git a/trunk/drivers/input/misc/cobalt_btns.c b/trunk/drivers/input/misc/cobalt_btns.c index 4833b1a82623..1aef97ed5e84 100644 --- a/trunk/drivers/input/misc/cobalt_btns.c +++ b/trunk/drivers/input/misc/cobalt_btns.c @@ -27,48 +27,55 @@ #define BUTTONS_COUNT_THRESHOLD 3 #define BUTTONS_STATUS_MASK 0xfe000000 -static const unsigned short cobalt_map[] = { - KEY_RESERVED, - KEY_RESTART, - KEY_LEFT, - KEY_UP, - KEY_DOWN, - KEY_RIGHT, - KEY_ENTER, - KEY_SELECT -}; - struct buttons_dev { struct input_polled_dev *poll_dev; - unsigned short keymap[ARRAY_SIZE(cobalt_map)]; - int count[ARRAY_SIZE(cobalt_map)]; void __iomem *reg; }; +struct buttons_map { + uint32_t mask; + int keycode; + int count; +}; + +static struct buttons_map buttons_map[] = { + { 0x02000000, KEY_RESTART, }, + { 0x04000000, KEY_LEFT, }, + { 0x08000000, KEY_UP, }, + { 0x10000000, KEY_DOWN, }, + { 0x20000000, KEY_RIGHT, }, + { 0x40000000, KEY_ENTER, }, + { 0x80000000, KEY_SELECT, }, +}; + static void handle_buttons(struct input_polled_dev *dev) { + struct buttons_map *button = buttons_map; struct buttons_dev *bdev = dev->private; struct input_dev *input = dev->input; uint32_t status; int i; - status = ~readl(bdev->reg) >> 24; + status = readl(bdev->reg); + status = ~status & BUTTONS_STATUS_MASK; - for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) { - if (status & (1UL << i)) { - if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) { - input_event(input, EV_MSC, MSC_SCAN, i); - input_report_key(input, bdev->keymap[i], 1); - input_sync(input); - } + for (i = 0; i < ARRAY_SIZE(buttons_map); i++) { + if (status & button->mask) { + button->count++; } else { - if (bdev->count[i] >= BUTTONS_COUNT_THRESHOLD) { - input_event(input, EV_MSC, MSC_SCAN, i); - input_report_key(input, bdev->keymap[i], 0); + if (button->count >= BUTTONS_COUNT_THRESHOLD) { + input_report_key(input, button->keycode, 0); input_sync(input); } - bdev->count[i] = 0; + button->count = 0; + } + + if (button->count == BUTTONS_COUNT_THRESHOLD) { + input_report_key(input, button->keycode, 1); + input_sync(input); } + + button++; } } @@ -87,8 +94,6 @@ static int __devinit cobalt_buttons_probe(struct platform_device *pdev) goto err_free_mem; } - memcpy(bdev->keymap, cobalt_map, sizeof(bdev->keymap)); - poll_dev->private = bdev; poll_dev->poll = handle_buttons; poll_dev->poll_interval = BUTTONS_POLL_INTERVAL; @@ -99,15 +104,11 @@ static int __devinit cobalt_buttons_probe(struct platform_device *pdev) input->id.bustype = BUS_HOST; input->cdev.dev = &pdev->dev; - input->keycode = pdev->keymap; - input->keycodemax = ARRAY_SIZE(pdev->keymap); - input->keycodesize = sizeof(unsigned short); - - input_set_capability(input, EV_MSC, MSC_SCAN); - __set_bit(EV_KEY, input->evbit); - for (i = 0; i < ARRAY_SIZE(buttons_map); i++) - __set_bit(input->keycode[i], input->keybit); - __clear_bit(KEY_RESERVED, input->keybit); + input->evbit[0] = BIT_MASK(EV_KEY); + for (i = 0; i < ARRAY_SIZE(buttons_map); i++) { + set_bit(buttons_map[i].keycode, input->keybit); + buttons_map[i].count = 0; + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { diff --git a/trunk/drivers/input/misc/keyspan_remote.c b/trunk/drivers/input/misc/keyspan_remote.c index 952938a8e991..fd74347047dd 100644 --- a/trunk/drivers/input/misc/keyspan_remote.c +++ b/trunk/drivers/input/misc/keyspan_remote.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #define DRIVER_VERSION "v0.1" @@ -45,12 +46,53 @@ MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); #define RECV_SIZE 8 /* The UIA-11 type have a 8 byte limit. */ +/* table of devices that work with this driver */ +static struct usb_device_id keyspan_table[] = { + { USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) }, + { } /* Terminating entry */ +}; + +/* Structure to store all the real stuff that a remote sends to us. */ +struct keyspan_message { + u16 system; + u8 button; + u8 toggle; +}; + +/* Structure used for all the bit testing magic needed to be done. */ +struct bit_tester { + u32 tester; + int len; + int pos; + int bits_left; + u8 buffer[32]; +}; + +/* Structure to hold all of our driver specific stuff */ +struct usb_keyspan { + char name[128]; + char phys[64]; + struct usb_device* udev; + struct input_dev *input; + struct usb_interface* interface; + struct usb_endpoint_descriptor* in_endpoint; + struct urb* irq_urb; + int open; + dma_addr_t in_dma; + unsigned char* in_buffer; + + /* variables used to parse messages from remote. */ + struct bit_tester data; + int stage; + int toggle; +}; + /* * Table that maps the 31 possible keycodes to input keys. * Currently there are 15 and 17 button models so RESERVED codes * are blank areas in the mapping. */ -static const unsigned short keyspan_key_table[] = { +static const int keyspan_key_table[] = { KEY_RESERVED, /* 0 is just a place holder. */ KEY_RESERVED, KEY_STOP, @@ -85,48 +127,6 @@ static const unsigned short keyspan_key_table[] = { KEY_MENU }; -/* table of devices that work with this driver */ -static struct usb_device_id keyspan_table[] = { - { USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) }, - { } /* Terminating entry */ -}; - -/* Structure to store all the real stuff that a remote sends to us. */ -struct keyspan_message { - u16 system; - u8 button; - u8 toggle; -}; - -/* Structure used for all the bit testing magic needed to be done. */ -struct bit_tester { - u32 tester; - int len; - int pos; - int bits_left; - u8 buffer[32]; -}; - -/* Structure to hold all of our driver specific stuff */ -struct usb_keyspan { - char name[128]; - char phys[64]; - unsigned short keymap[ARRAY_SIZE(keyspan_key_table)]; - struct usb_device *udev; - struct input_dev *input; - struct usb_interface *interface; - struct usb_endpoint_descriptor *in_endpoint; - struct urb* irq_urb; - int open; - dma_addr_t in_dma; - unsigned char *in_buffer; - - /* variables used to parse messages from remote. */ - struct bit_tester data; - int stage; - int toggle; -}; - static struct usb_driver keyspan_driver; /* @@ -173,15 +173,6 @@ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) return 0; } -static void keyspan_report_button(struct usb_keyspan *remote, int button, int press) -{ - struct input_dev *input = remote->input; - - input_event(input, EV_MSC, MSC_SCAN, button); - input_report_key(input, remote->keymap[button], press); - input_sync(input); -} - /* * Routine that handles all the logic needed to parse out the message from the remote. */ @@ -320,8 +311,9 @@ static void keyspan_check_data(struct usb_keyspan *remote) __FUNCTION__, message.system, message.button, message.toggle); if (message.toggle != remote->toggle) { - keyspan_report_button(remote, message.button, 1); - keyspan_report_button(remote, message.button, 0); + input_report_key(remote->input, keyspan_key_table[message.button], 1); + input_report_key(remote->input, keyspan_key_table[message.button], 0); + input_sync(remote->input); remote->toggle = message.toggle; } @@ -499,21 +491,16 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic usb_make_path(udev, remote->phys, sizeof(remote->phys)); strlcat(remote->phys, "/input0", sizeof(remote->phys)); - memcpy(remote->keymap, keyspan_key_table, sizeof(remote->keymap)); input_dev->name = remote->name; input_dev->phys = remote->phys; usb_to_input_id(udev, &input_dev->id); input_dev->dev.parent = &interface->dev; - input_dev->keycode = remote->keymap; - input_dev->keycodesize = sizeof(unsigned short); - input_dev->keycodemax = ARRAY_SIZE(remote->keymap); - input_set_capability(input_dev, EV_MSC, MSC_SCAN); - __set_bit(EV_KEY, input_dev->evbit); + input_dev->evbit[0] = BIT_MASK(EV_KEY); /* We will only report KEY events. */ for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++) - __set_bit(keyspan_key_table[i], input_dev->keybit); - __clear_bit(KEY_RESERVED, input_dev->keybit); + if (keyspan_key_table[i] != KEY_RESERVED) + set_bit(keyspan_key_table[i], input_dev->keybit); input_set_drvdata(input_dev, remote); @@ -521,14 +508,12 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic input_dev->close = keyspan_close; /* - * Initialize the URB to access the device. - * The urb gets sent to the device in keyspan_open() + * Initialize the URB to access the device. The urb gets sent to the device in keyspan_open() */ usb_fill_int_urb(remote->irq_urb, - remote->udev, - usb_rcvintpipe(remote->udev, endpoint->bEndpointAddress), + remote->udev, usb_rcvintpipe(remote->udev, remote->in_endpoint->bEndpointAddress), remote->in_buffer, RECV_SIZE, keyspan_irq_recv, remote, - endpoint->bInterval); + remote->in_endpoint->bInterval); remote->irq_urb->transfer_dma = remote->in_dma; remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; diff --git a/trunk/drivers/input/mouse/inport.c b/trunk/drivers/input/mouse/inport.c index 06c35fc553c0..26ec09529b51 100644 --- a/trunk/drivers/input/mouse/inport.c +++ b/trunk/drivers/input/mouse/inport.c @@ -35,6 +35,7 @@ */ #include +#include #include #include #include diff --git a/trunk/drivers/input/mouse/logibm.c b/trunk/drivers/input/mouse/logibm.c index 9ea895593b27..37e7c75b43bd 100644 --- a/trunk/drivers/input/mouse/logibm.c +++ b/trunk/drivers/input/mouse/logibm.c @@ -36,6 +36,7 @@ */ #include +#include #include #include #include diff --git a/trunk/drivers/input/mouse/psmouse-base.c b/trunk/drivers/input/mouse/psmouse-base.c index f5a6be1d3c46..b8628252e10c 100644 --- a/trunk/drivers/input/mouse/psmouse-base.c +++ b/trunk/drivers/input/mouse/psmouse-base.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/input/mouse/trackpoint.c b/trunk/drivers/input/mouse/trackpoint.c index 26b845fc186a..9ab5b5ea809d 100644 --- a/trunk/drivers/input/mouse/trackpoint.c +++ b/trunk/drivers/input/mouse/trackpoint.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/input/mousedev.c b/trunk/drivers/input/mousedev.c index bbbe5e81adc1..be83516c776c 100644 --- a/trunk/drivers/input/mousedev.c +++ b/trunk/drivers/input/mousedev.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -1032,7 +1033,7 @@ static const struct input_device_id mousedev_ids[] = { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, - .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) }, + .evbit = { BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_SYN) }, .keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) }, .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, }, /* Mouse-like device with absolute X and Y but ordinary diff --git a/trunk/drivers/input/serio/i8042-x86ia64io.h b/trunk/drivers/input/serio/i8042-x86ia64io.h index 662e84482c26..c5e68dcd88ac 100644 --- a/trunk/drivers/input/serio/i8042-x86ia64io.h +++ b/trunk/drivers/input/serio/i8042-x86ia64io.h @@ -63,7 +63,7 @@ static inline void i8042_write_command(int val) outb(val, I8042_COMMAND_REG); } -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) #include @@ -185,13 +185,6 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"), }, }, - { - .ident = "Fujitsu-Siemens Amilo Pro 2010", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"), - }, - }, { /* * No data is coming from the touchscreen unless KBC @@ -284,57 +277,6 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { #endif -#ifdef CONFIG_X86 - -#include - -/* - * Some Wistron based laptops need us to explicitly enable the 'Dritek - * keyboard extension' to make their extra keys start generating scancodes. - * Originally, this was just confined to older laptops, but a few Acer laptops - * have turned up in 2007 that also need this again. - */ -static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = { - { - .ident = "Acer Aspire 5630", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), - }, - }, - { - .ident = "Acer Aspire 5650", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), - }, - }, - { - .ident = "Acer Aspire 5680", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), - }, - }, - { - .ident = "Acer Aspire 9110", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), - }, - }, - { - .ident = "Acer TravelMate 2490", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), - }, - }, - { } -}; - -#endif /* CONFIG_X86 */ - #ifdef CONFIG_PNP #include @@ -570,7 +512,7 @@ static int __init i8042_platform_init(void) i8042_reset = 1; #endif -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) if (dmi_check_system(i8042_dmi_noloop_table)) i8042_noloop = 1; @@ -578,11 +520,6 @@ static int __init i8042_platform_init(void) i8042_nomux = 1; #endif -#ifdef CONFIG_X86 - if (dmi_check_system(i8042_dmi_dritek_table)) - i8042_dritek = 1; -#endif /* CONFIG_X86 */ - return retval; } diff --git a/trunk/drivers/input/serio/i8042.c b/trunk/drivers/input/serio/i8042.c index 2763394869d2..1a0cea3c5294 100644 --- a/trunk/drivers/input/serio/i8042.c +++ b/trunk/drivers/input/serio/i8042.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -63,12 +64,6 @@ static unsigned int i8042_blink_frequency = 500; module_param_named(panicblink, i8042_blink_frequency, uint, 0600); MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics"); -#ifdef CONFIG_X86 -static unsigned int i8042_dritek; -module_param_named(dritek, i8042_dritek, bool, 0); -MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension"); -#endif - #ifdef CONFIG_PNP static int i8042_nopnp; module_param_named(nopnp, i8042_nopnp, bool, 0); @@ -285,14 +280,7 @@ static void i8042_stop(struct serio *serio) struct i8042_port *port = serio->port_data; port->exists = 0; - - /* - * We synchronize with both AUX and KBD IRQs because there is - * a (very unlikely) chance that AUX IRQ is raised for KBD port - * and vice versa. - */ - synchronize_irq(I8042_AUX_IRQ); - synchronize_irq(I8042_KBD_IRQ); + synchronize_sched(); port->serio = NULL; } @@ -1151,7 +1139,6 @@ static int __devinit i8042_setup_kbd(void) static int __devinit i8042_probe(struct platform_device *dev) { int error; - char param; error = i8042_controller_selftest(); if (error) @@ -1172,14 +1159,7 @@ static int __devinit i8042_probe(struct platform_device *dev) if (error) goto out_fail; } -#ifdef CONFIG_X86 - if (i8042_dritek) { - param = 0x90; - error = i8042_command(¶m, 0x1059); - if (error) - goto out_fail; - } -#endif + /* * Ok, everything is ready, let's register all serio ports */ diff --git a/trunk/drivers/input/serio/libps2.c b/trunk/drivers/input/serio/libps2.c index b819239d74dc..10d9d74ae43a 100644 --- a/trunk/drivers/input/serio/libps2.c +++ b/trunk/drivers/input/serio/libps2.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/input/touchscreen/ads7846.c b/trunk/drivers/input/touchscreen/ads7846.c index 58934a40f5ce..fd9c5d51870a 100644 --- a/trunk/drivers/input/touchscreen/ads7846.c +++ b/trunk/drivers/input/touchscreen/ads7846.c @@ -116,7 +116,6 @@ struct ads7846 { // FIXME remove "irq_disabled" unsigned irq_disabled:1; /* P: lock */ unsigned disabled:1; - unsigned is_suspended:1; int (*filter)(void *data, int data_idx, int *val); void *filter_data; @@ -204,7 +203,7 @@ static void ads7846_disable(struct ads7846 *ts); static int device_suspended(struct device *dev) { struct ads7846 *ts = dev_get_drvdata(dev); - return ts->is_suspended || ts->disabled; + return dev->power.power_state.event != PM_EVENT_ON || ts->disabled; } static int ads7846_read12_ser(struct device *dev, unsigned command) @@ -795,7 +794,7 @@ static int ads7846_suspend(struct spi_device *spi, pm_message_t message) spin_lock_irq(&ts->lock); - ts->is_suspended = 1; + spi->dev.power.power_state = message; ads7846_disable(ts); spin_unlock_irq(&ts->lock); @@ -810,7 +809,7 @@ static int ads7846_resume(struct spi_device *spi) spin_lock_irq(&ts->lock); - ts->is_suspended = 0; + spi->dev.power.power_state = PMSG_ON; ads7846_enable(ts); spin_unlock_irq(&ts->lock); @@ -872,6 +871,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) } dev_set_drvdata(&spi->dev, ts); + spi->dev.power.power_state = PMSG_ON; ts->spi = spi; ts->input = input_dev; diff --git a/trunk/drivers/input/touchscreen/mk712.c b/trunk/drivers/input/touchscreen/mk712.c index efd3aebaba5f..80a658868706 100644 --- a/trunk/drivers/input/touchscreen/mk712.c +++ b/trunk/drivers/input/touchscreen/mk712.c @@ -36,6 +36,7 @@ */ #include +#include #include #include #include diff --git a/trunk/drivers/input/touchscreen/ucb1400_ts.c b/trunk/drivers/input/touchscreen/ucb1400_ts.c index 607f9933aa1f..986a8365e37f 100644 --- a/trunk/drivers/input/touchscreen/ucb1400_ts.c +++ b/trunk/drivers/input/touchscreen/ucb1400_ts.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include diff --git a/trunk/drivers/media/video/usbvideo/konicawc.c b/trunk/drivers/media/video/usbvideo/konicawc.c index 719b17ce83f8..3e93f8058770 100644 --- a/trunk/drivers/media/video/usbvideo/konicawc.c +++ b/trunk/drivers/media/video/usbvideo/konicawc.c @@ -241,6 +241,8 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev input_dev->evbit[0] = BIT_MASK(EV_KEY); input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); + input_dev->private = cam; + error = input_register_device(cam->input); if (error) { warn("Failed to register camera's input device, err: %d\n", diff --git a/trunk/drivers/media/video/usbvideo/quickcam_messenger.c b/trunk/drivers/media/video/usbvideo/quickcam_messenger.c index a2acba0bcc47..5e7b79501370 100644 --- a/trunk/drivers/media/video/usbvideo/quickcam_messenger.c +++ b/trunk/drivers/media/video/usbvideo/quickcam_messenger.c @@ -105,6 +105,8 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev) input_dev->evbit[0] = BIT_MASK(EV_KEY); input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); + input_dev->private = cam; + error = input_register_device(cam->input); if (error) { warn("Failed to register camera's input device, err: %d\n", diff --git a/trunk/drivers/misc/Kconfig b/trunk/drivers/misc/Kconfig index 7b5220ca7d7f..78cd33861766 100644 --- a/trunk/drivers/misc/Kconfig +++ b/trunk/drivers/misc/Kconfig @@ -285,13 +285,4 @@ config INTEL_MENLOW If unsure, say N. -config ENCLOSURE_SERVICES - tristate "Enclosure Services" - default n - help - Provides support for intelligent enclosures (bays which - contain storage devices). You also need either a host - driver (SCSI/ATA) which supports enclosures - or a SCSI enclosure device (SES) to use these services. - endif # MISC_DEVICES diff --git a/trunk/drivers/misc/Makefile b/trunk/drivers/misc/Makefile index 7f13549cc87e..1f41654aae4d 100644 --- a/trunk/drivers/misc/Makefile +++ b/trunk/drivers/misc/Makefile @@ -20,4 +20,3 @@ obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o -obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o diff --git a/trunk/drivers/misc/enclosure.c b/trunk/drivers/misc/enclosure.c deleted file mode 100644 index 6fcb0e96adf4..000000000000 --- a/trunk/drivers/misc/enclosure.c +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Enclosure Services - * - * Copyright (C) 2008 James Bottomley - * -**----------------------------------------------------------------------------- -** -** This program is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License -** version 2 as published by the Free Software Foundation. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -**----------------------------------------------------------------------------- -*/ -#include -#include -#include -#include -#include -#include -#include - -static LIST_HEAD(container_list); -static DEFINE_MUTEX(container_list_lock); -static struct class enclosure_class; -static struct class enclosure_component_class; - -/** - * enclosure_find - find an enclosure given a device - * @dev: the device to find for - * - * Looks through the list of registered enclosures to see - * if it can find a match for a device. Returns NULL if no - * enclosure is found. Obtains a reference to the enclosure class - * device which must be released with class_device_put(). - */ -struct enclosure_device *enclosure_find(struct device *dev) -{ - struct enclosure_device *edev = NULL; - - mutex_lock(&container_list_lock); - list_for_each_entry(edev, &container_list, node) { - if (edev->cdev.dev == dev) { - class_device_get(&edev->cdev); - mutex_unlock(&container_list_lock); - return edev; - } - } - mutex_unlock(&container_list_lock); - - return NULL; -} -EXPORT_SYMBOL_GPL(enclosure_find); - -/** - * enclosure_for_each_device - calls a function for each enclosure - * @fn: the function to call - * @data: the data to pass to each call - * - * Loops over all the enclosures calling the function. - * - * Note, this function uses a mutex which will be held across calls to - * @fn, so it must have non atomic context, and @fn may (although it - * should not) sleep or otherwise cause the mutex to be held for - * indefinite periods - */ -int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *), - void *data) -{ - int error = 0; - struct enclosure_device *edev; - - mutex_lock(&container_list_lock); - list_for_each_entry(edev, &container_list, node) { - error = fn(edev, data); - if (error) - break; - } - mutex_unlock(&container_list_lock); - - return error; -} -EXPORT_SYMBOL_GPL(enclosure_for_each_device); - -/** - * enclosure_register - register device as an enclosure - * - * @dev: device containing the enclosure - * @components: number of components in the enclosure - * - * This sets up the device for being an enclosure. Note that @dev does - * not have to be a dedicated enclosure device. It may be some other type - * of device that additionally responds to enclosure services - */ -struct enclosure_device * -enclosure_register(struct device *dev, const char *name, int components, - struct enclosure_component_callbacks *cb) -{ - struct enclosure_device *edev = - kzalloc(sizeof(struct enclosure_device) + - sizeof(struct enclosure_component)*components, - GFP_KERNEL); - int err, i; - - BUG_ON(!cb); - - if (!edev) - return ERR_PTR(-ENOMEM); - - edev->components = components; - - edev->cdev.class = &enclosure_class; - edev->cdev.dev = get_device(dev); - edev->cb = cb; - snprintf(edev->cdev.class_id, BUS_ID_SIZE, "%s", name); - err = class_device_register(&edev->cdev); - if (err) - goto err; - - for (i = 0; i < components; i++) - edev->component[i].number = -1; - - mutex_lock(&container_list_lock); - list_add_tail(&edev->node, &container_list); - mutex_unlock(&container_list_lock); - - return edev; - - err: - put_device(edev->cdev.dev); - kfree(edev); - return ERR_PTR(err); -} -EXPORT_SYMBOL_GPL(enclosure_register); - -static struct enclosure_component_callbacks enclosure_null_callbacks; - -/** - * enclosure_unregister - remove an enclosure - * - * @edev: the registered enclosure to remove; - */ -void enclosure_unregister(struct enclosure_device *edev) -{ - int i; - - mutex_lock(&container_list_lock); - list_del(&edev->node); - mutex_unlock(&container_list_lock); - - for (i = 0; i < edev->components; i++) - if (edev->component[i].number != -1) - class_device_unregister(&edev->component[i].cdev); - - /* prevent any callbacks into service user */ - edev->cb = &enclosure_null_callbacks; - class_device_unregister(&edev->cdev); -} -EXPORT_SYMBOL_GPL(enclosure_unregister); - -static void enclosure_release(struct class_device *cdev) -{ - struct enclosure_device *edev = to_enclosure_device(cdev); - - put_device(cdev->dev); - kfree(edev); -} - -static void enclosure_component_release(struct class_device *cdev) -{ - if (cdev->dev) - put_device(cdev->dev); - class_device_put(cdev->parent); -} - -/** - * enclosure_component_register - add a particular component to an enclosure - * @edev: the enclosure to add the component - * @num: the device number - * @type: the type of component being added - * @name: an optional name to appear in sysfs (leave NULL if none) - * - * Registers the component. The name is optional for enclosures that - * give their components a unique name. If not, leave the field NULL - * and a name will be assigned. - * - * Returns a pointer to the enclosure component or an error. - */ -struct enclosure_component * -enclosure_component_register(struct enclosure_device *edev, - unsigned int number, - enum enclosure_component_type type, - const char *name) -{ - struct enclosure_component *ecomp; - struct class_device *cdev; - int err; - - if (number >= edev->components) - return ERR_PTR(-EINVAL); - - ecomp = &edev->component[number]; - - if (ecomp->number != -1) - return ERR_PTR(-EINVAL); - - ecomp->type = type; - ecomp->number = number; - cdev = &ecomp->cdev; - cdev->parent = class_device_get(&edev->cdev); - cdev->class = &enclosure_component_class; - if (name) - snprintf(cdev->class_id, BUS_ID_SIZE, "%s", name); - else - snprintf(cdev->class_id, BUS_ID_SIZE, "%u", number); - - err = class_device_register(cdev); - if (err) - ERR_PTR(err); - - return ecomp; -} -EXPORT_SYMBOL_GPL(enclosure_component_register); - -/** - * enclosure_add_device - add a device as being part of an enclosure - * @edev: the enclosure device being added to. - * @num: the number of the component - * @dev: the device being added - * - * Declares a real device to reside in slot (or identifier) @num of an - * enclosure. This will cause the relevant sysfs links to appear. - * This function may also be used to change a device associated with - * an enclosure without having to call enclosure_remove_device() in - * between. - * - * Returns zero on success or an error. - */ -int enclosure_add_device(struct enclosure_device *edev, int component, - struct device *dev) -{ - struct class_device *cdev; - - if (!edev || component >= edev->components) - return -EINVAL; - - cdev = &edev->component[component].cdev; - - class_device_del(cdev); - if (cdev->dev) - put_device(cdev->dev); - cdev->dev = get_device(dev); - return class_device_add(cdev); -} -EXPORT_SYMBOL_GPL(enclosure_add_device); - -/** - * enclosure_remove_device - remove a device from an enclosure - * @edev: the enclosure device - * @num: the number of the component to remove - * - * Returns zero on success or an error. - * - */ -int enclosure_remove_device(struct enclosure_device *edev, int component) -{ - struct class_device *cdev; - - if (!edev || component >= edev->components) - return -EINVAL; - - cdev = &edev->component[component].cdev; - - class_device_del(cdev); - if (cdev->dev) - put_device(cdev->dev); - cdev->dev = NULL; - return class_device_add(cdev); -} -EXPORT_SYMBOL_GPL(enclosure_remove_device); - -/* - * sysfs pieces below - */ - -static ssize_t enclosure_show_components(struct class_device *cdev, char *buf) -{ - struct enclosure_device *edev = to_enclosure_device(cdev); - - return snprintf(buf, 40, "%d\n", edev->components); -} - -static struct class_device_attribute enclosure_attrs[] = { - __ATTR(components, S_IRUGO, enclosure_show_components, NULL), - __ATTR_NULL -}; - -static struct class enclosure_class = { - .name = "enclosure", - .owner = THIS_MODULE, - .release = enclosure_release, - .class_dev_attrs = enclosure_attrs, -}; - -static const char *const enclosure_status [] = { - [ENCLOSURE_STATUS_UNSUPPORTED] = "unsupported", - [ENCLOSURE_STATUS_OK] = "OK", - [ENCLOSURE_STATUS_CRITICAL] = "critical", - [ENCLOSURE_STATUS_NON_CRITICAL] = "non-critical", - [ENCLOSURE_STATUS_UNRECOVERABLE] = "unrecoverable", - [ENCLOSURE_STATUS_NOT_INSTALLED] = "not installed", - [ENCLOSURE_STATUS_UNKNOWN] = "unknown", - [ENCLOSURE_STATUS_UNAVAILABLE] = "unavailable", -}; - -static const char *const enclosure_type [] = { - [ENCLOSURE_COMPONENT_DEVICE] = "device", - [ENCLOSURE_COMPONENT_ARRAY_DEVICE] = "array device", -}; - -static ssize_t get_component_fault(struct class_device *cdev, char *buf) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - - if (edev->cb->get_fault) - edev->cb->get_fault(edev, ecomp); - return snprintf(buf, 40, "%d\n", ecomp->fault); -} - -static ssize_t set_component_fault(struct class_device *cdev, const char *buf, - size_t count) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - int val = simple_strtoul(buf, NULL, 0); - - if (edev->cb->set_fault) - edev->cb->set_fault(edev, ecomp, val); - return count; -} - -static ssize_t get_component_status(struct class_device *cdev, char *buf) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - - if (edev->cb->get_status) - edev->cb->get_status(edev, ecomp); - return snprintf(buf, 40, "%s\n", enclosure_status[ecomp->status]); -} - -static ssize_t set_component_status(struct class_device *cdev, const char *buf, - size_t count) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - int i; - - for (i = 0; enclosure_status[i]; i++) { - if (strncmp(buf, enclosure_status[i], - strlen(enclosure_status[i])) == 0 && - (buf[strlen(enclosure_status[i])] == '\n' || - buf[strlen(enclosure_status[i])] == '\0')) - break; - } - - if (enclosure_status[i] && edev->cb->set_status) { - edev->cb->set_status(edev, ecomp, i); - return count; - } else - return -EINVAL; -} - -static ssize_t get_component_active(struct class_device *cdev, char *buf) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - - if (edev->cb->get_active) - edev->cb->get_active(edev, ecomp); - return snprintf(buf, 40, "%d\n", ecomp->active); -} - -static ssize_t set_component_active(struct class_device *cdev, const char *buf, - size_t count) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - int val = simple_strtoul(buf, NULL, 0); - - if (edev->cb->set_active) - edev->cb->set_active(edev, ecomp, val); - return count; -} - -static ssize_t get_component_locate(struct class_device *cdev, char *buf) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - - if (edev->cb->get_locate) - edev->cb->get_locate(edev, ecomp); - return snprintf(buf, 40, "%d\n", ecomp->locate); -} - -static ssize_t set_component_locate(struct class_device *cdev, const char *buf, - size_t count) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - int val = simple_strtoul(buf, NULL, 0); - - if (edev->cb->set_locate) - edev->cb->set_locate(edev, ecomp, val); - return count; -} - -static ssize_t get_component_type(struct class_device *cdev, char *buf) -{ - struct enclosure_component *ecomp = to_enclosure_component(cdev); - - return snprintf(buf, 40, "%s\n", enclosure_type[ecomp->type]); -} - - -static struct class_device_attribute enclosure_component_attrs[] = { - __ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault, - set_component_fault), - __ATTR(status, S_IRUGO | S_IWUSR, get_component_status, - set_component_status), - __ATTR(active, S_IRUGO | S_IWUSR, get_component_active, - set_component_active), - __ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate, - set_component_locate), - __ATTR(type, S_IRUGO, get_component_type, NULL), - __ATTR_NULL -}; - -static struct class enclosure_component_class = { - .name = "enclosure_component", - .owner = THIS_MODULE, - .class_dev_attrs = enclosure_component_attrs, - .release = enclosure_component_release, -}; - -static int __init enclosure_init(void) -{ - int err; - - err = class_register(&enclosure_class); - if (err) - return err; - err = class_register(&enclosure_component_class); - if (err) - goto err_out; - - return 0; - err_out: - class_unregister(&enclosure_class); - - return err; -} - -static void __exit enclosure_exit(void) -{ - class_unregister(&enclosure_component_class); - class_unregister(&enclosure_class); -} - -module_init(enclosure_init); -module_exit(enclosure_exit); - -MODULE_AUTHOR("James Bottomley"); -MODULE_DESCRIPTION("Enclosure Services"); -MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/scsi/Kconfig b/trunk/drivers/scsi/Kconfig index a5f0aaaf0dd4..14fc7f39e83e 100644 --- a/trunk/drivers/scsi/Kconfig +++ b/trunk/drivers/scsi/Kconfig @@ -179,15 +179,7 @@ config CHR_DEV_SCH say M here and read and . The module will be called ch.o. If unsure, say N. - -config SCSI_ENCLOSURE - tristate "SCSI Enclosure Support" - depends on SCSI && ENCLOSURE_SERVICES - help - Enclosures are devices sitting on or in SCSI backplanes that - manage devices. If you have a disk cage, the chances are that - it has an enclosure device. Selecting this option will just allow - certain enclosure conditions to be reported and is not required. + comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" depends on SCSI @@ -358,6 +350,17 @@ config SGIWD93_SCSI If you have a Western Digital WD93 SCSI controller on an SGI MIPS system, say Y. Otherwise, say N. +config SCSI_DECNCR + tristate "DEC NCR53C94 Scsi Driver" + depends on MACH_DECSTATION && SCSI && TC + help + Say Y here to support the NCR53C94 SCSI controller chips on IOASIC + based TURBOchannel DECstations and TURBOchannel PMAZ-A cards. + +config SCSI_DECSII + tristate "DEC SII Scsi Driver" + depends on MACH_DECSTATION && SCSI && 32BIT + config BLK_DEV_3W_XXXX_RAID tristate "3ware 5/6/7/8xxx ATA-RAID support" depends on PCI && SCSI @@ -1260,6 +1263,17 @@ config SCSI_NCR53C8XX_NO_DISCONNECT not allow targets to disconnect is not reasonable if there is more than 1 device on a SCSI bus. The normal answer therefore is N. +config SCSI_MCA_53C9X + tristate "NCR MCA 53C9x SCSI support" + depends on MCA_LEGACY && SCSI && BROKEN_ON_SMP + help + Some MicroChannel machines, notably the NCR 35xx line, use a SCSI + controller based on the NCR 53C94. This driver will allow use of + the controller on the 3550, and very possibly others. + + To compile this driver as a module, choose M here: the + module will be called mca_53c9x. + config SCSI_PAS16 tristate "PAS16 SCSI support" depends on ISA && SCSI @@ -1586,6 +1600,45 @@ config GVP11_SCSI To compile this driver as a module, choose M here: the module will be called gvp11. +config CYBERSTORM_SCSI + tristate "CyberStorm SCSI support" + depends on ZORRO && SCSI + help + If you have an Amiga with an original (MkI) Phase5 Cyberstorm + accelerator board and the optional Cyberstorm SCSI controller, + answer Y. Otherwise, say N. + +config CYBERSTORMII_SCSI + tristate "CyberStorm Mk II SCSI support" + depends on ZORRO && SCSI + help + If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board + and the optional Cyberstorm SCSI controller, say Y. Otherwise, + answer N. + +config BLZ2060_SCSI + tristate "Blizzard 2060 SCSI support" + depends on ZORRO && SCSI + help + If you have an Amiga with a Phase5 Blizzard 2060 accelerator board + and want to use the onboard SCSI controller, say Y. Otherwise, + answer N. + +config BLZ1230_SCSI + tristate "Blizzard 1230IV/1260 SCSI support" + depends on ZORRO && SCSI + help + If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard + 1260 accelerator, and the optional SCSI module, say Y. Otherwise, + say N. + +config FASTLANE_SCSI + tristate "Fastlane SCSI support" + depends on ZORRO && SCSI + help + If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use + one in the near future, say Y to this question. Otherwise, say N. + config SCSI_A4000T tristate "A4000T NCR53c710 SCSI support (EXPERIMENTAL)" depends on AMIGA && SCSI && EXPERIMENTAL @@ -1613,6 +1666,15 @@ config SCSI_ZORRO7XX accelerator card for the Amiga 1200, - the SCSI controller on the GVP Turbo 040/060 accelerator. +config OKTAGON_SCSI + tristate "BSC Oktagon SCSI support (EXPERIMENTAL)" + depends on ZORRO && SCSI && EXPERIMENTAL + help + If you have the BSC Oktagon SCSI disk controller for the Amiga, say + Y to this question. If you're in doubt about whether you have one, + see the picture at + . + config ATARI_SCSI tristate "Atari native SCSI support" depends on ATARI && SCSI @@ -1665,6 +1727,18 @@ config MAC_SCSI SCSI-HOWTO, available from . +config SCSI_MAC_ESP + tristate "Macintosh NCR53c9[46] SCSI" + depends on MAC && SCSI + help + This is the NCR 53c9x SCSI controller found on most of the 68040 + based Macintoshes. If you have one of these say Y and read the + SCSI-HOWTO, available from + . + + To compile this driver as a module, choose M here: the + module will be called mac_esp. + config MVME147_SCSI bool "WD33C93 SCSI driver for MVME147" depends on MVME147 && SCSI=y @@ -1705,7 +1779,6 @@ config SUN3_SCSI config SUN3X_ESP bool "Sun3x ESP SCSI" depends on SUN3X && SCSI=y - select SCSI_SPI_ATTRS help The ESP was an on-board SCSI controller used on Sun 3/80 machines. Say Y here to compile in support for it. diff --git a/trunk/drivers/scsi/Makefile b/trunk/drivers/scsi/Makefile index 925c26b4fff9..93e1428d03fc 100644 --- a/trunk/drivers/scsi/Makefile +++ b/trunk/drivers/scsi/Makefile @@ -44,8 +44,15 @@ obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o obj-$(CONFIG_MVME147_SCSI) += mvme147.o wd33c93.o obj-$(CONFIG_SGIWD93_SCSI) += sgiwd93.o wd33c93.o +obj-$(CONFIG_CYBERSTORM_SCSI) += NCR53C9x.o cyberstorm.o +obj-$(CONFIG_CYBERSTORMII_SCSI) += NCR53C9x.o cyberstormII.o +obj-$(CONFIG_BLZ2060_SCSI) += NCR53C9x.o blz2060.o +obj-$(CONFIG_BLZ1230_SCSI) += NCR53C9x.o blz1230.o +obj-$(CONFIG_FASTLANE_SCSI) += NCR53C9x.o fastlane.o +obj-$(CONFIG_OKTAGON_SCSI) += NCR53C9x.o oktagon_esp_mod.o obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o obj-$(CONFIG_MAC_SCSI) += mac_scsi.o +obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o obj-$(CONFIG_MVME16x_SCSI) += 53c700.o mvme16x_scsi.o obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o @@ -88,6 +95,7 @@ obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/ obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o obj-$(CONFIG_SCSI_7000FASST) += wd7000.o +obj-$(CONFIG_SCSI_MCA_53C9X) += NCR53C9x.o mca_53c9x.o obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o obj-$(CONFIG_SCSI_EATA) += eata.o obj-$(CONFIG_SCSI_DC395x) += dc395x.o @@ -104,12 +112,13 @@ obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o obj-$(CONFIG_BLK_DEV_IDESCSI) += ide-scsi.o obj-$(CONFIG_SCSI_MESH) += mesh.o obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o +obj-$(CONFIG_SCSI_DECNCR) += NCR53C9x.o dec_esp.o obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o obj-$(CONFIG_SCSI_PPA) += ppa.o obj-$(CONFIG_SCSI_IMM) += imm.o obj-$(CONFIG_JAZZ_ESP) += esp_scsi.o jazz_esp.o -obj-$(CONFIG_SUN3X_ESP) += esp_scsi.o sun3x_esp.o +obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o obj-$(CONFIG_SCSI_SNI_53C710) += 53c700.o sni_53c710.o obj-$(CONFIG_SCSI_NSP32) += nsp32.o @@ -129,7 +138,6 @@ obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o obj-$(CONFIG_CHR_DEV_SCH) += ch.o -obj-$(CONFIG_SCSI_ENCLOSURE) += ses.o # This goes last, so that "real" scsi devices probe earlier obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o diff --git a/trunk/drivers/scsi/NCR53C9x.c b/trunk/drivers/scsi/NCR53C9x.c new file mode 100644 index 000000000000..5b0efc903918 --- /dev/null +++ b/trunk/drivers/scsi/NCR53C9x.c @@ -0,0 +1,3654 @@ +/* NCR53C9x.c: Generic SCSI driver code for NCR53C9x chips. + * + * Originally esp.c : EnhancedScsiProcessor Sun SCSI driver code. + * + * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu) + * + * Most DMA dependencies put in driver specific files by + * Jesper Skov (jskov@cygnus.co.uk) + * + * Set up to use esp_read/esp_write (preprocessor macros in NCR53c9x.h) by + * Tymm Twillman (tymm@coe.missouri.edu) + */ + +/* TODO: + * + * 1) Maybe disable parity checking in config register one for SCSI1 + * targets. (Gilmore says parity error on the SBus can lock up + * old sun4c's) + * 2) Add support for DMA2 pipelining. + * 3) Add tagged queueing. + * 4) Maybe change use of "esp" to something more "NCR"'ish. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include +#include + +/* Command phase enumeration. */ +enum { + not_issued = 0x00, /* Still in the issue_SC queue. */ + + /* Various forms of selecting a target. */ +#define in_slct_mask 0x10 + in_slct_norm = 0x10, /* ESP is arbitrating, normal selection */ + in_slct_stop = 0x11, /* ESP will select, then stop with IRQ */ + in_slct_msg = 0x12, /* select, then send a message */ + in_slct_tag = 0x13, /* select and send tagged queue msg */ + in_slct_sneg = 0x14, /* select and acquire sync capabilities */ + + /* Any post selection activity. */ +#define in_phases_mask 0x20 + in_datain = 0x20, /* Data is transferring from the bus */ + in_dataout = 0x21, /* Data is transferring to the bus */ + in_data_done = 0x22, /* Last DMA data operation done (maybe) */ + in_msgin = 0x23, /* Eating message from target */ + in_msgincont = 0x24, /* Eating more msg bytes from target */ + in_msgindone = 0x25, /* Decide what to do with what we got */ + in_msgout = 0x26, /* Sending message to target */ + in_msgoutdone = 0x27, /* Done sending msg out */ + in_cmdbegin = 0x28, /* Sending cmd after abnormal selection */ + in_cmdend = 0x29, /* Done sending slow cmd */ + in_status = 0x2a, /* Was in status phase, finishing cmd */ + in_freeing = 0x2b, /* freeing the bus for cmd cmplt or disc */ + in_the_dark = 0x2c, /* Don't know what bus phase we are in */ + + /* Special states, ie. not normal bus transitions... */ +#define in_spec_mask 0x80 + in_abortone = 0x80, /* Aborting one command currently */ + in_abortall = 0x81, /* Blowing away all commands we have */ + in_resetdev = 0x82, /* SCSI target reset in progress */ + in_resetbus = 0x83, /* SCSI bus reset in progress */ + in_tgterror = 0x84, /* Target did something stupid */ +}; + +enum { + /* Zero has special meaning, see skipahead[12]. */ +/*0*/ do_never, + +/*1*/ do_phase_determine, +/*2*/ do_reset_bus, +/*3*/ do_reset_complete, +/*4*/ do_work_bus, +/*5*/ do_intr_end +}; + +/* The master ring of all esp hosts we are managing in this driver. */ +static struct NCR_ESP *espchain; +int nesps = 0, esps_in_use = 0, esps_running = 0; +EXPORT_SYMBOL(nesps); +EXPORT_SYMBOL(esps_running); + +irqreturn_t esp_intr(int irq, void *dev_id); + +/* Debugging routines */ +static struct esp_cmdstrings { + unchar cmdchar; + char *text; +} esp_cmd_strings[] = { + /* Miscellaneous */ + { ESP_CMD_NULL, "ESP_NOP", }, + { ESP_CMD_FLUSH, "FIFO_FLUSH", }, + { ESP_CMD_RC, "RSTESP", }, + { ESP_CMD_RS, "RSTSCSI", }, + /* Disconnected State Group */ + { ESP_CMD_RSEL, "RESLCTSEQ", }, + { ESP_CMD_SEL, "SLCTNATN", }, + { ESP_CMD_SELA, "SLCTATN", }, + { ESP_CMD_SELAS, "SLCTATNSTOP", }, + { ESP_CMD_ESEL, "ENSLCTRESEL", }, + { ESP_CMD_DSEL, "DISSELRESEL", }, + { ESP_CMD_SA3, "SLCTATN3", }, + { ESP_CMD_RSEL3, "RESLCTSEQ", }, + /* Target State Group */ + { ESP_CMD_SMSG, "SNDMSG", }, + { ESP_CMD_SSTAT, "SNDSTATUS", }, + { ESP_CMD_SDATA, "SNDDATA", }, + { ESP_CMD_DSEQ, "DISCSEQ", }, + { ESP_CMD_TSEQ, "TERMSEQ", }, + { ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", }, + { ESP_CMD_DCNCT, "DISC", }, + { ESP_CMD_RMSG, "RCVMSG", }, + { ESP_CMD_RCMD, "RCVCMD", }, + { ESP_CMD_RDATA, "RCVDATA", }, + { ESP_CMD_RCSEQ, "RCVCMDSEQ", }, + /* Initiator State Group */ + { ESP_CMD_TI, "TRANSINFO", }, + { ESP_CMD_ICCSEQ, "INICMDSEQCOMP", }, + { ESP_CMD_MOK, "MSGACCEPTED", }, + { ESP_CMD_TPAD, "TPAD", }, + { ESP_CMD_SATN, "SATN", }, + { ESP_CMD_RATN, "RATN", }, +}; +#define NUM_ESP_COMMANDS ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings))) + +/* Print textual representation of an ESP command */ +static inline void esp_print_cmd(unchar espcmd) +{ + unchar dma_bit = espcmd & ESP_CMD_DMA; + int i; + + espcmd &= ~dma_bit; + for(i=0; i"); +} + +/* Print the interrupt register's value */ +static inline void esp_print_ireg(unchar intreg) +{ + printk("INTREG< "); + if(intreg & ESP_INTR_S) + printk("SLCT_NATN "); + if(intreg & ESP_INTR_SATN) + printk("SLCT_ATN "); + if(intreg & ESP_INTR_RSEL) + printk("RSLCT "); + if(intreg & ESP_INTR_FDONE) + printk("FDONE "); + if(intreg & ESP_INTR_BSERV) + printk("BSERV "); + if(intreg & ESP_INTR_DC) + printk("DISCNCT "); + if(intreg & ESP_INTR_IC) + printk("ILL_CMD "); + if(intreg & ESP_INTR_SR) + printk("SCSI_BUS_RESET "); + printk(">"); +} + +/* Print the sequence step registers contents */ +static inline void esp_print_seqreg(unchar stepreg) +{ + stepreg &= ESP_STEP_VBITS; + printk("STEP<%s>", + (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" : + (stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" : + (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" : + (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" : + (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" : + "UNKNOWN")))))); +} + +static char *phase_string(int phase) +{ + switch(phase) { + case not_issued: + return "UNISSUED"; + case in_slct_norm: + return "SLCTNORM"; + case in_slct_stop: + return "SLCTSTOP"; + case in_slct_msg: + return "SLCTMSG"; + case in_slct_tag: + return "SLCTTAG"; + case in_slct_sneg: + return "SLCTSNEG"; + case in_datain: + return "DATAIN"; + case in_dataout: + return "DATAOUT"; + case in_data_done: + return "DATADONE"; + case in_msgin: + return "MSGIN"; + case in_msgincont: + return "MSGINCONT"; + case in_msgindone: + return "MSGINDONE"; + case in_msgout: + return "MSGOUT"; + case in_msgoutdone: + return "MSGOUTDONE"; + case in_cmdbegin: + return "CMDBEGIN"; + case in_cmdend: + return "CMDEND"; + case in_status: + return "STATUS"; + case in_freeing: + return "FREEING"; + case in_the_dark: + return "CLUELESS"; + case in_abortone: + return "ABORTONE"; + case in_abortall: + return "ABORTALL"; + case in_resetdev: + return "RESETDEV"; + case in_resetbus: + return "RESETBUS"; + case in_tgterror: + return "TGTERROR"; + default: + return "UNKNOWN"; + }; +} + +#ifdef DEBUG_STATE_MACHINE +static inline void esp_advance_phase(Scsi_Cmnd *s, int newphase) +{ + ESPLOG(("<%s>", phase_string(newphase))); + s->SCp.sent_command = s->SCp.phase; + s->SCp.phase = newphase; +} +#else +#define esp_advance_phase(__s, __newphase) \ + (__s)->SCp.sent_command = (__s)->SCp.phase; \ + (__s)->SCp.phase = (__newphase); +#endif + +#ifdef DEBUG_ESP_CMDS +static inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs, + unchar cmd) +{ + esp->espcmdlog[esp->espcmdent] = cmd; + esp->espcmdent = (esp->espcmdent + 1) & 31; + esp_write(eregs->esp_cmnd, cmd); +} +#else +#define esp_cmd(__esp, __eregs, __cmd) esp_write((__eregs)->esp_cmnd, (__cmd)) +#endif + +/* How we use the various Linux SCSI data structures for operation. + * + * struct scsi_cmnd: + * + * We keep track of the syncronous capabilities of a target + * in the device member, using sync_min_period and + * sync_max_offset. These are the values we directly write + * into the ESP registers while running a command. If offset + * is zero the ESP will use asynchronous transfers. + * If the borken flag is set we assume we shouldn't even bother + * trying to negotiate for synchronous transfer as this target + * is really stupid. If we notice the target is dropping the + * bus, and we have been allowing it to disconnect, we clear + * the disconnect flag. + */ + +/* Manipulation of the ESP command queues. Thanks to the aha152x driver + * and its author, Juergen E. Fischer, for the methods used here. + * Note that these are per-ESP queues, not global queues like + * the aha152x driver uses. + */ +static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC) +{ + Scsi_Cmnd *end; + + new_SC->host_scribble = (unsigned char *) NULL; + if(!*SC) + *SC = new_SC; + else { + for(end=*SC;end->host_scribble;end=(Scsi_Cmnd *)end->host_scribble) + ; + end->host_scribble = (unsigned char *) new_SC; + } +} + +static inline void prepend_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC) +{ + new_SC->host_scribble = (unsigned char *) *SC; + *SC = new_SC; +} + +static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC) +{ + Scsi_Cmnd *ptr; + + ptr = *SC; + if(ptr) + *SC = (Scsi_Cmnd *) (*SC)->host_scribble; + return ptr; +} + +static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun) +{ + Scsi_Cmnd *ptr, *prev; + + for(ptr = *SC, prev = NULL; + ptr && ((ptr->device->id != target) || (ptr->device->lun != lun)); + prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble) + ; + if(ptr) { + if(prev) + prev->host_scribble=ptr->host_scribble; + else + *SC=(Scsi_Cmnd *)ptr->host_scribble; + } + return ptr; +} + +/* Resetting various pieces of the ESP scsi driver chipset */ + +/* Reset the ESP chip, _not_ the SCSI bus. */ +static void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + int family_code, version, i; + volatile int trash; + + /* Now reset the ESP chip */ + esp_cmd(esp, eregs, ESP_CMD_RC); + esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA); + if(esp->erev == fast) + esp_write(eregs->esp_cfg2, ESP_CONFIG2_FENAB); + esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA); + + /* This is the only point at which it is reliable to read + * the ID-code for a fast ESP chip variant. + */ + esp->max_period = ((35 * esp->ccycle) / 1000); + if(esp->erev == fast) { + char *erev2string[] = { + "Emulex FAS236", + "Emulex FPESP100A", + "fast", + "QLogic FAS366", + "Emulex FAS216", + "Symbios Logic 53CF9x-2", + "unknown!" + }; + + version = esp_read(eregs->esp_uid); + family_code = (version & 0xf8) >> 3; + if(family_code == 0x02) { + if ((version & 7) == 2) + esp->erev = fas216; + else + esp->erev = fas236; + } else if(family_code == 0x0a) + esp->erev = fas366; /* Version is usually '5'. */ + else if(family_code == 0x00) { + if ((version & 7) == 2) + esp->erev = fas100a; /* NCR53C9X */ + else + esp->erev = espunknown; + } else if(family_code == 0x14) { + if ((version & 7) == 2) + esp->erev = fsc; + else + esp->erev = espunknown; + } else if(family_code == 0x00) { + if ((version & 7) == 2) + esp->erev = fas100a; /* NCR53C9X */ + else + esp->erev = espunknown; + } else + esp->erev = espunknown; + ESPLOG(("esp%d: FAST chip is %s (family=%d, version=%d)\n", + esp->esp_id, erev2string[esp->erev - fas236], + family_code, (version & 7))); + + esp->min_period = ((4 * esp->ccycle) / 1000); + } else { + esp->min_period = ((5 * esp->ccycle) / 1000); + } + + /* Reload the configuration registers */ + esp_write(eregs->esp_cfact, esp->cfact); + esp->prev_stp = 0; + esp_write(eregs->esp_stp, 0); + esp->prev_soff = 0; + esp_write(eregs->esp_soff, 0); + esp_write(eregs->esp_timeo, esp->neg_defp); + esp->max_period = (esp->max_period + 3)>>2; + esp->min_period = (esp->min_period + 3)>>2; + + esp_write(eregs->esp_cfg1, esp->config1); + switch(esp->erev) { + case esp100: + /* nothing to do */ + break; + case esp100a: + esp_write(eregs->esp_cfg2, esp->config2); + break; + case esp236: + /* Slow 236 */ + esp_write(eregs->esp_cfg2, esp->config2); + esp->prev_cfg3 = esp->config3[0]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + break; + case fas366: + panic("esp: FAS366 support not present, please notify " + "jongk@cs.utwente.nl"); + break; + case fas216: + case fas236: + case fsc: + /* Fast ESP variants */ + esp_write(eregs->esp_cfg2, esp->config2); + for(i=0; i<8; i++) + esp->config3[i] |= ESP_CONFIG3_FCLK; + esp->prev_cfg3 = esp->config3[0]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + if(esp->diff) + esp->radelay = 0; + else + esp->radelay = 16; + /* Different timeout constant for these chips */ + esp->neg_defp = + FSC_NEG_DEFP(esp->cfreq, + (esp->cfact == ESP_CCF_F0 ? + ESP_CCF_F7 + 1 : esp->cfact)); + esp_write(eregs->esp_timeo, esp->neg_defp); + /* Enable Active Negotiation if possible */ + if((esp->erev == fsc) && !esp->diff) + esp_write(eregs->esp_cfg4, ESP_CONFIG4_EAN); + break; + case fas100a: + /* Fast 100a */ + esp_write(eregs->esp_cfg2, esp->config2); + for(i=0; i<8; i++) + esp->config3[i] |= ESP_CONFIG3_FCLOCK; + esp->prev_cfg3 = esp->config3[0]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + esp->radelay = 32; + break; + default: + panic("esp: what could it be... I wonder..."); + break; + }; + + /* Eat any bitrot in the chip */ + trash = esp_read(eregs->esp_intrpt); + udelay(100); +} + +/* This places the ESP into a known state at boot time. */ +void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + volatile unchar trash; + + /* Reset the DMA */ + if(esp->dma_reset) + esp->dma_reset(esp); + + /* Reset the ESP */ + esp_reset_esp(esp, eregs); + + /* Reset the SCSI bus, but tell ESP not to generate an irq */ + esp_write(eregs->esp_cfg1, (esp_read(eregs->esp_cfg1) | ESP_CONFIG1_SRRDISAB)); + esp_cmd(esp, eregs, ESP_CMD_RS); + udelay(400); + esp_write(eregs->esp_cfg1, esp->config1); + + /* Eat any bitrot in the chip and we are done... */ + trash = esp_read(eregs->esp_intrpt); +} +EXPORT_SYMBOL(esp_bootup_reset); + +/* Allocate structure and insert basic data such as SCSI chip frequency + * data and a pointer to the device + */ +struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev, + int hotplug) +{ + struct NCR_ESP *esp, *elink; + struct Scsi_Host *esp_host; + + if (hotplug) + esp_host = scsi_host_alloc(tpnt, sizeof(struct NCR_ESP)); + else + esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP)); + if(!esp_host) + panic("Cannot register ESP SCSI host"); + esp = (struct NCR_ESP *) esp_host->hostdata; + if(!esp) + panic("No esp in hostdata"); + esp->ehost = esp_host; + esp->edev = esp_dev; + esp->esp_id = nesps++; + + /* Set bitshift value (only used on Amiga with multiple ESPs) */ + esp->shift = 2; + + /* Put into the chain of esp chips detected */ + if(espchain) { + elink = espchain; + while(elink->next) elink = elink->next; + elink->next = esp; + } else { + espchain = esp; + } + esp->next = NULL; + + return esp; +} + +void esp_deallocate(struct NCR_ESP *esp) +{ + struct NCR_ESP *elink; + + if(espchain == esp) { + espchain = NULL; + } else { + for(elink = espchain; elink && (elink->next != esp); elink = elink->next); + if(elink) + elink->next = esp->next; + } + nesps--; +} + +/* Complete initialization of ESP structure and device + * Caller must have initialized appropriate parts of the ESP structure + * between the call to esp_allocate and this function. + */ +void esp_initialize(struct NCR_ESP *esp) +{ + struct ESP_regs *eregs = esp->eregs; + unsigned int fmhz; + unchar ccf; + int i; + + /* Check out the clock properties of the chip. */ + + /* This is getting messy but it has to be done + * correctly or else you get weird behavior all + * over the place. We are trying to basically + * figure out three pieces of information. + * + * a) Clock Conversion Factor + * + * This is a representation of the input + * crystal clock frequency going into the + * ESP on this machine. Any operation whose + * timing is longer than 400ns depends on this + * value being correct. For example, you'll + * get blips for arbitration/selection during + * high load or with multiple targets if this + * is not set correctly. + * + * b) Selection Time-Out + * + * The ESP isn't very bright and will arbitrate + * for the bus and try to select a target + * forever if you let it. This value tells + * the ESP when it has taken too long to + * negotiate and that it should interrupt + * the CPU so we can see what happened. + * The value is computed as follows (from + * NCR/Symbios chip docs). + * + * (Time Out Period) * (Input Clock) + * STO = ---------------------------------- + * (8192) * (Clock Conversion Factor) + * + * You usually want the time out period to be + * around 250ms, I think we'll set it a little + * bit higher to account for fully loaded SCSI + * bus's and slow devices that don't respond so + * quickly to selection attempts. (yeah, I know + * this is out of spec. but there is a lot of + * buggy pieces of firmware out there so bite me) + * + * c) Imperical constants for synchronous offset + * and transfer period register values + * + * This entails the smallest and largest sync + * period we could ever handle on this ESP. + */ + + fmhz = esp->cfreq; + + if(fmhz <= (5000000)) + ccf = 0; + else + ccf = (((5000000 - 1) + (fmhz))/(5000000)); + if(!ccf || ccf > 8) { + /* If we can't find anything reasonable, + * just assume 20MHZ. This is the clock + * frequency of the older sun4c's where I've + * been unable to find the clock-frequency + * PROM property. All other machines provide + * useful values it seems. + */ + ccf = ESP_CCF_F4; + fmhz = (20000000); + } + if(ccf==(ESP_CCF_F7+1)) + esp->cfact = ESP_CCF_F0; + else if(ccf == ESP_CCF_NEVER) + esp->cfact = ESP_CCF_F2; + else + esp->cfact = ccf; + esp->cfreq = fmhz; + esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz); + esp->ctick = ESP_TICK(ccf, esp->ccycle); + esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf); + esp->sync_defp = SYNC_DEFP_SLOW; + + printk("SCSI ID %d Clk %dMHz CCF=%d TOut %d ", + esp->scsi_id, (esp->cfreq / 1000000), + ccf, (int) esp->neg_defp); + + /* Fill in ehost data */ + esp->ehost->base = (unsigned long)eregs; + esp->ehost->this_id = esp->scsi_id; + esp->ehost->irq = esp->irq; + + /* SCSI id mask */ + esp->scsi_id_mask = (1 << esp->scsi_id); + + /* Probe the revision of this esp */ + esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7)); + esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY); + esp_write(eregs->esp_cfg2, esp->config2); + if((esp_read(eregs->esp_cfg2) & ~(ESP_CONFIG2_MAGIC)) != + (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) { + printk("NCR53C90(esp100)\n"); + esp->erev = esp100; + } else { + esp->config2 = 0; + esp_write(eregs->esp_cfg2, 0); + esp_write(eregs->esp_cfg3, 5); + if(esp_read(eregs->esp_cfg3) != 5) { + printk("NCR53C90A(esp100a)\n"); + esp->erev = esp100a; + } else { + int target; + + for(target=0; target<8; target++) + esp->config3[target] = 0; + esp->prev_cfg3 = 0; + esp_write(eregs->esp_cfg3, 0); + if(ccf > ESP_CCF_F5) { + printk("NCR53C9XF(espfast)\n"); + esp->erev = fast; + esp->sync_defp = SYNC_DEFP_FAST; + } else { + printk("NCR53C9x(esp236)\n"); + esp->erev = esp236; + } + } + } + + /* Initialize the command queues */ + esp->current_SC = NULL; + esp->disconnected_SC = NULL; + esp->issue_SC = NULL; + + /* Clear the state machines. */ + esp->targets_present = 0; + esp->resetting_bus = 0; + esp->snip = 0; + + init_waitqueue_head(&esp->reset_queue); + + esp->fas_premature_intr_workaround = 0; + for(i = 0; i < 32; i++) + esp->espcmdlog[i] = 0; + esp->espcmdent = 0; + for(i = 0; i < 16; i++) { + esp->cur_msgout[i] = 0; + esp->cur_msgin[i] = 0; + } + esp->prevmsgout = esp->prevmsgin = 0; + esp->msgout_len = esp->msgin_len = 0; + + /* Clear the one behind caches to hold unmatchable values. */ + esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff; + + /* Reset the thing before we try anything... */ + esp_bootup_reset(esp, eregs); + + esps_in_use++; +} + +/* 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 *esp_info(struct Scsi_Host *host) +{ + struct NCR_ESP *esp; + + esp = (struct NCR_ESP *) host->hostdata; + switch(esp->erev) { + case esp100: + return "ESP100 (NCR53C90)"; + case esp100a: + return "ESP100A (NCR53C90A)"; + case esp236: + return "ESP236 (NCR53C9x)"; + case fas216: + return "Emulex FAS216"; + case fas236: + return "Emulex FAS236"; + case fas366: + return "QLogic FAS366"; + case fas100a: + return "FPESP100A"; + case fsc: + return "Symbios Logic 53CF9x-2"; + default: + panic("Bogon ESP revision"); + }; +} +EXPORT_SYMBOL(esp_info); + +/* From Wolfgang Stanglmeier's NCR scsi driver. */ +struct info_str +{ + char *buffer; + int length; + int offset; + int pos; +}; + +static void copy_mem_info(struct info_str *info, char *data, int len) +{ + if (info->pos + len > info->length) + len = info->length - info->pos; + + if (info->pos + len < info->offset) { + info->pos += len; + return; + } + if (info->pos < info->offset) { + data += (info->offset - info->pos); + len -= (info->offset - info->pos); + } + + if (len > 0) { + memcpy(info->buffer + info->pos, data, len); + info->pos += len; + } +} + +static int copy_info(struct info_str *info, char *fmt, ...) +{ + va_list args; + char buf[81]; + int len; + + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + copy_mem_info(info, buf, len); + return len; +} + +static int esp_host_info(struct NCR_ESP *esp, char *ptr, off_t offset, int len) +{ + struct scsi_device *sdev; + struct info_str info; + int i; + + info.buffer = ptr; + info.length = len; + info.offset = offset; + info.pos = 0; + + copy_info(&info, "ESP Host Adapter:\n"); + copy_info(&info, "\tESP Model\t\t"); + switch(esp->erev) { + case esp100: + copy_info(&info, "ESP100 (NCR53C90)\n"); + break; + case esp100a: + copy_info(&info, "ESP100A (NCR53C90A)\n"); + break; + case esp236: + copy_info(&info, "ESP236 (NCR53C9x)\n"); + break; + case fas216: + copy_info(&info, "Emulex FAS216\n"); + break; + case fas236: + copy_info(&info, "Emulex FAS236\n"); + break; + case fas100a: + copy_info(&info, "FPESP100A\n"); + break; + case fast: + copy_info(&info, "Generic FAST\n"); + break; + case fas366: + copy_info(&info, "QLogic FAS366\n"); + break; + case fsc: + copy_info(&info, "Symbios Logic 53C9x-2\n"); + break; + case espunknown: + default: + copy_info(&info, "Unknown!\n"); + break; + }; + copy_info(&info, "\tLive Targets\t\t[ "); + for(i = 0; i < 15; i++) { + if(esp->targets_present & (1 << i)) + copy_info(&info, "%d ", i); + } + copy_info(&info, "]\n\n"); + + /* Now describe the state of each existing target. */ + copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\n"); + + shost_for_each_device(sdev, esp->ehost) { + struct esp_device *esp_dev = sdev->hostdata; + uint id = sdev->id; + + if (!(esp->targets_present & (1 << id))) + continue; + + copy_info(&info, "%d\t\t", id); + copy_info(&info, "%08lx\t", esp->config3[id]); + copy_info(&info, "[%02lx,%02lx]\t\t\t", + esp_dev->sync_max_offset, + esp_dev->sync_min_period); + copy_info(&info, "%s\n", esp_dev->disconnect ? "yes" : "no"); + } + + return info.pos > info.offset? info.pos - info.offset : 0; +} + +/* ESP proc filesystem code. */ +int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, + int inout) +{ + struct NCR_ESP *esp = (struct NCR_ESP *)shost->hostdata; + + if(inout) + return -EINVAL; /* not yet */ + if(start) + *start = buffer; + return esp_host_info(esp, buffer, offset, length); +} +EXPORT_SYMBOL(esp_proc_info); + +static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + if(sp->use_sg == 0) { + sp->SCp.this_residual = sp->request_bufflen; + sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; + sp->SCp.buffers_residual = 0; + if (esp->dma_mmu_get_scsi_one) + esp->dma_mmu_get_scsi_one(esp, sp); + else + sp->SCp.ptr = + (char *) virt_to_phys(sp->request_buffer); + } else { + sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; + sp->SCp.buffers_residual = sp->use_sg - 1; + sp->SCp.this_residual = sp->SCp.buffer->length; + if (esp->dma_mmu_get_scsi_sgl) + esp->dma_mmu_get_scsi_sgl(esp, sp); + else + sp->SCp.ptr = + (char *) virt_to_phys(sg_virt(sp->SCp.buffer)); + } +} + +static void esp_release_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + if(sp->use_sg == 0) { + if (esp->dma_mmu_release_scsi_one) + esp->dma_mmu_release_scsi_one(esp, sp); + } else { + if (esp->dma_mmu_release_scsi_sgl) + esp->dma_mmu_release_scsi_sgl(esp, sp); + } +} + +static void esp_restore_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + struct esp_pointers *ep = &esp->data_pointers[scmd_id(sp)]; + + sp->SCp.ptr = ep->saved_ptr; + sp->SCp.buffer = ep->saved_buffer; + sp->SCp.this_residual = ep->saved_this_residual; + sp->SCp.buffers_residual = ep->saved_buffers_residual; +} + +static void esp_save_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + struct esp_pointers *ep = &esp->data_pointers[scmd_id(sp)]; + + ep->saved_ptr = sp->SCp.ptr; + ep->saved_buffer = sp->SCp.buffer; + ep->saved_this_residual = sp->SCp.this_residual; + ep->saved_buffers_residual = sp->SCp.buffers_residual; +} + +/* Some rules: + * + * 1) Never ever panic while something is live on the bus. + * If there is to be any chance of syncing the disks this + * rule is to be obeyed. + * + * 2) Any target that causes a foul condition will no longer + * have synchronous transfers done to it, no questions + * asked. + * + * 3) Keep register accesses to a minimum. Think about some + * day when we have Xbus machines this is running on and + * the ESP chip is on the other end of the machine on a + * different board from the cpu where this is running. + */ + +/* Fire off a command. We assume the bus is free and that the only + * case where we could see an interrupt is where we have disconnected + * commands active and they are trying to reselect us. + */ +static inline void esp_check_cmd(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + switch(sp->cmd_len) { + case 6: + case 10: + case 12: + esp->esp_slowcmd = 0; + break; + + default: + esp->esp_slowcmd = 1; + esp->esp_scmdleft = sp->cmd_len; + esp->esp_scmdp = &sp->cmnd[0]; + break; + }; +} + +static inline void build_sync_nego_msg(struct NCR_ESP *esp, int period, int offset) +{ + esp->cur_msgout[0] = EXTENDED_MESSAGE; + esp->cur_msgout[1] = 3; + esp->cur_msgout[2] = EXTENDED_SDTR; + esp->cur_msgout[3] = period; + esp->cur_msgout[4] = offset; + esp->msgout_len = 5; +} + +static void esp_exec_cmd(struct NCR_ESP *esp) +{ + struct ESP_regs *eregs = esp->eregs; + struct esp_device *esp_dev; + Scsi_Cmnd *SCptr; + struct scsi_device *SDptr; + volatile unchar *cmdp = esp->esp_command; + unsigned char the_esp_command; + int lun, target; + int i; + + /* Hold off if we have disconnected commands and + * an IRQ is showing... + */ + if(esp->disconnected_SC && esp->dma_irq_p(esp)) + return; + + /* Grab first member of the issue queue. */ + SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC); + + /* Safe to panic here because current_SC is null. */ + if(!SCptr) + panic("esp: esp_exec_cmd and issue queue is NULL"); + + SDptr = SCptr->device; + esp_dev = SDptr->hostdata; + lun = SCptr->device->lun; + target = SCptr->device->id; + + esp->snip = 0; + esp->msgout_len = 0; + + /* Send it out whole, or piece by piece? The ESP + * only knows how to automatically send out 6, 10, + * and 12 byte commands. I used to think that the + * Linux SCSI code would never throw anything other + * than that to us, but then again there is the + * SCSI generic driver which can send us anything. + */ + esp_check_cmd(esp, SCptr); + + /* If arbitration/selection is successful, the ESP will leave + * ATN asserted, causing the target to go into message out + * phase. The ESP will feed the target the identify and then + * the target can only legally go to one of command, + * datain/out, status, or message in phase, or stay in message + * out phase (should we be trying to send a sync negotiation + * message after the identify). It is not allowed to drop + * BSY, but some buggy targets do and we check for this + * condition in the selection complete code. Most of the time + * we'll make the command bytes available to the ESP and it + * will not interrupt us until it finishes command phase, we + * cannot do this for command sizes the ESP does not + * understand and in this case we'll get interrupted right + * when the target goes into command phase. + * + * It is absolutely _illegal_ in the presence of SCSI-2 devices + * to use the ESP select w/o ATN command. When SCSI-2 devices are + * present on the bus we _must_ always go straight to message out + * phase with an identify message for the target. Being that + * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2 + * selections should not confuse SCSI-1 we hope. + */ + + if(esp_dev->sync) { + /* this targets sync is known */ +#ifdef CONFIG_SCSI_MAC_ESP +do_sync_known: +#endif + if(esp_dev->disconnect) + *cmdp++ = IDENTIFY(1, lun); + else + *cmdp++ = IDENTIFY(0, lun); + + if(esp->esp_slowcmd) { + the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA); + esp_advance_phase(SCptr, in_slct_stop); + } else { + the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA); + esp_advance_phase(SCptr, in_slct_norm); + } + } else if(!(esp->targets_present & (1<disconnect)) { + /* After the bootup SCSI code sends both the + * TEST_UNIT_READY and INQUIRY commands we want + * to at least attempt allowing the device to + * disconnect. + */ + ESPMISC(("esp: Selecting device for first time. target=%d " + "lun=%d\n", target, SCptr->device->lun)); + if(!SDptr->borken && !esp_dev->disconnect) + esp_dev->disconnect = 1; + + *cmdp++ = IDENTIFY(0, lun); + esp->prevmsgout = NOP; + esp_advance_phase(SCptr, in_slct_norm); + the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA); + + /* Take no chances... */ + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + } else { + int toshiba_cdrom_hwbug_wkaround = 0; + +#ifdef CONFIG_SCSI_MAC_ESP + /* Never allow synchronous transfers (disconnect OK) on + * Macintosh. Well, maybe later when we figured out how to + * do DMA on the machines that support it ... + */ + esp_dev->disconnect = 1; + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + esp_dev->sync = 1; + esp->snip = 0; + goto do_sync_known; +#endif + /* We've talked to this guy before, + * but never negotiated. Let's try + * sync negotiation. + */ + if(!SDptr->borken) { + if((SDptr->type == TYPE_ROM) && + (!strncmp(SDptr->vendor, "TOSHIBA", 7))) { + /* Nice try sucker... */ + ESPMISC(("esp%d: Disabling sync for buggy " + "Toshiba CDROM.\n", esp->esp_id)); + toshiba_cdrom_hwbug_wkaround = 1; + build_sync_nego_msg(esp, 0, 0); + } else { + build_sync_nego_msg(esp, esp->sync_defp, 15); + } + } else { + build_sync_nego_msg(esp, 0, 0); + } + esp_dev->sync = 1; + esp->snip = 1; + + /* A fix for broken SCSI1 targets, when they disconnect + * they lock up the bus and confuse ESP. So disallow + * disconnects for SCSI1 targets for now until we + * find a better fix. + * + * Addendum: This is funny, I figured out what was going + * on. The blotzed SCSI1 target would disconnect, + * one of the other SCSI2 targets or both would be + * disconnected as well. The SCSI1 target would + * stay disconnected long enough that we start + * up a command on one of the SCSI2 targets. As + * the ESP is arbitrating for the bus the SCSI1 + * target begins to arbitrate as well to reselect + * the ESP. The SCSI1 target refuses to drop it's + * ID bit on the data bus even though the ESP is + * at ID 7 and is the obvious winner for any + * arbitration. The ESP is a poor sport and refuses + * to lose arbitration, it will continue indefinitely + * trying to arbitrate for the bus and can only be + * stopped via a chip reset or SCSI bus reset. + * Therefore _no_ disconnects for SCSI1 targets + * thank you very much. ;-) + */ + if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) || + toshiba_cdrom_hwbug_wkaround || SDptr->borken) { + ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d " + "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun)); + esp_dev->disconnect = 0; + *cmdp++ = IDENTIFY(0, lun); + } else { + *cmdp++ = IDENTIFY(1, lun); + } + + /* ESP fifo is only so big... + * Make this look like a slow command. + */ + esp->esp_slowcmd = 1; + esp->esp_scmdleft = SCptr->cmd_len; + esp->esp_scmdp = &SCptr->cmnd[0]; + + the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA); + esp_advance_phase(SCptr, in_slct_msg); + } + + if(!esp->esp_slowcmd) + for(i = 0; i < SCptr->cmd_len; i++) + *cmdp++ = SCptr->cmnd[i]; + + esp_write(eregs->esp_busid, (target & 7)); + if (esp->prev_soff != esp_dev->sync_max_offset || + esp->prev_stp != esp_dev->sync_min_period || + (esp->erev > esp100a && + esp->prev_cfg3 != esp->config3[target])) { + esp->prev_soff = esp_dev->sync_max_offset; + esp_write(eregs->esp_soff, esp->prev_soff); + esp->prev_stp = esp_dev->sync_min_period; + esp_write(eregs->esp_stp, esp->prev_stp); + if(esp->erev > esp100a) { + esp->prev_cfg3 = esp->config3[target]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + } + } + i = (cmdp - esp->esp_command); + + /* Set up the DMA and ESP counters */ + if(esp->do_pio_cmds){ + int j = 0; + + /* + * XXX MSch: + * + * It seems this is required, at least to clean up + * after failed commands when using PIO mode ... + */ + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + + for(;jesp_fdata, esp->esp_command[j]); + the_esp_command &= ~ESP_CMD_DMA; + + /* Tell ESP to "go". */ + esp_cmd(esp, eregs, the_esp_command); + } else { + /* Set up the ESP counters */ + esp_write(eregs->esp_tclow, i); + esp_write(eregs->esp_tcmed, 0); + esp->dma_init_write(esp, esp->esp_command_dvma, i); + + /* Tell ESP to "go". */ + esp_cmd(esp, eregs, the_esp_command); + } +} + +/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */ +int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + struct NCR_ESP *esp; + + /* Set up func ptr and initial driver cmd-phase. */ + SCpnt->scsi_done = done; + SCpnt->SCp.phase = not_issued; + + esp = (struct NCR_ESP *) SCpnt->device->host->hostdata; + + if(esp->dma_led_on) + esp->dma_led_on(esp); + + /* We use the scratch area. */ + ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->lun)); + ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->lun)); + + esp_get_dmabufs(esp, SCpnt); + esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */ + + SCpnt->SCp.Status = CHECK_CONDITION; + SCpnt->SCp.Message = 0xff; + SCpnt->SCp.sent_command = 0; + + /* Place into our queue. */ + if(SCpnt->cmnd[0] == REQUEST_SENSE) { + ESPQUEUE(("RQSENSE\n")); + prepend_SC(&esp->issue_SC, SCpnt); + } else { + ESPQUEUE(("\n")); + append_SC(&esp->issue_SC, SCpnt); + } + + /* Run it now if we can. */ + if(!esp->current_SC && !esp->resetting_bus) + esp_exec_cmd(esp); + + return 0; +} + +/* Dump driver state. */ +static void esp_dump_cmd(Scsi_Cmnd *SCptr) +{ + ESPLOG(("[tgt<%02x> lun<%02x> " + "pphase<%s> cphase<%s>]", + SCptr->device->id, SCptr->device->lun, + phase_string(SCptr->SCp.sent_command), + phase_string(SCptr->SCp.phase))); +} + +static void esp_dump_state(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; +#ifdef DEBUG_ESP_CMDS + int i; +#endif + + ESPLOG(("esp%d: dumping state\n", esp->esp_id)); + + /* Print DMA status */ + esp->dma_dump_state(esp); + + ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n", + esp->esp_id, esp->sreg, esp->seqreg, esp->ireg)); + ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n", + esp->esp_id, esp_read(eregs->esp_status), esp_read(eregs->esp_sstep), + esp_read(eregs->esp_intrpt))); +#ifdef DEBUG_ESP_CMDS + printk("esp%d: last ESP cmds [", esp->esp_id); + i = (esp->espcmdent - 1) & 31; + printk("<"); + esp_print_cmd(esp->espcmdlog[i]); + printk(">"); + i = (i - 1) & 31; + printk("<"); + esp_print_cmd(esp->espcmdlog[i]); + printk(">"); + i = (i - 1) & 31; + printk("<"); + esp_print_cmd(esp->espcmdlog[i]); + printk(">"); + i = (i - 1) & 31; + printk("<"); + esp_print_cmd(esp->espcmdlog[i]); + printk(">"); + printk("]\n"); +#endif /* (DEBUG_ESP_CMDS) */ + + if(SCptr) { + ESPLOG(("esp%d: current command ", esp->esp_id)); + esp_dump_cmd(SCptr); + } + ESPLOG(("\n")); + SCptr = esp->disconnected_SC; + ESPLOG(("esp%d: disconnected ", esp->esp_id)); + while(SCptr) { + esp_dump_cmd(SCptr); + SCptr = (Scsi_Cmnd *) SCptr->host_scribble; + } + ESPLOG(("\n")); +} + +/* Abort a command. The host_lock is acquired by caller. */ +int esp_abort(Scsi_Cmnd *SCptr) +{ + struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->device->host->hostdata; + struct ESP_regs *eregs = esp->eregs; + int don; + + ESPLOG(("esp%d: Aborting command\n", esp->esp_id)); + esp_dump_state(esp, eregs); + + /* Wheee, if this is the current command on the bus, the + * best we can do is assert ATN and wait for msgout phase. + * This should even fix a hung SCSI bus when we lose state + * in the driver and timeout because the eventual phase change + * will cause the ESP to (eventually) give an interrupt. + */ + if(esp->current_SC == SCptr) { + esp->cur_msgout[0] = ABORT; + esp->msgout_len = 1; + esp->msgout_ctr = 0; + esp_cmd(esp, eregs, ESP_CMD_SATN); + return SUCCESS; + } + + /* If it is still in the issue queue then we can safely + * call the completion routine and report abort success. + */ + don = esp->dma_ports_p(esp); + if(don) { + esp->dma_ints_off(esp); + synchronize_irq(esp->irq); + } + if(esp->issue_SC) { + Scsi_Cmnd **prev, *this; + for(prev = (&esp->issue_SC), this = esp->issue_SC; + this; + prev = (Scsi_Cmnd **) &(this->host_scribble), + this = (Scsi_Cmnd *) this->host_scribble) { + if(this == SCptr) { + *prev = (Scsi_Cmnd *) this->host_scribble; + this->host_scribble = NULL; + esp_release_dmabufs(esp, this); + this->result = DID_ABORT << 16; + this->scsi_done(this); + if(don) + esp->dma_ints_on(esp); + return SUCCESS; + } + } + } + + /* Yuck, the command to abort is disconnected, it is not + * worth trying to abort it now if something else is live + * on the bus at this time. So, we let the SCSI code wait + * a little bit and try again later. + */ + if(esp->current_SC) { + if(don) + esp->dma_ints_on(esp); + return FAILED; + } + + /* It's disconnected, we have to reconnect to re-establish + * the nexus and tell the device to abort. However, we really + * cannot 'reconnect' per se. Don't try to be fancy, just + * indicate failure, which causes our caller to reset the whole + * bus. + */ + + if(don) + esp->dma_ints_on(esp); + return FAILED; +} + +/* We've sent ESP_CMD_RS to the ESP, the interrupt had just + * arrived indicating the end of the SCSI bus reset. Our job + * is to clean out the command queues and begin re-execution + * of SCSI commands once more. + */ +static int esp_finish_reset(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + Scsi_Cmnd *sp = esp->current_SC; + + /* Clean up currently executing command, if any. */ + if (sp != NULL) { + esp_release_dmabufs(esp, sp); + sp->result = (DID_RESET << 16); + sp->scsi_done(sp); + esp->current_SC = NULL; + } + + /* Clean up disconnected queue, they have been invalidated + * by the bus reset. + */ + if (esp->disconnected_SC) { + while((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) { + esp_release_dmabufs(esp, sp); + sp->result = (DID_RESET << 16); + sp->scsi_done(sp); + } + } + + /* SCSI bus reset is complete. */ + esp->resetting_bus = 0; + wake_up(&esp->reset_queue); + + /* Ok, now it is safe to get commands going once more. */ + if(esp->issue_SC) + esp_exec_cmd(esp); + + return do_intr_end; +} + +static int esp_do_resetbus(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id)); + esp->resetting_bus = 1; + esp_cmd(esp, eregs, ESP_CMD_RS); + + return do_intr_end; +} + +/* Reset ESP chip, reset hanging bus, then kill active and + * disconnected commands for targets without soft reset. + * + * The host_lock is acquired by caller. + */ +int esp_reset(Scsi_Cmnd *SCptr) +{ + struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->device->host->hostdata; + + spin_lock_irq(esp->ehost->host_lock); + (void) esp_do_resetbus(esp, esp->eregs); + spin_unlock_irq(esp->ehost->host_lock); + + wait_event(esp->reset_queue, (esp->resetting_bus == 0)); + + return SUCCESS; +} + +/* Internal ESP done function. */ +static void esp_done(struct NCR_ESP *esp, int error) +{ + Scsi_Cmnd *done_SC; + + if(esp->current_SC) { + done_SC = esp->current_SC; + esp->current_SC = NULL; + esp_release_dmabufs(esp, done_SC); + done_SC->result = error; + done_SC->scsi_done(done_SC); + + /* Bus is free, issue any commands in the queue. */ + if(esp->issue_SC && !esp->current_SC) + esp_exec_cmd(esp); + } else { + /* Panic is safe as current_SC is null so we may still + * be able to accept more commands to sync disk buffers. + */ + ESPLOG(("panicing\n")); + panic("esp: done() called with NULL esp->current_SC"); + } +} + +/* Wheee, ESP interrupt engine. */ + +/* Forward declarations. */ +static int esp_do_phase_determine(struct NCR_ESP *esp, + struct ESP_regs *eregs); +static int esp_do_data_finale(struct NCR_ESP *esp, struct ESP_regs *eregs); +static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs); +static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs); +static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs); +static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs); +static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs); +static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs); + +#define sreg_datainp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DIP) +#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP) + +/* We try to avoid some interrupts by jumping ahead and see if the ESP + * has gotten far enough yet. Hence the following. + */ +static inline int skipahead1(struct NCR_ESP *esp, struct ESP_regs *eregs, + Scsi_Cmnd *scp, int prev_phase, int new_phase) +{ + if(scp->SCp.sent_command != prev_phase) + return 0; + + if(esp->dma_irq_p(esp)) { + /* Yes, we are able to save an interrupt. */ + esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR)); + esp->ireg = esp_read(eregs->esp_intrpt); + if(!(esp->ireg & ESP_INTR_SR)) + return 0; + else + return do_reset_complete; + } + /* Ho hum, target is taking forever... */ + scp->SCp.sent_command = new_phase; /* so we don't recurse... */ + return do_intr_end; +} + +static inline int skipahead2(struct NCR_ESP *esp, + struct ESP_regs *eregs, + Scsi_Cmnd *scp, int prev_phase1, int prev_phase2, + int new_phase) +{ + if(scp->SCp.sent_command != prev_phase1 && + scp->SCp.sent_command != prev_phase2) + return 0; + if(esp->dma_irq_p(esp)) { + /* Yes, we are able to save an interrupt. */ + esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR)); + esp->ireg = esp_read(eregs->esp_intrpt); + if(!(esp->ireg & ESP_INTR_SR)) + return 0; + else + return do_reset_complete; + } + /* Ho hum, target is taking forever... */ + scp->SCp.sent_command = new_phase; /* so we don't recurse... */ + return do_intr_end; +} + +/* Misc. esp helper macros. */ +#define esp_setcount(__eregs, __cnt) \ + esp_write((__eregs)->esp_tclow, ((__cnt) & 0xff)); \ + esp_write((__eregs)->esp_tcmed, (((__cnt) >> 8) & 0xff)) + +#define esp_getcount(__eregs) \ + ((esp_read((__eregs)->esp_tclow)&0xff) | \ + ((esp_read((__eregs)->esp_tcmed)&0xff) << 8)) + +#define fcount(__esp, __eregs) \ + (esp_read((__eregs)->esp_fflags) & ESP_FF_FBYTES) + +#define fnzero(__esp, __eregs) \ + (esp_read((__eregs)->esp_fflags) & ESP_FF_ONOTZERO) + +/* XXX speculative nops unnecessary when continuing amidst a data phase + * XXX even on esp100!!! another case of flooding the bus with I/O reg + * XXX writes... + */ +#define esp_maybe_nop(__esp, __eregs) \ + if((__esp)->erev == esp100) \ + esp_cmd((__esp), (__eregs), ESP_CMD_NULL) + +#define sreg_to_dataphase(__sreg) \ + ((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain) + +/* The ESP100 when in synchronous data phase, can mistake a long final + * REQ pulse from the target as an extra byte, it places whatever is on + * the data lines into the fifo. For now, we will assume when this + * happens that the target is a bit quirky and we don't want to + * be talking synchronously to it anyways. Regardless, we need to + * tell the ESP to eat the extraneous byte so that we can proceed + * to the next phase. + */ +static inline int esp100_sync_hwbug(struct NCR_ESP *esp, struct ESP_regs *eregs, + Scsi_Cmnd *sp, int fifocnt) +{ + /* Do not touch this piece of code. */ + if((!(esp->erev == esp100)) || + (!(sreg_datainp((esp->sreg = esp_read(eregs->esp_status))) && !fifocnt) && + !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) { + if(sp->SCp.phase == in_dataout) + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + return 0; + } else { + /* Async mode for this guy. */ + build_sync_nego_msg(esp, 0, 0); + + /* Ack the bogus byte, but set ATN first. */ + esp_cmd(esp, eregs, ESP_CMD_SATN); + esp_cmd(esp, eregs, ESP_CMD_MOK); + return 1; + } +} + +/* This closes the window during a selection with a reselect pending, because + * we use DMA for the selection process the FIFO should hold the correct + * contents if we get reselected during this process. So we just need to + * ack the possible illegal cmd interrupt pending on the esp100. + */ +static inline int esp100_reconnect_hwbug(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + volatile unchar junk; + + if(esp->erev != esp100) + return 0; + junk = esp_read(eregs->esp_intrpt); + + if(junk & ESP_INTR_SR) + return 1; + return 0; +} + +/* This verifies the BUSID bits during a reselection so that we know which + * target is talking to us. + */ +static inline int reconnect_target(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + int it, me = esp->scsi_id_mask, targ = 0; + + if(2 != fcount(esp, eregs)) + return -1; + it = esp_read(eregs->esp_fdata); + if(!(it & me)) + return -1; + it &= ~me; + if(it & (it - 1)) + return -1; + while(!(it & 1)) + targ++, it >>= 1; + return targ; +} + +/* This verifies the identify from the target so that we know which lun is + * being reconnected. + */ +static inline int reconnect_lun(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + int lun; + + if((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) + return -1; + lun = esp_read(eregs->esp_fdata); + + /* Yes, you read this correctly. We report lun of zero + * if we see parity error. ESP reports parity error for + * the lun byte, and this is the only way to hope to recover + * because the target is connected. + */ + if(esp->sreg & ESP_STAT_PERR) + return 0; + + /* Check for illegal bits being set in the lun. */ + if((lun & 0x40) || !(lun & 0x80)) + return -1; + + return lun & 7; +} + +/* This puts the driver in a state where it can revitalize a command that + * is being continued due to reselection. + */ +static inline void esp_connect(struct NCR_ESP *esp, struct ESP_regs *eregs, + Scsi_Cmnd *sp) +{ + struct scsi_device *dp = sp->device; + struct esp_device *esp_dev = dp->hostdata; + + if(esp->prev_soff != esp_dev->sync_max_offset || + esp->prev_stp != esp_dev->sync_min_period || + (esp->erev > esp100a && + esp->prev_cfg3 != esp->config3[scmd_id(sp)])) { + esp->prev_soff = esp_dev->sync_max_offset; + esp_write(eregs->esp_soff, esp->prev_soff); + esp->prev_stp = esp_dev->sync_min_period; + esp_write(eregs->esp_stp, esp->prev_stp); + if(esp->erev > esp100a) { + esp->prev_cfg3 = esp->config3[scmd_id(sp)]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + } + } + esp->current_SC = sp; +} + +/* This will place the current working command back into the issue queue + * if we are to receive a reselection amidst a selection attempt. + */ +static inline void esp_reconnect(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + if(!esp->disconnected_SC) + ESPLOG(("esp%d: Weird, being reselected but disconnected " + "command queue is empty.\n", esp->esp_id)); + esp->snip = 0; + esp->current_SC = NULL; + sp->SCp.phase = not_issued; + append_SC(&esp->issue_SC, sp); +} + +/* Begin message in phase. */ +static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + esp_maybe_nop(esp, eregs); + esp_cmd(esp, eregs, ESP_CMD_TI); + esp->msgin_len = 1; + esp->msgin_ctr = 0; + esp_advance_phase(esp->current_SC, in_msgindone); + return do_work_bus; +} + +static inline void advance_sg(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + ++sp->SCp.buffer; + --sp->SCp.buffers_residual; + sp->SCp.this_residual = sp->SCp.buffer->length; + if (esp->dma_advance_sg) + esp->dma_advance_sg (sp); + else + sp->SCp.ptr = (char *) virt_to_phys(sg_virt(sp->SCp.buffer)); + +} + +/* Please note that the way I've coded these routines is that I _always_ + * check for a disconnect during any and all information transfer + * phases. The SCSI standard states that the target _can_ cause a BUS + * FREE condition by dropping all MSG/CD/IO/BSY signals. Also note + * that during information transfer phases the target controls every + * change in phase, the only thing the initiator can do is "ask" for + * a message out phase by driving ATN true. The target can, and sometimes + * will, completely ignore this request so we cannot assume anything when + * we try to force a message out phase to abort/reset a target. Most of + * the time the target will eventually be nice and go to message out, so + * we may have to hold on to our state about what we want to tell the target + * for some period of time. + */ + +/* I think I have things working here correctly. Even partial transfers + * within a buffer or sub-buffer should not upset us at all no matter + * how bad the target and/or ESP fucks things up. + */ +static int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + int thisphase, hmuch; + + ESPDATA(("esp_do_data: ")); + esp_maybe_nop(esp, eregs); + thisphase = sreg_to_dataphase(esp->sreg); + esp_advance_phase(SCptr, thisphase); + ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT")); + hmuch = esp->dma_can_transfer(esp, SCptr); + + /* + * XXX MSch: cater for PIO transfer here; PIO used if hmuch == 0 + */ + if (hmuch) { /* DMA */ + /* + * DMA + */ + ESPDATA(("hmuch<%d> ", hmuch)); + esp->current_transfer_size = hmuch; + esp_setcount(eregs, (esp->fas_premature_intr_workaround ? + (hmuch + 0x40) : hmuch)); + esp->dma_setup(esp, (__u32)((unsigned long)SCptr->SCp.ptr), + hmuch, (thisphase == in_datain)); + ESPDATA(("DMA|TI --> do_intr_end\n")); + esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); + return do_intr_end; + /* + * end DMA + */ + } else { + /* + * PIO + */ + int oldphase, i = 0; /* or where we left off last time ?? esp->current_data ?? */ + int fifocnt = 0; + unsigned char *p = phys_to_virt((unsigned long)SCptr->SCp.ptr); + + oldphase = esp_read(eregs->esp_status) & ESP_STAT_PMASK; + + /* + * polled transfer; ugly, can we make this happen in a DRQ + * interrupt handler ?? + * requires keeping track of state information in host or + * command struct! + * Problem: I've never seen a DRQ happen on Mac, not even + * with ESP_CMD_DMA ... + */ + + /* figure out how much needs to be transferred */ + hmuch = SCptr->SCp.this_residual; + ESPDATA(("hmuch<%d> pio ", hmuch)); + esp->current_transfer_size = hmuch; + + /* tell the ESP ... */ + esp_setcount(eregs, hmuch); + + /* loop */ + while (hmuch) { + int j, fifo_stuck = 0, newphase; + unsigned long timeout; +#if 0 + unsigned long flags; +#endif +#if 0 + if ( i % 10 ) + ESPDATA(("\r")); + else + ESPDATA(( /*"\n"*/ "\r")); +#endif +#if 0 + local_irq_save(flags); +#endif + if(thisphase == in_datain) { + /* 'go' ... */ + esp_cmd(esp, eregs, ESP_CMD_TI); + + /* wait for data */ + timeout = 1000000; + while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout) + udelay(2); + if (timeout == 0) + printk("DRQ datain timeout! \n"); + + newphase = esp->sreg & ESP_STAT_PMASK; + + /* see how much we got ... */ + fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES); + + if (!fifocnt) + fifo_stuck++; + else + fifo_stuck = 0; + + ESPDATA(("\rgot %d st %x ph %x", fifocnt, esp->sreg, newphase)); + + /* read fifo */ + for(j=0;jesp_fdata); + + ESPDATA(("(%d) ", i)); + + /* how many to go ?? */ + hmuch -= fifocnt; + + /* break if status phase !! */ + if(newphase == ESP_STATP) { + /* clear int. */ + esp->ireg = esp_read(eregs->esp_intrpt); + break; + } + } else { +#define MAX_FIFO 8 + /* how much will fit ? */ + int this_count = MAX_FIFO - fifocnt; + if (this_count > hmuch) + this_count = hmuch; + + /* fill fifo */ + for(j=0;jesp_fdata, p[i++]); + + /* how many left if this goes out ?? */ + hmuch -= this_count; + + /* 'go' ... */ + esp_cmd(esp, eregs, ESP_CMD_TI); + + /* wait for 'got it' */ + timeout = 1000000; + while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout) + udelay(2); + if (timeout == 0) + printk("DRQ dataout timeout! \n"); + + newphase = esp->sreg & ESP_STAT_PMASK; + + /* need to check how much was sent ?? */ + fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES); + + ESPDATA(("\rsent %d st %x ph %x", this_count - fifocnt, esp->sreg, newphase)); + + ESPDATA(("(%d) ", i)); + + /* break if status phase !! */ + if(newphase == ESP_STATP) { + /* clear int. */ + esp->ireg = esp_read(eregs->esp_intrpt); + break; + } + + } + + /* clear int. */ + esp->ireg = esp_read(eregs->esp_intrpt); + + ESPDATA(("ir %x ... ", esp->ireg)); + + if (hmuch == 0) + ESPDATA(("done! \n")); + +#if 0 + local_irq_restore(flags); +#endif + + /* check new bus phase */ + if (newphase != oldphase && i < esp->current_transfer_size) { + /* something happened; disconnect ?? */ + ESPDATA(("phase change, dropped out with %d done ... ", i)); + break; + } + + /* check int. status */ + if (esp->ireg & ESP_INTR_DC) { + /* disconnect */ + ESPDATA(("disconnect; %d transferred ... ", i)); + break; + } else if (esp->ireg & ESP_INTR_FDONE) { + /* function done */ + ESPDATA(("function done; %d transferred ... ", i)); + break; + } + + /* XXX fixme: bail out on stall */ + if (fifo_stuck > 10) { + /* we're stuck */ + ESPDATA(("fifo stall; %d transferred ... ", i)); + break; + } + } + + ESPDATA(("\n")); + /* check successful completion ?? */ + + if (thisphase == in_dataout) + hmuch += fifocnt; /* stuck?? adjust data pointer ...*/ + + /* tell do_data_finale how much was transferred */ + esp->current_transfer_size -= hmuch; + + /* still not completely sure on this one ... */ + return /*do_intr_end*/ do_work_bus /*do_phase_determine*/ ; + + /* + * end PIO + */ + } + return do_intr_end; +} + +/* See how successful the data transfer was. */ +static int esp_do_data_finale(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + struct esp_device *esp_dev = SCptr->device->hostdata; + int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0; + + if(esp->dma_led_off) + esp->dma_led_off(esp); + + ESPDATA(("esp_do_data_finale: ")); + + if(SCptr->SCp.phase == in_datain) { + if(esp->sreg & ESP_STAT_PERR) { + /* Yuck, parity error. The ESP asserts ATN + * so that we can go to message out phase + * immediately and inform the target that + * something bad happened. + */ + ESPLOG(("esp%d: data bad parity detected.\n", + esp->esp_id)); + esp->cur_msgout[0] = INITIATOR_ERROR; + esp->msgout_len = 1; + } + if(esp->dma_drain) + esp->dma_drain(esp); + } + if(esp->dma_invalidate) + esp->dma_invalidate(esp); + + /* This could happen for the above parity error case. */ + if(!(esp->ireg == ESP_INTR_BSERV)) { + /* Please go to msgout phase, please please please... */ + ESPLOG(("esp%d: !BSERV after data, probably to msgout\n", + esp->esp_id)); + return esp_do_phase_determine(esp, eregs); + } + + /* Check for partial transfers and other horrible events. */ + fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES); + ecount = esp_getcount(eregs); + if(esp->fas_premature_intr_workaround) + ecount -= 0x40; + bytes_sent = esp->current_transfer_size; + + ESPDATA(("trans_sz=%d, ", bytes_sent)); + if(!(esp->sreg & ESP_STAT_TCNT)) + bytes_sent -= ecount; + if(SCptr->SCp.phase == in_dataout) + bytes_sent -= fifocnt; + + ESPDATA(("bytes_sent=%d (ecount=%d, fifocnt=%d), ", bytes_sent, + ecount, fifocnt)); + + /* If we were in synchronous mode, check for peculiarities. */ + if(esp_dev->sync_max_offset) + bogus_data = esp100_sync_hwbug(esp, eregs, SCptr, fifocnt); + else + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + + /* Until we are sure of what has happened, we are certainly + * in the dark. + */ + esp_advance_phase(SCptr, in_the_dark); + + /* Check for premature interrupt condition. Can happen on FAS2x6 + * chips. QLogic recommends a workaround by overprogramming the + * transfer counters, but this makes doing scatter-gather impossible. + * Until there is a way to disable scatter-gather for a single target, + * and not only for the entire host adapter as it is now, the workaround + * is way to expensive performance wise. + * Instead, it turns out that when this happens the target has disconnected + * already but it doesn't show in the interrupt register. Compensate for + * that here to try and avoid a SCSI bus reset. + */ + if(!esp->fas_premature_intr_workaround && (fifocnt == 1) && + sreg_dataoutp(esp->sreg)) { + ESPLOG(("esp%d: Premature interrupt, enabling workaround\n", + esp->esp_id)); +#if 0 + /* Disable scatter-gather operations, they are not possible + * when using this workaround. + */ + esp->ehost->sg_tablesize = 0; + esp->ehost->use_clustering = ENABLE_CLUSTERING; + esp->fas_premature_intr_workaround = 1; + bytes_sent = 0; + if(SCptr->use_sg) { + ESPLOG(("esp%d: Aborting scatter-gather operation\n", + esp->esp_id)); + esp->cur_msgout[0] = ABORT; + esp->msgout_len = 1; + esp->msgout_ctr = 0; + esp_cmd(esp, eregs, ESP_CMD_SATN); + esp_setcount(eregs, 0xffff); + esp_cmd(esp, eregs, ESP_CMD_NULL); + esp_cmd(esp, eregs, ESP_CMD_TPAD | ESP_CMD_DMA); + return do_intr_end; + } +#else + /* Just set the disconnected bit. That's what appears to + * happen anyway. The state machine will pick it up when + * we return. + */ + esp->ireg |= ESP_INTR_DC; +#endif + } + + if(bytes_sent < 0) { + /* I've seen this happen due to lost state in this + * driver. No idea why it happened, but allowing + * this value to be negative caused things to + * lock up. This allows greater chance of recovery. + * In fact every time I've seen this, it has been + * a driver bug without question. + */ + ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id)); + ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n", + esp->esp_id, + esp->current_transfer_size, fifocnt, ecount)); + ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n", + esp->esp_id, + SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual)); + ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id, + SCptr->device->id)); + SCptr->device->borken = 1; + esp_dev->sync = 0; + bytes_sent = 0; + } + + /* Update the state of our transfer. */ + SCptr->SCp.ptr += bytes_sent; + SCptr->SCp.this_residual -= bytes_sent; + if(SCptr->SCp.this_residual < 0) { + /* shit */ + ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id)); + SCptr->SCp.this_residual = 0; + } + + /* Maybe continue. */ + if(!bogus_data) { + ESPDATA(("!bogus_data, ")); + /* NO MATTER WHAT, we advance the scatterlist, + * if the target should decide to disconnect + * in between scatter chunks (which is common) + * we could die horribly! I used to have the sg + * advance occur only if we are going back into + * (or are staying in) a data phase, you can + * imagine the hell I went through trying to + * figure this out. + */ + if(!SCptr->SCp.this_residual && SCptr->SCp.buffers_residual) + advance_sg(esp, SCptr); +#ifdef DEBUG_ESP_DATA + if(sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) { + ESPDATA(("to more data\n")); + } else { + ESPDATA(("to new phase\n")); + } +#endif + return esp_do_phase_determine(esp, eregs); + } + /* Bogus data, just wait for next interrupt. */ + ESPLOG(("esp%d: bogus_data during end of data phase\n", + esp->esp_id)); + return do_intr_end; +} + +/* We received a non-good status return at the end of + * running a SCSI command. This is used to decide if + * we should clear our synchronous transfer state for + * such a device when that happens. + * + * The idea is that when spinning up a disk or rewinding + * a tape, we don't want to go into a loop re-negotiating + * synchronous capabilities over and over. + */ +static int esp_should_clear_sync(Scsi_Cmnd *sp) +{ + unchar cmd = sp->cmnd[0]; + + /* These cases are for spinning up a disk and + * waiting for that spinup to complete. + */ + if(cmd == START_STOP) + return 0; + + if(cmd == TEST_UNIT_READY) + return 0; + + /* One more special case for SCSI tape drives, + * this is what is used to probe the device for + * completion of a rewind or tape load operation. + */ + if(sp->device->type == TYPE_TAPE && cmd == MODE_SENSE) + return 0; + + return 1; +} + +/* Either a command is completing or a target is dropping off the bus + * to continue the command in the background so we can do other work. + */ +static int esp_do_freebus(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + int rval; + + rval = skipahead2(esp, eregs, SCptr, in_status, in_msgindone, in_freeing); + if(rval) + return rval; + + if(esp->ireg != ESP_INTR_DC) { + ESPLOG(("esp%d: Target will not disconnect\n", esp->esp_id)); + return do_reset_bus; /* target will not drop BSY... */ + } + esp->msgout_len = 0; + esp->prevmsgout = NOP; + if(esp->prevmsgin == COMMAND_COMPLETE) { + struct esp_device *esp_dev = SCptr->device->hostdata; + /* Normal end of nexus. */ + if(esp->disconnected_SC) + esp_cmd(esp, eregs, ESP_CMD_ESEL); + + if(SCptr->SCp.Status != GOOD && + SCptr->SCp.Status != CONDITION_GOOD && + ((1<targets_present) && + esp_dev->sync && esp_dev->sync_max_offset) { + /* SCSI standard says that the synchronous capabilities + * should be renegotiated at this point. Most likely + * we are about to request sense from this target + * in which case we want to avoid using sync + * transfers until we are sure of the current target + * state. + */ + ESPMISC(("esp: Status <%d> for target %d lun %d\n", + SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun)); + + /* But don't do this when spinning up a disk at + * boot time while we poll for completion as it + * fills up the console with messages. Also, tapes + * can report not ready many times right after + * loading up a tape. + */ + if(esp_should_clear_sync(SCptr) != 0) + esp_dev->sync = 0; + } + ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun)); + esp_done(esp, ((SCptr->SCp.Status & 0xff) | + ((SCptr->SCp.Message & 0xff)<<8) | + (DID_OK << 16))); + } else if(esp->prevmsgin == DISCONNECT) { + /* Normal disconnect. */ + esp_cmd(esp, eregs, ESP_CMD_ESEL); + ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun)); + append_SC(&esp->disconnected_SC, SCptr); + esp->current_SC = NULL; + if(esp->issue_SC) + esp_exec_cmd(esp); + } else { + /* Driver bug, we do not expect a disconnect here + * and should not have advanced the state engine + * to in_freeing. + */ + ESPLOG(("esp%d: last msg not disc and not cmd cmplt.\n", + esp->esp_id)); + return do_reset_bus; + } + return do_intr_end; +} + +/* When a reselect occurs, and we cannot find the command to + * reconnect to in our queues, we do this. + */ +static int esp_bad_reconnect(struct NCR_ESP *esp) +{ + Scsi_Cmnd *sp; + + ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n", + esp->esp_id)); + ESPLOG(("QUEUE DUMP\n")); + sp = esp->issue_SC; + ESPLOG(("esp%d: issue_SC[", esp->esp_id)); + while(sp) { + ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); + sp = (Scsi_Cmnd *) sp->host_scribble; + } + ESPLOG(("]\n")); + sp = esp->current_SC; + ESPLOG(("esp%d: current_SC[", esp->esp_id)); + while(sp) { + ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); + sp = (Scsi_Cmnd *) sp->host_scribble; + } + ESPLOG(("]\n")); + sp = esp->disconnected_SC; + ESPLOG(("esp%d: disconnected_SC[", esp->esp_id)); + while(sp) { + ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); + sp = (Scsi_Cmnd *) sp->host_scribble; + } + ESPLOG(("]\n")); + return do_reset_bus; +} + +/* Do the needy when a target tries to reconnect to us. */ +static int esp_do_reconnect(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + int lun, target; + Scsi_Cmnd *SCptr; + + /* Check for all bogus conditions first. */ + target = reconnect_target(esp, eregs); + if(target < 0) { + ESPDISC(("bad bus bits\n")); + return do_reset_bus; + } + lun = reconnect_lun(esp, eregs); + if(lun < 0) { + ESPDISC(("target=%2x, bad identify msg\n", target)); + return do_reset_bus; + } + + /* Things look ok... */ + ESPDISC(("R<%02x,%02x>", target, lun)); + + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + if(esp100_reconnect_hwbug(esp, eregs)) + return do_reset_bus; + esp_cmd(esp, eregs, ESP_CMD_NULL); + + SCptr = remove_SC(&esp->disconnected_SC, (unchar) target, (unchar) lun); + if(!SCptr) + return esp_bad_reconnect(esp); + + esp_connect(esp, eregs, SCptr); + esp_cmd(esp, eregs, ESP_CMD_MOK); + + /* Reconnect implies a restore pointers operation. */ + esp_restore_pointers(esp, SCptr); + + esp->snip = 0; + esp_advance_phase(SCptr, in_the_dark); + return do_intr_end; +} + +/* End of NEXUS (hopefully), pick up status + message byte then leave if + * all goes well. + */ +static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + int intr, rval; + + rval = skipahead1(esp, eregs, SCptr, in_the_dark, in_status); + if(rval) + return rval; + + intr = esp->ireg; + ESPSTAT(("esp_do_status: ")); + if(intr != ESP_INTR_DC) { + int message_out = 0; /* for parity problems */ + + /* Ack the message. */ + ESPSTAT(("ack msg, ")); + esp_cmd(esp, eregs, ESP_CMD_MOK); + + if(esp->dma_poll) + esp->dma_poll(esp, (unsigned char *) esp->esp_command); + + ESPSTAT(("got something, ")); + /* ESP chimes in with one of + * + * 1) function done interrupt: + * both status and message in bytes + * are available + * + * 2) bus service interrupt: + * only status byte was acquired + * + * 3) Anything else: + * can't happen, but we test for it + * anyways + * + * ALSO: If bad parity was detected on either + * the status _or_ the message byte then + * the ESP has asserted ATN on the bus + * and we must therefore wait for the + * next phase change. + */ + if(intr & ESP_INTR_FDONE) { + /* We got it all, hallejulia. */ + ESPSTAT(("got both, ")); + SCptr->SCp.Status = esp->esp_command[0]; + SCptr->SCp.Message = esp->esp_command[1]; + esp->prevmsgin = SCptr->SCp.Message; + esp->cur_msgin[0] = SCptr->SCp.Message; + if(esp->sreg & ESP_STAT_PERR) { + /* There was bad parity for the + * message byte, the status byte + * was ok. + */ + message_out = MSG_PARITY_ERROR; + } + } else if(intr == ESP_INTR_BSERV) { + /* Only got status byte. */ + ESPLOG(("esp%d: got status only, ", esp->esp_id)); + if(!(esp->sreg & ESP_STAT_PERR)) { + SCptr->SCp.Status = esp->esp_command[0]; + SCptr->SCp.Message = 0xff; + } else { + /* The status byte had bad parity. + * we leave the scsi_pointer Status + * field alone as we set it to a default + * of CHECK_CONDITION in esp_queue. + */ + message_out = INITIATOR_ERROR; + } + } else { + /* This shouldn't happen ever. */ + ESPSTAT(("got bolixed\n")); + esp_advance_phase(SCptr, in_the_dark); + return esp_do_phase_determine(esp, eregs); + } + + if(!message_out) { + ESPSTAT(("status=%2x msg=%2x, ", SCptr->SCp.Status, + SCptr->SCp.Message)); + if(SCptr->SCp.Message == COMMAND_COMPLETE) { + ESPSTAT(("and was COMMAND_COMPLETE\n")); + esp_advance_phase(SCptr, in_freeing); + return esp_do_freebus(esp, eregs); + } else { + ESPLOG(("esp%d: and _not_ COMMAND_COMPLETE\n", + esp->esp_id)); + esp->msgin_len = esp->msgin_ctr = 1; + esp_advance_phase(SCptr, in_msgindone); + return esp_do_msgindone(esp, eregs); + } + } else { + /* With luck we'll be able to let the target + * know that bad parity happened, it will know + * which byte caused the problems and send it + * again. For the case where the status byte + * receives bad parity, I do not believe most + * targets recover very well. We'll see. + */ + ESPLOG(("esp%d: bad parity somewhere mout=%2x\n", + esp->esp_id, message_out)); + esp->cur_msgout[0] = message_out; + esp->msgout_len = esp->msgout_ctr = 1; + esp_advance_phase(SCptr, in_the_dark); + return esp_do_phase_determine(esp, eregs); + } + } else { + /* If we disconnect now, all hell breaks loose. */ + ESPLOG(("esp%d: whoops, disconnect\n", esp->esp_id)); + esp_advance_phase(SCptr, in_the_dark); + return esp_do_phase_determine(esp, eregs); + } +} + +static int esp_enter_status(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + unchar thecmd = ESP_CMD_ICCSEQ; + + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + + if(esp->do_pio_cmds) { + esp_advance_phase(esp->current_SC, in_status); + esp_cmd(esp, eregs, thecmd); + while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR)); + esp->esp_command[0] = esp_read(eregs->esp_fdata); + while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR)); + esp->esp_command[1] = esp_read(eregs->esp_fdata); + } else { + esp->esp_command[0] = esp->esp_command[1] = 0xff; + esp_write(eregs->esp_tclow, 2); + esp_write(eregs->esp_tcmed, 0); + esp->dma_init_read(esp, esp->esp_command_dvma, 2); + thecmd |= ESP_CMD_DMA; + esp_cmd(esp, eregs, thecmd); + esp_advance_phase(esp->current_SC, in_status); + } + + return esp_do_status(esp, eregs); +} + +static int esp_disconnect_amidst_phases(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + Scsi_Cmnd *sp = esp->current_SC; + struct esp_device *esp_dev = sp->device->hostdata; + + /* This means real problems if we see this + * here. Unless we were actually trying + * to force the device to abort/reset. + */ + ESPLOG(("esp%d: Disconnect amidst phases, ", esp->esp_id)); + ESPLOG(("pphase<%s> cphase<%s>, ", + phase_string(sp->SCp.phase), + phase_string(sp->SCp.sent_command))); + + if(esp->disconnected_SC) + esp_cmd(esp, eregs, ESP_CMD_ESEL); + + switch(esp->cur_msgout[0]) { + default: + /* We didn't expect this to happen at all. */ + ESPLOG(("device is bolixed\n")); + esp_advance_phase(sp, in_tgterror); + esp_done(esp, (DID_ERROR << 16)); + break; + + case BUS_DEVICE_RESET: + ESPLOG(("device reset successful\n")); + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + esp_dev->sync = 0; + esp_advance_phase(sp, in_resetdev); + esp_done(esp, (DID_RESET << 16)); + break; + + case ABORT: + ESPLOG(("device abort successful\n")); + esp_advance_phase(sp, in_abortone); + esp_done(esp, (DID_ABORT << 16)); + break; + + }; + return do_intr_end; +} + +static int esp_enter_msgout(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + esp_advance_phase(esp->current_SC, in_msgout); + return esp_do_msgout(esp, eregs); +} + +static int esp_enter_msgin(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + esp_advance_phase(esp->current_SC, in_msgin); + return esp_do_msgin(esp, eregs); +} + +static int esp_enter_cmd(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + esp_advance_phase(esp->current_SC, in_cmdbegin); + return esp_do_cmdbegin(esp, eregs); +} + +static int esp_enter_badphase(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id, + esp->sreg & ESP_STAT_PMASK)); + return do_reset_bus; +} + +typedef int (*espfunc_t)(struct NCR_ESP *, + struct ESP_regs *); + +static espfunc_t phase_vector[] = { + esp_do_data, /* ESP_DOP */ + esp_do_data, /* ESP_DIP */ + esp_enter_cmd, /* ESP_CMDP */ + esp_enter_status, /* ESP_STATP */ + esp_enter_badphase, /* ESP_STAT_PMSG */ + esp_enter_badphase, /* ESP_STAT_PMSG | ESP_STAT_PIO */ + esp_enter_msgout, /* ESP_MOP */ + esp_enter_msgin, /* ESP_MIP */ +}; + +/* The target has control of the bus and we have to see where it has + * taken us. + */ +static int esp_do_phase_determine(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + if ((esp->ireg & ESP_INTR_DC) != 0) + return esp_disconnect_amidst_phases(esp, eregs); + return phase_vector[esp->sreg & ESP_STAT_PMASK](esp, eregs); +} + +/* First interrupt after exec'ing a cmd comes here. */ +static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + struct esp_device *esp_dev = SCptr->device->hostdata; + int cmd_bytes_sent, fcnt; + + fcnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES); + cmd_bytes_sent = esp->dma_bytes_sent(esp, fcnt); + if(esp->dma_invalidate) + esp->dma_invalidate(esp); + + /* Let's check to see if a reselect happened + * while we we're trying to select. This must + * be checked first. + */ + if(esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) { + esp_reconnect(esp, SCptr); + return esp_do_reconnect(esp, eregs); + } + + /* Looks like things worked, we should see a bus service & + * a function complete interrupt at this point. Note we + * are doing a direct comparison because we don't want to + * be fooled into thinking selection was successful if + * ESP_INTR_DC is set, see below. + */ + if(esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) { + /* target speaks... */ + esp->targets_present |= (1<snip) + esp_dev->sync = 1; + + /* See how far, if at all, we got in getting + * the information out to the target. + */ + switch(esp->seqreg) { + default: + + case ESP_STEP_ASEL: + /* Arbitration won, target selected, but + * we are in some phase which is not command + * phase nor is it message out phase. + * + * XXX We've confused the target, obviously. + * XXX So clear it's state, but we also end + * XXX up clearing everyone elses. That isn't + * XXX so nice. I'd like to just reset this + * XXX target, but if I cannot even get it's + * XXX attention and finish selection to talk + * XXX to it, there is not much more I can do. + * XXX If we have a loaded bus we're going to + * XXX spend the next second or so renegotiating + * XXX for synchronous transfers. + */ + ESPLOG(("esp%d: STEP_ASEL for tgt %d\n", + esp->esp_id, SCptr->device->id)); + + case ESP_STEP_SID: + /* Arbitration won, target selected, went + * to message out phase, sent one message + * byte, then we stopped. ATN is asserted + * on the SCSI bus and the target is still + * there hanging on. This is a legal + * sequence step if we gave the ESP a select + * and stop command. + * + * XXX See above, I could set the borken flag + * XXX in the device struct and retry the + * XXX command. But would that help for + * XXX tagged capable targets? + */ + + case ESP_STEP_NCMD: + /* Arbitration won, target selected, maybe + * sent the one message byte in message out + * phase, but we did not go to command phase + * in the end. Actually, we could have sent + * only some of the message bytes if we tried + * to send out the entire identify and tag + * message using ESP_CMD_SA3. + */ + cmd_bytes_sent = 0; + break; + + case ESP_STEP_PPC: + /* No, not the powerPC pinhead. Arbitration + * won, all message bytes sent if we went to + * message out phase, went to command phase + * but only part of the command was sent. + * + * XXX I've seen this, but usually in conjunction + * XXX with a gross error which appears to have + * XXX occurred between the time I told the + * XXX ESP to arbitrate and when I got the + * XXX interrupt. Could I have misloaded the + * XXX command bytes into the fifo? Actually, + * XXX I most likely missed a phase, and therefore + * XXX went into never never land and didn't even + * XXX know it. That was the old driver though. + * XXX What is even more peculiar is that the ESP + * XXX showed the proper function complete and + * XXX bus service bits in the interrupt register. + */ + + case ESP_STEP_FINI4: + case ESP_STEP_FINI5: + case ESP_STEP_FINI6: + case ESP_STEP_FINI7: + /* Account for the identify message */ + if(SCptr->SCp.phase == in_slct_norm) + cmd_bytes_sent -= 1; + }; + esp_cmd(esp, eregs, ESP_CMD_NULL); + + /* Be careful, we could really get fucked during synchronous + * data transfers if we try to flush the fifo now. + */ + if(!fcnt && /* Fifo is empty and... */ + /* either we are not doing synchronous transfers or... */ + (!esp_dev->sync_max_offset || + /* We are not going into data in phase. */ + ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP))) + esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* flush is safe */ + + /* See how far we got if this is not a slow command. */ + if(!esp->esp_slowcmd) { + if(cmd_bytes_sent < 0) + cmd_bytes_sent = 0; + if(cmd_bytes_sent != SCptr->cmd_len) { + /* Crapola, mark it as a slowcmd + * so that we have some chance of + * keeping the command alive with + * good luck. + * + * XXX Actually, if we didn't send it all + * XXX this means either we didn't set things + * XXX up properly (driver bug) or the target + * XXX or the ESP detected parity on one of + * XXX the command bytes. This makes much + * XXX more sense, and therefore this code + * XXX should be changed to send out a + * XXX parity error message or if the status + * XXX register shows no parity error then + * XXX just expect the target to bring the + * XXX bus into message in phase so that it + * XXX can send us the parity error message. + * XXX SCSI sucks... + */ + esp->esp_slowcmd = 1; + esp->esp_scmdp = &(SCptr->cmnd[cmd_bytes_sent]); + esp->esp_scmdleft = (SCptr->cmd_len - cmd_bytes_sent); + } + } + + /* Now figure out where we went. */ + esp_advance_phase(SCptr, in_the_dark); + return esp_do_phase_determine(esp, eregs); + } + + /* Did the target even make it? */ + if(esp->ireg == ESP_INTR_DC) { + /* wheee... nobody there or they didn't like + * what we told it to do, clean up. + */ + + /* If anyone is off the bus, but working on + * a command in the background for us, tell + * the ESP to listen for them. + */ + if(esp->disconnected_SC) + esp_cmd(esp, eregs, ESP_CMD_ESEL); + + if(((1<device->id) & esp->targets_present) && + esp->seqreg && esp->cur_msgout[0] == EXTENDED_MESSAGE && + (SCptr->SCp.phase == in_slct_msg || + SCptr->SCp.phase == in_slct_stop)) { + /* shit */ + esp->snip = 0; + ESPLOG(("esp%d: Failed synchronous negotiation for target %d " + "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun)); + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + esp_dev->sync = 1; /* so we don't negotiate again */ + + /* Run the command again, this time though we + * won't try to negotiate for synchronous transfers. + * + * XXX I'd like to do something like send an + * XXX INITIATOR_ERROR or ABORT message to the + * XXX target to tell it, "Sorry I confused you, + * XXX please come back and I will be nicer next + * XXX time". But that requires having the target + * XXX on the bus, and it has dropped BSY on us. + */ + esp->current_SC = NULL; + esp_advance_phase(SCptr, not_issued); + prepend_SC(&esp->issue_SC, SCptr); + esp_exec_cmd(esp); + return do_intr_end; + } + + /* Ok, this is normal, this is what we see during boot + * or whenever when we are scanning the bus for targets. + * But first make sure that is really what is happening. + */ + if(((1<device->id) & esp->targets_present)) { + ESPLOG(("esp%d: Warning, live target %d not responding to " + "selection.\n", esp->esp_id, SCptr->device->id)); + + /* This _CAN_ happen. The SCSI standard states that + * the target is to _not_ respond to selection if + * _it_ detects bad parity on the bus for any reason. + * Therefore, we assume that if we've talked successfully + * to this target before, bad parity is the problem. + */ + esp_done(esp, (DID_PARITY << 16)); + } else { + /* Else, there really isn't anyone there. */ + ESPMISC(("esp: selection failure, maybe nobody there?\n")); + ESPMISC(("esp: target %d lun %d\n", + SCptr->device->id, SCptr->device->lun)); + esp_done(esp, (DID_BAD_TARGET << 16)); + } + return do_intr_end; + } + + + ESPLOG(("esp%d: Selection failure.\n", esp->esp_id)); + printk("esp%d: Currently -- ", esp->esp_id); + esp_print_ireg(esp->ireg); + printk(" "); + esp_print_statreg(esp->sreg); + printk(" "); + esp_print_seqreg(esp->seqreg); + printk("\n"); + printk("esp%d: New -- ", esp->esp_id); + esp->sreg = esp_read(eregs->esp_status); + esp->seqreg = esp_read(eregs->esp_sstep); + esp->ireg = esp_read(eregs->esp_intrpt); + esp_print_ireg(esp->ireg); + printk(" "); + esp_print_statreg(esp->sreg); + printk(" "); + esp_print_seqreg(esp->seqreg); + printk("\n"); + ESPLOG(("esp%d: resetting bus\n", esp->esp_id)); + return do_reset_bus; /* ugh... */ +} + +/* Continue reading bytes for msgin phase. */ +static int esp_do_msgincont(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + if(esp->ireg & ESP_INTR_BSERV) { + /* in the right phase too? */ + if((esp->sreg & ESP_STAT_PMASK) == ESP_MIP) { + /* phew... */ + esp_cmd(esp, eregs, ESP_CMD_TI); + esp_advance_phase(esp->current_SC, in_msgindone); + return do_intr_end; + } + + /* We changed phase but ESP shows bus service, + * in this case it is most likely that we, the + * hacker who has been up for 20hrs straight + * staring at the screen, drowned in coffee + * smelling like retched cigarette ashes + * have miscoded something..... so, try to + * recover as best we can. + */ + ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id)); + } + esp_advance_phase(esp->current_SC, in_the_dark); + return do_phase_determine; +} + +static int check_singlebyte_msg(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + esp->prevmsgin = esp->cur_msgin[0]; + if(esp->cur_msgin[0] & 0x80) { + /* wheee... */ + ESPLOG(("esp%d: target sends identify amidst phases\n", + esp->esp_id)); + esp_advance_phase(esp->current_SC, in_the_dark); + return 0; + } else if(((esp->cur_msgin[0] & 0xf0) == 0x20) || + (esp->cur_msgin[0] == EXTENDED_MESSAGE)) { + esp->msgin_len = 2; + esp_advance_phase(esp->current_SC, in_msgincont); + return 0; + } + esp_advance_phase(esp->current_SC, in_the_dark); + switch(esp->cur_msgin[0]) { + default: + /* We don't want to hear about it. */ + ESPLOG(("esp%d: msg %02x which we don't know about\n", esp->esp_id, + esp->cur_msgin[0])); + return MESSAGE_REJECT; + + case NOP: + ESPLOG(("esp%d: target %d sends a nop\n", esp->esp_id, + esp->current_SC->device->id)); + return 0; + + case RESTORE_POINTERS: + /* In this case we might also have to backup the + * "slow command" pointer. It is rare to get such + * a save/restore pointer sequence so early in the + * bus transition sequences, but cover it. + */ + if(esp->esp_slowcmd) { + esp->esp_scmdleft = esp->current_SC->cmd_len; + esp->esp_scmdp = &esp->current_SC->cmnd[0]; + } + esp_restore_pointers(esp, esp->current_SC); + return 0; + + case SAVE_POINTERS: + esp_save_pointers(esp, esp->current_SC); + return 0; + + case COMMAND_COMPLETE: + case DISCONNECT: + /* Freeing the bus, let it go. */ + esp->current_SC->SCp.phase = in_freeing; + return 0; + + case MESSAGE_REJECT: + ESPMISC(("msg reject, ")); + if(esp->prevmsgout == EXTENDED_MESSAGE) { + struct esp_device *esp_dev = esp->current_SC->device->hostdata; + + /* Doesn't look like this target can + * do synchronous or WIDE transfers. + */ + ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n")); + esp_dev->sync = 1; + esp_dev->wide = 1; + esp_dev->sync_min_period = 0; + esp_dev->sync_max_offset = 0; + return 0; + } else { + ESPMISC(("not sync nego, sending ABORT\n")); + return ABORT; + } + }; +} + +/* Target negotiates for synchronous transfers before we do, this + * is legal although very strange. What is even funnier is that + * the SCSI2 standard specifically recommends against targets doing + * this because so many initiators cannot cope with this occurring. + */ +static int target_with_ants_in_pants(struct NCR_ESP *esp, + Scsi_Cmnd *SCptr, + struct esp_device *esp_dev) +{ + if(esp_dev->sync || SCptr->device->borken) { + /* sorry, no can do */ + ESPSDTR(("forcing to async, ")); + build_sync_nego_msg(esp, 0, 0); + esp_dev->sync = 1; + esp->snip = 1; + ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id)); + esp_advance_phase(SCptr, in_the_dark); + return EXTENDED_MESSAGE; + } + + /* Ok, we'll check them out... */ + return 0; +} + +static void sync_report(struct NCR_ESP *esp) +{ + int msg3, msg4; + char *type; + + msg3 = esp->cur_msgin[3]; + msg4 = esp->cur_msgin[4]; + if(msg4) { + int hz = 1000000000 / (msg3 * 4); + int integer = hz / 1000000; + int fraction = (hz - (integer * 1000000)) / 10000; + if((msg3 * 4) < 200) { + type = "FAST"; + } else { + type = "synchronous"; + } + + /* Do not transform this back into one big printk + * again, it triggers a bug in our sparc64-gcc272 + * sibling call optimization. -DaveM + */ + ESPLOG((KERN_INFO "esp%d: target %d ", + esp->esp_id, esp->current_SC->device->id)); + ESPLOG(("[period %dns offset %d %d.%02dMHz ", + (int) msg3 * 4, (int) msg4, + integer, fraction)); + ESPLOG(("%s SCSI%s]\n", type, + (((msg3 * 4) < 200) ? "-II" : ""))); + } else { + ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n", + esp->esp_id, esp->current_SC->device->id)); + } +} + +static int check_multibyte_msg(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + struct esp_device *esp_dev = SCptr->device->hostdata; + unchar regval = 0; + int message_out = 0; + + ESPSDTR(("chk multibyte msg: ")); + if(esp->cur_msgin[2] == EXTENDED_SDTR) { + int period = esp->cur_msgin[3]; + int offset = esp->cur_msgin[4]; + + ESPSDTR(("is sync nego response, ")); + if(!esp->snip) { + int rval; + + /* Target negotiates first! */ + ESPSDTR(("target jumps the gun, ")); + message_out = EXTENDED_MESSAGE; /* we must respond */ + rval = target_with_ants_in_pants(esp, SCptr, esp_dev); + if(rval) + return rval; + } + + ESPSDTR(("examining sdtr, ")); + + /* Offset cannot be larger than ESP fifo size. */ + if(offset > 15) { + ESPSDTR(("offset too big %2x, ", offset)); + offset = 15; + ESPSDTR(("sending back new offset\n")); + build_sync_nego_msg(esp, period, offset); + return EXTENDED_MESSAGE; + } + + if(offset && period > esp->max_period) { + /* Yeee, async for this slow device. */ + ESPSDTR(("period too long %2x, ", period)); + build_sync_nego_msg(esp, 0, 0); + ESPSDTR(("hoping for msgout\n")); + esp_advance_phase(esp->current_SC, in_the_dark); + return EXTENDED_MESSAGE; + } else if (offset && period < esp->min_period) { + ESPSDTR(("period too short %2x, ", period)); + period = esp->min_period; + if(esp->erev > esp236) + regval = 4; + else + regval = 5; + } else if(offset) { + int tmp; + + ESPSDTR(("period is ok, ")); + tmp = esp->ccycle / 1000; + regval = (((period << 2) + tmp - 1) / tmp); + if(regval && (esp->erev > esp236)) { + if(period >= 50) + regval--; + } + } + + if(offset) { + unchar bit; + + esp_dev->sync_min_period = (regval & 0x1f); + esp_dev->sync_max_offset = (offset | esp->radelay); + if(esp->erev > esp236) { + if(esp->erev == fas100a) + bit = ESP_CONFIG3_FAST; + else + bit = ESP_CONFIG3_FSCSI; + if(period < 50) + esp->config3[SCptr->device->id] |= bit; + else + esp->config3[SCptr->device->id] &= ~bit; + esp->prev_cfg3 = esp->config3[SCptr->device->id]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + } + esp->prev_soff = esp_dev->sync_min_period; + esp_write(eregs->esp_soff, esp->prev_soff); + esp->prev_stp = esp_dev->sync_max_offset; + esp_write(eregs->esp_stp, esp->prev_stp); + + ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n", + esp_dev->sync_max_offset, + esp_dev->sync_min_period, + esp->config3[scmd_id(SCptr)])); + + esp->snip = 0; + } else if(esp_dev->sync_max_offset) { + unchar bit; + + /* back to async mode */ + ESPSDTR(("unaccaptable sync nego, forcing async\n")); + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + esp->prev_soff = 0; + esp_write(eregs->esp_soff, 0); + esp->prev_stp = 0; + esp_write(eregs->esp_stp, 0); + if(esp->erev > esp236) { + if(esp->erev == fas100a) + bit = ESP_CONFIG3_FAST; + else + bit = ESP_CONFIG3_FSCSI; + esp->config3[SCptr->device->id] &= ~bit; + esp->prev_cfg3 = esp->config3[SCptr->device->id]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + } + } + + sync_report(esp); + + ESPSDTR(("chk multibyte msg: sync is known, ")); + esp_dev->sync = 1; + + if(message_out) { + ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n", + esp->esp_id)); + build_sync_nego_msg(esp, period, offset); + esp_advance_phase(SCptr, in_the_dark); + return EXTENDED_MESSAGE; + } + + ESPSDTR(("returning zero\n")); + esp_advance_phase(SCptr, in_the_dark); /* ...or else! */ + return 0; + } else if(esp->cur_msgin[2] == EXTENDED_WDTR) { + ESPLOG(("esp%d: AIEEE wide msg received\n", esp->esp_id)); + message_out = MESSAGE_REJECT; + } else if(esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) { + ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id)); + message_out = MESSAGE_REJECT; + } + esp_advance_phase(SCptr, in_the_dark); + return message_out; +} + +static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + int message_out = 0, it = 0, rval; + + rval = skipahead1(esp, eregs, SCptr, in_msgin, in_msgindone); + if(rval) + return rval; + if(SCptr->SCp.sent_command != in_status) { + if(!(esp->ireg & ESP_INTR_DC)) { + if(esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) { + message_out = MSG_PARITY_ERROR; + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + } else if((it = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES))!=1) { + /* We certainly dropped the ball somewhere. */ + message_out = INITIATOR_ERROR; + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + } else if(!esp->msgin_len) { + it = esp_read(eregs->esp_fdata); + esp_advance_phase(SCptr, in_msgincont); + } else { + /* it is ok and we want it */ + it = esp->cur_msgin[esp->msgin_ctr] = + esp_read(eregs->esp_fdata); + esp->msgin_ctr++; + } + } else { + esp_advance_phase(SCptr, in_the_dark); + return do_work_bus; + } + } else { + it = esp->cur_msgin[0]; + } + if(!message_out && esp->msgin_len) { + if(esp->msgin_ctr < esp->msgin_len) { + esp_advance_phase(SCptr, in_msgincont); + } else if(esp->msgin_len == 1) { + message_out = check_singlebyte_msg(esp, eregs); + } else if(esp->msgin_len == 2) { + if(esp->cur_msgin[0] == EXTENDED_MESSAGE) { + if((it+2) >= 15) { + message_out = MESSAGE_REJECT; + } else { + esp->msgin_len = (it + 2); + esp_advance_phase(SCptr, in_msgincont); + } + } else { + message_out = MESSAGE_REJECT; /* foo on you */ + } + } else { + message_out = check_multibyte_msg(esp, eregs); + } + } + if(message_out < 0) { + return -message_out; + } else if(message_out) { + if(((message_out != 1) && + ((message_out < 0x20) || (message_out & 0x80)))) + esp->msgout_len = 1; + esp->cur_msgout[0] = message_out; + esp_cmd(esp, eregs, ESP_CMD_SATN); + esp_advance_phase(SCptr, in_the_dark); + esp->msgin_len = 0; + } + esp->sreg = esp_read(eregs->esp_status); + esp->sreg &= ~(ESP_STAT_INTR); + if((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD)) + esp_cmd(esp, eregs, ESP_CMD_MOK); + if((SCptr->SCp.sent_command == in_msgindone) && + (SCptr->SCp.phase == in_freeing)) + return esp_do_freebus(esp, eregs); + return do_intr_end; +} + +static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + unsigned char tmp; + Scsi_Cmnd *SCptr = esp->current_SC; + + esp_advance_phase(SCptr, in_cmdend); + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + tmp = *esp->esp_scmdp++; + esp->esp_scmdleft--; + esp_write(eregs->esp_fdata, tmp); + esp_cmd(esp, eregs, ESP_CMD_TI); + return do_intr_end; +} + +static int esp_do_cmddone(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + esp_cmd(esp, eregs, ESP_CMD_NULL); + if(esp->ireg & ESP_INTR_BSERV) { + esp_advance_phase(esp->current_SC, in_the_dark); + return esp_do_phase_determine(esp, eregs); + } + ESPLOG(("esp%d: in do_cmddone() but didn't get BSERV interrupt.\n", + esp->esp_id)); + return do_reset_bus; +} + +static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + switch(esp->msgout_len) { + case 1: + esp_write(eregs->esp_fdata, esp->cur_msgout[0]); + esp_cmd(esp, eregs, ESP_CMD_TI); + break; + + case 2: + if(esp->do_pio_cmds){ + esp_write(eregs->esp_fdata, esp->cur_msgout[0]); + esp_write(eregs->esp_fdata, esp->cur_msgout[1]); + esp_cmd(esp, eregs, ESP_CMD_TI); + } else { + esp->esp_command[0] = esp->cur_msgout[0]; + esp->esp_command[1] = esp->cur_msgout[1]; + esp->dma_setup(esp, esp->esp_command_dvma, 2, 0); + esp_setcount(eregs, 2); + esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); + } + break; + + case 4: + esp->snip = 1; + if(esp->do_pio_cmds){ + esp_write(eregs->esp_fdata, esp->cur_msgout[0]); + esp_write(eregs->esp_fdata, esp->cur_msgout[1]); + esp_write(eregs->esp_fdata, esp->cur_msgout[2]); + esp_write(eregs->esp_fdata, esp->cur_msgout[3]); + esp_cmd(esp, eregs, ESP_CMD_TI); + } else { + esp->esp_command[0] = esp->cur_msgout[0]; + esp->esp_command[1] = esp->cur_msgout[1]; + esp->esp_command[2] = esp->cur_msgout[2]; + esp->esp_command[3] = esp->cur_msgout[3]; + esp->dma_setup(esp, esp->esp_command_dvma, 4, 0); + esp_setcount(eregs, 4); + esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); + } + break; + + case 5: + esp->snip = 1; + if(esp->do_pio_cmds){ + esp_write(eregs->esp_fdata, esp->cur_msgout[0]); + esp_write(eregs->esp_fdata, esp->cur_msgout[1]); + esp_write(eregs->esp_fdata, esp->cur_msgout[2]); + esp_write(eregs->esp_fdata, esp->cur_msgout[3]); + esp_write(eregs->esp_fdata, esp->cur_msgout[4]); + esp_cmd(esp, eregs, ESP_CMD_TI); + } else { + esp->esp_command[0] = esp->cur_msgout[0]; + esp->esp_command[1] = esp->cur_msgout[1]; + esp->esp_command[2] = esp->cur_msgout[2]; + esp->esp_command[3] = esp->cur_msgout[3]; + esp->esp_command[4] = esp->cur_msgout[4]; + esp->dma_setup(esp, esp->esp_command_dvma, 5, 0); + esp_setcount(eregs, 5); + esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); + } + break; + + default: + /* whoops */ + ESPMISC(("bogus msgout sending NOP\n")); + esp->cur_msgout[0] = NOP; + esp_write(eregs->esp_fdata, esp->cur_msgout[0]); + esp->msgout_len = 1; + esp_cmd(esp, eregs, ESP_CMD_TI); + break; + } + esp_advance_phase(esp->current_SC, in_msgoutdone); + return do_intr_end; +} + +static int esp_do_msgoutdone(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + if((esp->msgout_len > 1) && esp->dma_barrier) + esp->dma_barrier(esp); + + if(!(esp->ireg & ESP_INTR_DC)) { + esp_cmd(esp, eregs, ESP_CMD_NULL); + switch(esp->sreg & ESP_STAT_PMASK) { + case ESP_MOP: + /* whoops, parity error */ + ESPLOG(("esp%d: still in msgout, parity error assumed\n", + esp->esp_id)); + if(esp->msgout_len > 1) + esp_cmd(esp, eregs, ESP_CMD_SATN); + esp_advance_phase(esp->current_SC, in_msgout); + return do_work_bus; + + case ESP_DIP: + break; + + default: + if(!fcount(esp, eregs) && + !(((struct esp_device *)esp->current_SC->device->hostdata)->sync_max_offset)) + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + break; + + }; + } + + /* If we sent out a synchronous negotiation message, update + * our state. + */ + if(esp->cur_msgout[2] == EXTENDED_MESSAGE && + esp->cur_msgout[4] == EXTENDED_SDTR) { + esp->snip = 1; /* anal retentiveness... */ + } + + esp->prevmsgout = esp->cur_msgout[0]; + esp->msgout_len = 0; + esp_advance_phase(esp->current_SC, in_the_dark); + return esp_do_phase_determine(esp, eregs); +} + +static int esp_bus_unexpected(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + ESPLOG(("esp%d: command in weird state %2x\n", + esp->esp_id, esp->current_SC->SCp.phase)); + return do_reset_bus; +} + +static espfunc_t bus_vector[] = { + esp_do_data_finale, + esp_do_data_finale, + esp_bus_unexpected, + esp_do_msgin, + esp_do_msgincont, + esp_do_msgindone, + esp_do_msgout, + esp_do_msgoutdone, + esp_do_cmdbegin, + esp_do_cmddone, + esp_do_status, + esp_do_freebus, + esp_do_phase_determine, + esp_bus_unexpected, + esp_bus_unexpected, + esp_bus_unexpected, +}; + +/* This is the second tier in our dual-level SCSI state machine. */ +static int esp_work_bus(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + unsigned int phase; + + ESPBUS(("esp_work_bus: ")); + if(!SCptr) { + ESPBUS(("reconnect\n")); + return esp_do_reconnect(esp, eregs); + } + phase = SCptr->SCp.phase; + if ((phase & 0xf0) == in_phases_mask) + return bus_vector[(phase & 0x0f)](esp, eregs); + else if((phase & 0xf0) == in_slct_mask) + return esp_select_complete(esp, eregs); + else + return esp_bus_unexpected(esp, eregs); +} + +static espfunc_t isvc_vector[] = { + NULL, + esp_do_phase_determine, + esp_do_resetbus, + esp_finish_reset, + esp_work_bus +}; + +/* Main interrupt handler for an esp adapter. */ +void esp_handle(struct NCR_ESP *esp) +{ + struct ESP_regs *eregs; + Scsi_Cmnd *SCptr; + int what_next = do_intr_end; + eregs = esp->eregs; + SCptr = esp->current_SC; + + if(esp->dma_irq_entry) + esp->dma_irq_entry(esp); + + /* Check for errors. */ + esp->sreg = esp_read(eregs->esp_status); + esp->sreg &= (~ESP_STAT_INTR); + esp->seqreg = (esp_read(eregs->esp_sstep) & ESP_STEP_VBITS); + esp->ireg = esp_read(eregs->esp_intrpt); /* Unlatch intr and stat regs */ + ESPIRQ(("handle_irq: [sreg<%02x> sstep<%02x> ireg<%02x>]\n", + esp->sreg, esp->seqreg, esp->ireg)); + if(esp->sreg & (ESP_STAT_SPAM)) { + /* Gross error, could be due to one of: + * + * - top of fifo overwritten, could be because + * we tried to do a synchronous transfer with + * an offset greater than ESP fifo size + * + * - top of command register overwritten + * + * - DMA setup to go in one direction, SCSI + * bus points in the other, whoops + * + * - weird phase change during asynchronous + * data phase while we are initiator + */ + ESPLOG(("esp%d: Gross error sreg=%2x\n", esp->esp_id, esp->sreg)); + + /* If a command is live on the bus we cannot safely + * reset the bus, so we'll just let the pieces fall + * where they may. Here we are hoping that the + * target will be able to cleanly go away soon + * so we can safely reset things. + */ + if(!SCptr) { + ESPLOG(("esp%d: No current cmd during gross error, " + "resetting bus\n", esp->esp_id)); + what_next = do_reset_bus; + goto state_machine; + } + } + + /* No current cmd is only valid at this point when there are + * commands off the bus or we are trying a reset. + */ + if(!SCptr && !esp->disconnected_SC && !(esp->ireg & ESP_INTR_SR)) { + /* Panic is safe, since current_SC is null. */ + ESPLOG(("esp%d: no command in esp_handle()\n", esp->esp_id)); + panic("esp_handle: current_SC == penguin within interrupt!"); + } + + if(esp->ireg & (ESP_INTR_IC)) { + /* Illegal command fed to ESP. Outside of obvious + * software bugs that could cause this, there is + * a condition with ESP100 where we can confuse the + * ESP into an erroneous illegal command interrupt + * because it does not scrape the FIFO properly + * for reselection. See esp100_reconnect_hwbug() + * to see how we try very hard to avoid this. + */ + ESPLOG(("esp%d: invalid command\n", esp->esp_id)); + + esp_dump_state(esp, eregs); + + if(SCptr) { + /* Devices with very buggy firmware can drop BSY + * during a scatter list interrupt when using sync + * mode transfers. We continue the transfer as + * expected, the target drops the bus, the ESP + * gets confused, and we get a illegal command + * interrupt because the bus is in the disconnected + * state now and ESP_CMD_TI is only allowed when + * a nexus is alive on the bus. + */ + ESPLOG(("esp%d: Forcing async and disabling disconnect for " + "target %d\n", esp->esp_id, SCptr->device->id)); + SCptr->device->borken = 1; /* foo on you */ + } + + what_next = do_reset_bus; + } else if(!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) { + int phase; + + if(SCptr) { + phase = SCptr->SCp.phase; + if(phase & in_phases_mask) { + what_next = esp_work_bus(esp, eregs); + } else if(phase & in_slct_mask) { + what_next = esp_select_complete(esp, eregs); + } else { + ESPLOG(("esp%d: interrupt for no good reason...\n", + esp->esp_id)); + what_next = do_intr_end; + } + } else { + ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n", + esp->esp_id)); + what_next = do_reset_bus; + } + } else if(esp->ireg & ESP_INTR_SR) { + ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id)); + what_next = do_reset_complete; + } else if(esp->ireg & (ESP_INTR_S | ESP_INTR_SATN)) { + ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n", + esp->esp_id)); + what_next = do_reset_bus; + } else if(esp->ireg & ESP_INTR_RSEL) { + if(!SCptr) { + /* This is ok. */ + what_next = esp_do_reconnect(esp, eregs); + } else if(SCptr->SCp.phase & in_slct_mask) { + /* Only selection code knows how to clean + * up properly. + */ + ESPDISC(("Reselected during selection attempt\n")); + what_next = esp_select_complete(esp, eregs); + } else { + ESPLOG(("esp%d: Reselected while bus is busy\n", + esp->esp_id)); + what_next = do_reset_bus; + } + } + + /* This is tier-one in our dual level SCSI state machine. */ +state_machine: + while(what_next != do_intr_end) { + if (what_next >= do_phase_determine && + what_next < do_intr_end) + what_next = isvc_vector[what_next](esp, eregs); + else { + /* state is completely lost ;-( */ + ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n", + esp->esp_id)); + what_next = do_reset_bus; + } + } + if(esp->dma_irq_exit) + esp->dma_irq_exit(esp); +} +EXPORT_SYMBOL(esp_handle); + +#ifndef CONFIG_SMP +irqreturn_t esp_intr(int irq, void *dev_id) +{ + struct NCR_ESP *esp; + unsigned long flags; + int again; + struct Scsi_Host *dev = dev_id; + + /* Handle all ESP interrupts showing at this IRQ level. */ + spin_lock_irqsave(dev->host_lock, flags); +repeat: + again = 0; + for_each_esp(esp) { +#ifndef __mips__ + if(((esp)->irq & 0xff) == irq) { +#endif + if(esp->dma_irq_p(esp)) { + again = 1; + + esp->dma_ints_off(esp); + + ESPIRQ(("I%d(", esp->esp_id)); + esp_handle(esp); + ESPIRQ((")")); + + esp->dma_ints_on(esp); + } +#ifndef __mips__ + } +#endif + } + if(again) + goto repeat; + spin_unlock_irqrestore(dev->host_lock, flags); + return IRQ_HANDLED; +} +#else +/* For SMP we only service one ESP on the list list at our IRQ level! */ +irqreturn_t esp_intr(int irq, void *dev_id) +{ + struct NCR_ESP *esp; + unsigned long flags; + struct Scsi_Host *dev = dev_id; + + /* Handle all ESP interrupts showing at this IRQ level. */ + spin_lock_irqsave(dev->host_lock, flags); + for_each_esp(esp) { + if(((esp)->irq & 0xf) == irq) { + if(esp->dma_irq_p(esp)) { + esp->dma_ints_off(esp); + + ESPIRQ(("I[%d:%d](", + smp_processor_id(), esp->esp_id)); + esp_handle(esp); + ESPIRQ((")")); + + esp->dma_ints_on(esp); + goto out; + } + } + } +out: + spin_unlock_irqrestore(dev->host_lock, flags); + return IRQ_HANDLED; +} +#endif + +int esp_slave_alloc(struct scsi_device *SDptr) +{ + struct esp_device *esp_dev = + kzalloc(sizeof(struct esp_device), GFP_ATOMIC); + + if (!esp_dev) + return -ENOMEM; + SDptr->hostdata = esp_dev; + return 0; +} + +void esp_slave_destroy(struct scsi_device *SDptr) +{ + struct NCR_ESP *esp = (struct NCR_ESP *) SDptr->host->hostdata; + + esp->targets_present &= ~(1 << sdev_id(SDptr)); + kfree(SDptr->hostdata); + SDptr->hostdata = NULL; +} + +#ifdef MODULE +int init_module(void) { return 0; } +void cleanup_module(void) {} +void esp_release(void) +{ + esps_in_use--; + esps_running = esps_in_use; +} +EXPORT_SYMBOL(esp_release); +#endif + +EXPORT_SYMBOL(esp_abort); +EXPORT_SYMBOL(esp_allocate); +EXPORT_SYMBOL(esp_deallocate); +EXPORT_SYMBOL(esp_initialize); +EXPORT_SYMBOL(esp_intr); +EXPORT_SYMBOL(esp_queue); +EXPORT_SYMBOL(esp_reset); +EXPORT_SYMBOL(esp_slave_alloc); +EXPORT_SYMBOL(esp_slave_destroy); +EXPORT_SYMBOL(esps_in_use); + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/NCR53C9x.h b/trunk/drivers/scsi/NCR53C9x.h new file mode 100644 index 000000000000..00a0ba040dba --- /dev/null +++ b/trunk/drivers/scsi/NCR53C9x.h @@ -0,0 +1,668 @@ +/* NCR53C9x.c: Defines and structures for the NCR53C9x generic driver. + * + * Originally esp.h: Defines and structures for the Sparc ESP + * (Enhanced SCSI Processor) driver under Linux. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * Generalization by Jesper Skov (jskov@cygnus.co.uk) + * + * More generalization (for i386 stuff) by Tymm Twillman (tymm@computer.org) + */ + +#ifndef NCR53C9X_H +#define NCR53C9X_H + +#include + +/* djweis for mac driver */ +#if defined(CONFIG_MAC) +#define PAD_SIZE 15 +#else +#define PAD_SIZE 3 +#endif + +/* Handle multiple hostadapters on Amiga + * generally PAD_SIZE = 3 + * but there is one exception: Oktagon (PAD_SIZE = 1) */ +#if defined(CONFIG_OKTAGON_SCSI) || defined(CONFIG_OKTAGON_SCSI_MODULE) +#undef PAD_SIZE +#if defined(CONFIG_BLZ1230_SCSI) || defined(CONFIG_BLZ1230_SCSI_MODULE) || \ + defined(CONFIG_BLZ2060_SCSI) || defined(CONFIG_BLZ2060_SCSI_MODULE) || \ + defined(CONFIG_CYBERSTORM_SCSI) || defined(CONFIG_CYBERSTORM_SCSI_MODULE) || \ + defined(CONFIG_CYBERSTORMII_SCSI) || defined(CONFIG_CYBERSTORMII_SCSI_MODULE) || \ + defined(CONFIG_FASTLANE_SCSI) || defined(CONFIG_FASTLANE_SCSI_MODULE) +#define MULTIPLE_PAD_SIZES +#else +#define PAD_SIZE 1 +#endif +#endif + +/* Macros for debugging messages */ + +#define DEBUG_ESP +/* #define DEBUG_ESP_DATA */ +/* #define DEBUG_ESP_QUEUE */ +/* #define DEBUG_ESP_DISCONNECT */ +/* #define DEBUG_ESP_STATUS */ +/* #define DEBUG_ESP_PHASES */ +/* #define DEBUG_ESP_WORKBUS */ +/* #define DEBUG_STATE_MACHINE */ +/* #define DEBUG_ESP_CMDS */ +/* #define DEBUG_ESP_IRQS */ +/* #define DEBUG_SDTR */ +/* #define DEBUG_ESP_SG */ + +/* Use the following to sprinkle debugging messages in a way which + * suits you if combinations of the above become too verbose when + * trying to track down a specific problem. + */ +/* #define DEBUG_ESP_MISC */ + +#if defined(DEBUG_ESP) +#define ESPLOG(foo) printk foo +#else +#define ESPLOG(foo) +#endif /* (DEBUG_ESP) */ + +#if defined(DEBUG_ESP_DATA) +#define ESPDATA(foo) printk foo +#else +#define ESPDATA(foo) +#endif + +#if defined(DEBUG_ESP_QUEUE) +#define ESPQUEUE(foo) printk foo +#else +#define ESPQUEUE(foo) +#endif + +#if defined(DEBUG_ESP_DISCONNECT) +#define ESPDISC(foo) printk foo +#else +#define ESPDISC(foo) +#endif + +#if defined(DEBUG_ESP_STATUS) +#define ESPSTAT(foo) printk foo +#else +#define ESPSTAT(foo) +#endif + +#if defined(DEBUG_ESP_PHASES) +#define ESPPHASE(foo) printk foo +#else +#define ESPPHASE(foo) +#endif + +#if defined(DEBUG_ESP_WORKBUS) +#define ESPBUS(foo) printk foo +#else +#define ESPBUS(foo) +#endif + +#if defined(DEBUG_ESP_IRQS) +#define ESPIRQ(foo) printk foo +#else +#define ESPIRQ(foo) +#endif + +#if defined(DEBUG_SDTR) +#define ESPSDTR(foo) printk foo +#else +#define ESPSDTR(foo) +#endif + +#if defined(DEBUG_ESP_MISC) +#define ESPMISC(foo) printk foo +#else +#define ESPMISC(foo) +#endif + +/* + * padding for register structure + */ +#ifdef CONFIG_JAZZ_ESP +#define EREGS_PAD(n) +#else +#ifndef MULTIPLE_PAD_SIZES +#define EREGS_PAD(n) unchar n[PAD_SIZE]; +#endif +#endif + +/* The ESP SCSI controllers have their register sets in three + * "classes": + * + * 1) Registers which are both read and write. + * 2) Registers which are read only. + * 3) Registers which are write only. + * + * Yet, they all live within the same IO space. + */ + +#if !defined(__i386__) && !defined(__x86_64__) + +#ifndef MULTIPLE_PAD_SIZES + +#ifdef CONFIG_CPU_HAS_WB +#include +#define esp_write(__reg, __val) do{(__reg) = (__val); wbflush();} while(0) +#else +#define esp_write(__reg, __val) ((__reg) = (__val)) +#endif +#define esp_read(__reg) (__reg) + +struct ESP_regs { + /* Access Description Offset */ + volatile unchar esp_tclow; /* rw Low bits of the transfer count 0x00 */ + EREGS_PAD(tlpad1); + volatile unchar esp_tcmed; /* rw Mid bits of the transfer count 0x04 */ + EREGS_PAD(fdpad); + volatile unchar esp_fdata; /* rw FIFO data bits 0x08 */ + EREGS_PAD(cbpad); + volatile unchar esp_cmnd; /* rw SCSI command bits 0x0c */ + EREGS_PAD(stpad); + volatile unchar esp_status; /* ro ESP status register 0x10 */ +#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */ + EREGS_PAD(irqpd); + volatile unchar esp_intrpt; /* ro Kind of interrupt 0x14 */ +#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */ + EREGS_PAD(sspad); + volatile unchar esp_sstep; /* ro Sequence step register 0x18 */ +#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */ + EREGS_PAD(ffpad); + volatile unchar esp_fflags; /* ro Bits of current FIFO info 0x1c */ +#define esp_soff esp_fflags /* wo Sync offset 0x1c */ + EREGS_PAD(cf1pd); + volatile unchar esp_cfg1; /* rw First configuration register 0x20 */ + EREGS_PAD(cfpad); + volatile unchar esp_cfact; /* wo Clock conversion factor 0x24 */ + EREGS_PAD(ctpad); + volatile unchar esp_ctest; /* wo Chip test register 0x28 */ + EREGS_PAD(cf2pd); + volatile unchar esp_cfg2; /* rw Second configuration register 0x2c */ + EREGS_PAD(cf3pd); + + /* The following is only found on the 53C9X series SCSI chips */ + volatile unchar esp_cfg3; /* rw Third configuration register 0x30 */ + EREGS_PAD(cf4pd); + volatile unchar esp_cfg4; /* rw Fourth configuration register 0x34 */ + EREGS_PAD(thpd); + /* The following is found on all chips except the NCR53C90 (ESP100) */ + volatile unchar esp_tchi; /* rw High bits of transfer count 0x38 */ +#define esp_uid esp_tchi /* ro Unique ID code 0x38 */ + EREGS_PAD(fgpad); + volatile unchar esp_fgrnd; /* rw Data base for fifo 0x3c */ +}; + +#else /* MULTIPLE_PAD_SIZES */ + +#define esp_write(__reg, __val) (*(__reg) = (__val)) +#define esp_read(__reg) (*(__reg)) + +struct ESP_regs { + unsigned char io_addr[64]; /* dummy */ + /* Access Description Offset */ +#define esp_tclow io_addr /* rw Low bits of the transfer count 0x00 */ +#define esp_tcmed io_addr + (1<<(esp->shift)) /* rw Mid bits of the transfer count 0x04 */ +#define esp_fdata io_addr + (2<<(esp->shift)) /* rw FIFO data bits 0x08 */ +#define esp_cmnd io_addr + (3<<(esp->shift)) /* rw SCSI command bits 0x0c */ +#define esp_status io_addr + (4<<(esp->shift)) /* ro ESP status register 0x10 */ +#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */ +#define esp_intrpt io_addr + (5<<(esp->shift)) /* ro Kind of interrupt 0x14 */ +#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */ +#define esp_sstep io_addr + (6<<(esp->shift)) /* ro Sequence step register 0x18 */ +#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */ +#define esp_fflags io_addr + (7<<(esp->shift)) /* ro Bits of current FIFO info 0x1c */ +#define esp_soff esp_fflags /* wo Sync offset 0x1c */ +#define esp_cfg1 io_addr + (8<<(esp->shift)) /* rw First configuration register 0x20 */ +#define esp_cfact io_addr + (9<<(esp->shift)) /* wo Clock conversion factor 0x24 */ +#define esp_ctest io_addr + (10<<(esp->shift)) /* wo Chip test register 0x28 */ +#define esp_cfg2 io_addr + (11<<(esp->shift)) /* rw Second configuration register 0x2c */ + + /* The following is only found on the 53C9X series SCSI chips */ +#define esp_cfg3 io_addr + (12<<(esp->shift)) /* rw Third configuration register 0x30 */ +#define esp_cfg4 io_addr + (13<<(esp->shift)) /* rw Fourth configuration register 0x34 */ + + /* The following is found on all chips except the NCR53C90 (ESP100) */ +#define esp_tchi io_addr + (14<<(esp->shift)) /* rw High bits of transfer count 0x38 */ +#define esp_uid esp_tchi /* ro Unique ID code 0x38 */ +#define esp_fgrnd io_addr + (15<<(esp->shift)) /* rw Data base for fifo 0x3c */ +}; + +#endif + +#else /* !defined(__i386__) && !defined(__x86_64__) */ + +#define esp_write(__reg, __val) outb((__val), (__reg)) +#define esp_read(__reg) inb((__reg)) + +struct ESP_regs { + unsigned int io_addr; + /* Access Description Offset */ +#define esp_tclow io_addr /* rw Low bits of the transfer count 0x00 */ +#define esp_tcmed io_addr + 1 /* rw Mid bits of the transfer count 0x04 */ +#define esp_fdata io_addr + 2 /* rw FIFO data bits 0x08 */ +#define esp_cmnd io_addr + 3 /* rw SCSI command bits 0x0c */ +#define esp_status io_addr + 4 /* ro ESP status register 0x10 */ +#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */ +#define esp_intrpt io_addr + 5 /* ro Kind of interrupt 0x14 */ +#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */ +#define esp_sstep io_addr + 6 /* ro Sequence step register 0x18 */ +#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */ +#define esp_fflags io_addr + 7 /* ro Bits of current FIFO info 0x1c */ +#define esp_soff esp_fflags /* wo Sync offset 0x1c */ +#define esp_cfg1 io_addr + 8 /* rw First configuration register 0x20 */ +#define esp_cfact io_addr + 9 /* wo Clock conversion factor 0x24 */ +#define esp_ctest io_addr + 10 /* wo Chip test register 0x28 */ +#define esp_cfg2 io_addr + 11 /* rw Second configuration register 0x2c */ + + /* The following is only found on the 53C9X series SCSI chips */ +#define esp_cfg3 io_addr + 12 /* rw Third configuration register 0x30 */ +#define esp_cfg4 io_addr + 13 /* rw Fourth configuration register 0x34 */ + + /* The following is found on all chips except the NCR53C90 (ESP100) */ +#define esp_tchi io_addr + 14 /* rw High bits of transfer count 0x38 */ +#define esp_uid esp_tchi /* ro Unique ID code 0x38 */ +#define esp_fgrnd io_addr + 15 /* rw Data base for fifo 0x3c */ +}; + +#endif /* !defined(__i386__) && !defined(__x86_64__) */ + +/* Various revisions of the ESP board. */ +enum esp_rev { + esp100 = 0x00, /* NCR53C90 - very broken */ + esp100a = 0x01, /* NCR53C90A */ + esp236 = 0x02, + fas236 = 0x03, + fas100a = 0x04, + fast = 0x05, + fas366 = 0x06, + fas216 = 0x07, + fsc = 0x08, /* SYM53C94-2 */ + espunknown = 0x09 +}; + +/* We allocate one of these for each scsi device and attach it to + * SDptr->hostdata for use in the driver + */ +struct esp_device { + unsigned char sync_min_period; + unsigned char sync_max_offset; + unsigned sync:1; + unsigned wide:1; + unsigned disconnect:1; +}; + +/* We get one of these for each ESP probed. */ +struct NCR_ESP { + struct NCR_ESP *next; /* Next ESP on probed or NULL */ + struct ESP_regs *eregs; /* All esp registers */ + int dma; /* Who I do transfers with. */ + void *dregs; /* And his registers. */ + struct Scsi_Host *ehost; /* Backpointer to SCSI Host */ + + void *edev; /* Pointer to controller base/SBus */ + int esp_id; /* Unique per-ESP ID number */ + + /* ESP Configuration Registers */ + unsigned char config1; /* Copy of the 1st config register */ + unsigned char config2; /* Copy of the 2nd config register */ + unsigned char config3[16]; /* Copy of the 3rd config register */ + + /* The current command we are sending to the ESP chip. This esp_command + * ptr needs to be mapped in DVMA area so we can send commands and read + * from the ESP fifo without burning precious CPU cycles. Programmed I/O + * sucks when we have the DVMA to do it for us. The ESP is stupid and will + * only send out 6, 10, and 12 byte SCSI commands, others we need to send + * one byte at a time. esp_slowcmd being set says that we are doing one + * of the command types ESP doesn't understand, esp_scmdp keeps track of + * which byte we are sending, esp_scmdleft says how many bytes to go. + */ + volatile unchar *esp_command; /* Location of command (CPU view) */ + __u32 esp_command_dvma; /* Location of command (DVMA view) */ + unsigned char esp_clen; /* Length of this command */ + unsigned char esp_slowcmd; + unsigned char *esp_scmdp; + unsigned char esp_scmdleft; + + /* The following are used to determine the cause of an IRQ. Upon every + * IRQ entry we synchronize these with the hardware registers. + */ + unchar ireg; /* Copy of ESP interrupt register */ + unchar sreg; /* Same for ESP status register */ + unchar seqreg; /* The ESP sequence register */ + + /* The following is set when a premature interrupt condition is detected + * in some FAS revisions. + */ + unchar fas_premature_intr_workaround; + + /* To save register writes to the ESP, which can be expensive, we + * keep track of the previous value that various registers had for + * the last target we connected to. If they are the same for the + * current target, we skip the register writes as they are not needed. + */ + unchar prev_soff, prev_stp, prev_cfg3; + + /* For each target we keep track of save/restore data + * pointer information. This needs to be updated majorly + * when we add support for tagged queueing. -DaveM + */ + struct esp_pointers { + char *saved_ptr; + struct scatterlist *saved_buffer; + int saved_this_residual; + int saved_buffers_residual; + } data_pointers[16] /*XXX [MAX_TAGS_PER_TARGET]*/; + + /* Clock periods, frequencies, synchronization, etc. */ + unsigned int cfreq; /* Clock frequency in HZ */ + unsigned int cfact; /* Clock conversion factor */ + unsigned int ccycle; /* One ESP clock cycle */ + unsigned int ctick; /* One ESP clock time */ + unsigned int radelay; /* FAST chip req/ack delay */ + unsigned int neg_defp; /* Default negotiation period */ + unsigned int sync_defp; /* Default sync transfer period */ + unsigned int max_period; /* longest our period can be */ + unsigned int min_period; /* shortest period we can withstand */ + /* For slow to medium speed input clock rates we shoot for 5mb/s, + * but for high input clock rates we try to do 10mb/s although I + * don't think a transfer can even run that fast with an ESP even + * with DMA2 scatter gather pipelining. + */ +#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */ +#define SYNC_DEFP_FAST 0x19 /* 10mb/s */ + + unsigned int snip; /* Sync. negotiation in progress */ + unsigned int wnip; /* WIDE negotiation in progress */ + unsigned int targets_present; /* targets spoken to before */ + + int current_transfer_size; /* Set at beginning of data dma */ + + unchar espcmdlog[32]; /* Log of current esp cmds sent. */ + unchar espcmdent; /* Current entry in esp cmd log. */ + + /* Misc. info about this ESP */ + enum esp_rev erev; /* ESP revision */ + int irq; /* IRQ for this ESP */ + int scsi_id; /* Who am I as initiator? */ + int scsi_id_mask; /* Bitmask of 'me'. */ + int diff; /* Differential SCSI bus? */ + int slot; /* Slot the adapter occupies */ + + /* Our command queues, only one cmd lives in the current_SC queue. */ + Scsi_Cmnd *issue_SC; /* Commands to be issued */ + Scsi_Cmnd *current_SC; /* Who is currently working the bus */ + Scsi_Cmnd *disconnected_SC; /* Commands disconnected from the bus */ + + /* Message goo */ + unchar cur_msgout[16]; + unchar cur_msgin[16]; + unchar prevmsgout, prevmsgin; + unchar msgout_len, msgin_len; + unchar msgout_ctr, msgin_ctr; + + /* States that we cannot keep in the per cmd structure because they + * cannot be assosciated with any specific command. + */ + unchar resetting_bus; + wait_queue_head_t reset_queue; + + unchar do_pio_cmds; /* Do command transfer with pio */ + + /* How much bits do we have to shift the registers */ + unsigned char shift; + + /* Functions handling DMA + */ + /* Required functions */ + int (*dma_bytes_sent)(struct NCR_ESP *, int); + int (*dma_can_transfer)(struct NCR_ESP *, Scsi_Cmnd *); + void (*dma_dump_state)(struct NCR_ESP *); + void (*dma_init_read)(struct NCR_ESP *, __u32, int); + void (*dma_init_write)(struct NCR_ESP *, __u32, int); + void (*dma_ints_off)(struct NCR_ESP *); + void (*dma_ints_on)(struct NCR_ESP *); + int (*dma_irq_p)(struct NCR_ESP *); + int (*dma_ports_p)(struct NCR_ESP *); + void (*dma_setup)(struct NCR_ESP *, __u32, int, int); + + /* Optional functions (i.e. may be initialized to 0) */ + void (*dma_barrier)(struct NCR_ESP *); + void (*dma_drain)(struct NCR_ESP *); + void (*dma_invalidate)(struct NCR_ESP *); + void (*dma_irq_entry)(struct NCR_ESP *); + void (*dma_irq_exit)(struct NCR_ESP *); + void (*dma_led_off)(struct NCR_ESP *); + void (*dma_led_on)(struct NCR_ESP *); + void (*dma_poll)(struct NCR_ESP *, unsigned char *); + void (*dma_reset)(struct NCR_ESP *); + + /* Optional virtual DMA functions */ + void (*dma_mmu_get_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *); + void (*dma_mmu_get_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *); + void (*dma_mmu_release_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *); + void (*dma_mmu_release_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *); + void (*dma_advance_sg)(Scsi_Cmnd *); +}; + +/* Bitfield meanings for the above registers. */ + +/* ESP config reg 1, read-write, found on all ESP chips */ +#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */ +#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */ +#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */ +#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */ +#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */ +#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */ + +/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236+fsc chips */ +#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236,fsc) */ +#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236,fsc) */ +#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */ +#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tmode only) */ +#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */ +#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */ +#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236,fsc) */ +#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,esp216,fsc) */ +#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (esp236) */ +#define ESP_CONFIG2_RFB 0x80 /* Reserve FIFO byte (fsc) */ +#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */ + +/* ESP config register 3 read-write, found only esp236+fas236+fas100a+fsc chips */ +#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/fas366) */ +#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236/fsc) */ +#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a) */ +#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236/fsc) */ +#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a) */ +#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236/fsc) */ +#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a) */ +#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236/fsc) */ +#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a) */ +#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236/fsc) */ +#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236/fsc) */ +#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236/fsc) */ +#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236/fsc) */ + +/* ESP config register 4 read-write, found only on fsc chips */ +#define ESP_CONFIG4_BBTE 0x01 /* Back-to-Back transfer enable */ +#define ESP_CONFIG4_TEST 0x02 /* Transfer counter test mode */ +#define ESP_CONFIG4_EAN 0x04 /* Enable Active Negotiation */ + +/* ESP command register read-write */ +/* Group 1 commands: These may be sent at any point in time to the ESP + * chip. None of them can generate interrupts 'cept + * the "SCSI bus reset" command if you have not disabled + * SCSI reset interrupts in the config1 ESP register. + */ +#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */ +#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */ +#define ESP_CMD_RC 0x02 /* Chip reset */ +#define ESP_CMD_RS 0x03 /* SCSI bus reset */ + +/* Group 2 commands: ESP must be an initiator and connected to a target + * for these commands to work. + */ +#define ESP_CMD_TI 0x10 /* Transfer Information */ +#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */ +#define ESP_CMD_MOK 0x12 /* Message okie-dokie */ +#define ESP_CMD_TPAD 0x18 /* Transfer Pad */ +#define ESP_CMD_SATN 0x1a /* Set ATN */ +#define ESP_CMD_RATN 0x1b /* De-assert ATN */ + +/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected + * to a target as the initiator for these commands to work. + */ +#define ESP_CMD_SMSG 0x20 /* Send message */ +#define ESP_CMD_SSTAT 0x21 /* Send status */ +#define ESP_CMD_SDATA 0x22 /* Send data */ +#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */ +#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */ +#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */ +#define ESP_CMD_DCNCT 0x27 /* Disconnect */ +#define ESP_CMD_RMSG 0x28 /* Receive Message */ +#define ESP_CMD_RCMD 0x29 /* Receive Command */ +#define ESP_CMD_RDATA 0x2a /* Receive Data */ +#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */ + +/* Group 4 commands: The ESP must be in the disconnected state and must + * not be connected to any targets as initiator for + * these commands to work. + */ +#define ESP_CMD_RSEL 0x40 /* Reselect */ +#define ESP_CMD_SEL 0x41 /* Select w/o ATN */ +#define ESP_CMD_SELA 0x42 /* Select w/ATN */ +#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */ +#define ESP_CMD_ESEL 0x44 /* Enable selection */ +#define ESP_CMD_DSEL 0x45 /* Disable selections */ +#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */ +#define ESP_CMD_RSEL3 0x47 /* Reselect3 */ + +/* This bit enables the ESP's DMA */ +#define ESP_CMD_DMA 0x80 /* Do DMA? */ + +/* ESP status register read-only */ +#define ESP_STAT_PIO 0x01 /* IO phase bit */ +#define ESP_STAT_PCD 0x02 /* CD phase bit */ +#define ESP_STAT_PMSG 0x04 /* MSG phase bit */ +#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */ +#define ESP_STAT_TDONE 0x08 /* Transfer Completed */ +#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */ +#define ESP_STAT_PERR 0x20 /* Parity error */ +#define ESP_STAT_SPAM 0x40 /* Real bad error */ +/* This indicates the 'interrupt pending' condition, it is a reserved + * bit on old revs of the ESP (ESP100, ESP100A, FAS100A). + */ +#define ESP_STAT_INTR 0x80 /* Interrupt */ + +/* The status register can be masked with ESP_STAT_PMASK and compared + * with the following values to determine the current phase the ESP + * (at least thinks it) is in. For our purposes we also add our own + * software 'done' bit for our phase management engine. + */ +#define ESP_DOP (0) /* Data Out */ +#define ESP_DIP (ESP_STAT_PIO) /* Data In */ +#define ESP_CMDP (ESP_STAT_PCD) /* Command */ +#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */ +#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */ +#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */ + +/* ESP interrupt register read-only */ +#define ESP_INTR_S 0x01 /* Select w/o ATN */ +#define ESP_INTR_SATN 0x02 /* Select w/ATN */ +#define ESP_INTR_RSEL 0x04 /* Reselected */ +#define ESP_INTR_FDONE 0x08 /* Function done */ +#define ESP_INTR_BSERV 0x10 /* Bus service */ +#define ESP_INTR_DC 0x20 /* Disconnect */ +#define ESP_INTR_IC 0x40 /* Illegal command given */ +#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */ + +/* Interrupt status macros */ +#define ESP_SRESET_IRQ(esp) ((esp)->intreg & (ESP_INTR_SR)) +#define ESP_ILLCMD_IRQ(esp) ((esp)->intreg & (ESP_INTR_IC)) +#define ESP_SELECT_WITH_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_SATN)) +#define ESP_SELECT_WITHOUT_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_S)) +#define ESP_SELECTION_IRQ(esp) ((ESP_SELECT_WITH_ATN_IRQ(esp)) || \ + (ESP_SELECT_WITHOUT_ATN_IRQ(esp))) +#define ESP_RESELECTION_IRQ(esp) ((esp)->intreg & (ESP_INTR_RSEL)) + +/* ESP sequence step register read-only */ +#define ESP_STEP_VBITS 0x07 /* Valid bits */ +#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */ +#define ESP_STEP_SID 0x01 /* One msg byte sent */ +#define ESP_STEP_NCMD 0x02 /* Was not in command phase */ +#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd + * bytes to be lost + */ +#define ESP_STEP_FINI4 0x04 /* Command was sent ok */ + +/* Ho hum, some ESP's set the step register to this as well... */ +#define ESP_STEP_FINI5 0x05 +#define ESP_STEP_FINI6 0x06 +#define ESP_STEP_FINI7 0x07 +#define ESP_STEP_SOM 0x08 /* Synchronous Offset Max */ + +/* ESP chip-test register read-write */ +#define ESP_TEST_TARG 0x01 /* Target test mode */ +#define ESP_TEST_INI 0x02 /* Initiator test mode */ +#define ESP_TEST_TS 0x04 /* Tristate test mode */ + +/* ESP unique ID register read-only, found on fas236+fas100a+fsc only */ +#define ESP_UID_F100A 0x00 /* FAS100A */ +#define ESP_UID_F236 0x02 /* FAS236 */ +#define ESP_UID_FSC 0xa2 /* NCR53CF9x-2 */ +#define ESP_UID_REV 0x07 /* ESP revision */ +#define ESP_UID_FAM 0xf8 /* ESP family */ + +/* ESP fifo flags register read-only */ +/* Note that the following implies a 16 byte FIFO on the ESP. */ +#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */ +#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100,fsc) */ +#define ESP_FF_SSTEP 0xe0 /* Sequence step */ + +/* ESP clock conversion factor register write-only */ +#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */ +#define ESP_CCF_NEVER 0x01 /* Set it to this and die */ +#define ESP_CCF_F2 0x02 /* 10MHz */ +#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */ +#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */ +#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */ +#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */ +#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */ + +#define ESP_BUS_TIMEOUT 275 /* In milli-seconds */ +#define ESP_TIMEO_CONST 8192 +#define FSC_TIMEO_CONST 7668 +#define ESP_NEG_DEFP(mhz, cfact) \ + ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact))) +#define FSC_NEG_DEFP(mhz, cfact) \ + ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (7668 * (cfact))) +#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000)) +#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000)) + + +/* UGLY, UGLY, UGLY! */ +extern int nesps, esps_in_use, esps_running; + +/* For our interrupt engine. */ +#define for_each_esp(esp) \ + for((esp) = espchain; (esp); (esp) = (esp)->next) + + +/* External functions */ +extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs); +extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *, int); +extern void esp_deallocate(struct NCR_ESP *); +extern void esp_release(void); +extern void esp_initialize(struct NCR_ESP *); +extern irqreturn_t esp_intr(int, void *); +extern const char *esp_info(struct Scsi_Host *); +extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int esp_abort(Scsi_Cmnd *); +extern int esp_reset(Scsi_Cmnd *); +extern int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, + int inout); +extern int esp_slave_alloc(struct scsi_device *); +extern void esp_slave_destroy(struct scsi_device *); +#endif /* !(NCR53C9X_H) */ diff --git a/trunk/drivers/scsi/aacraid/aachba.c b/trunk/drivers/scsi/aacraid/aachba.c index bfd0e64964ac..d7235f42cf5f 100644 --- a/trunk/drivers/scsi/aacraid/aachba.c +++ b/trunk/drivers/scsi/aacraid/aachba.c @@ -859,31 +859,44 @@ static int setinqserial(struct aac_dev *dev, void *data, int cid) le32_to_cpu(dev->adapter_info.serial[0]), cid); } -static inline void set_sense(struct sense_data *sense_data, u8 sense_key, - u8 sense_code, u8 a_sense_code, u8 bit_pointer, u16 field_pointer) +static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code, + u8 a_sense_code, u8 incorrect_length, + u8 bit_pointer, u16 field_pointer, + u32 residue) { - u8 *sense_buf = (u8 *)sense_data; - /* Sense data valid, err code 70h */ - sense_buf[0] = 0x70; /* No info field */ + sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */ sense_buf[1] = 0; /* Segment number, always zero */ - sense_buf[2] = sense_key; /* Sense key */ + if (incorrect_length) { + sense_buf[2] = sense_key | 0x20;/* Set ILI bit | sense key */ + sense_buf[3] = BYTE3(residue); + sense_buf[4] = BYTE2(residue); + sense_buf[5] = BYTE1(residue); + sense_buf[6] = BYTE0(residue); + } else + sense_buf[2] = sense_key; /* Sense key */ + + if (sense_key == ILLEGAL_REQUEST) + sense_buf[7] = 10; /* Additional sense length */ + else + sense_buf[7] = 6; /* Additional sense length */ sense_buf[12] = sense_code; /* Additional sense code */ sense_buf[13] = a_sense_code; /* Additional sense code qualifier */ - if (sense_key == ILLEGAL_REQUEST) { - sense_buf[7] = 10; /* Additional sense length */ + sense_buf[15] = 0; - sense_buf[15] = bit_pointer; + if (sense_code == SENCODE_INVALID_PARAM_FIELD) + sense_buf[15] = 0x80;/* Std sense key specific field */ /* Illegal parameter is in the parameter block */ + if (sense_code == SENCODE_INVALID_CDB_FIELD) - sense_buf[15] |= 0xc0;/* Std sense key specific field */ + sense_buf[15] = 0xc0;/* Std sense key specific field */ /* Illegal parameter is in the CDB block */ + sense_buf[15] |= bit_pointer; sense_buf[16] = field_pointer >> 8; /* MSB */ sense_buf[17] = field_pointer; /* LSB */ - } else - sense_buf[7] = 6; /* Additional sense length */ + } } static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) @@ -893,9 +906,11 @@ static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); + set_sense((u8 *) &dev->fsa_dev[cid].sense_data, + HARDWARE_ERROR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); @@ -1505,9 +1520,11 @@ static void io_callback(void *context, struct fib * fibptr) le32_to_cpu(readreply->status)); #endif scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); + set_sense((u8 *) &dev->fsa_dev[cid].sense_data, + HARDWARE_ERROR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); @@ -1716,9 +1733,11 @@ static void synchronize_callback(void *context, struct fib *fibptr) le32_to_cpu(synchronizereply->status)); cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); + set_sense((u8 *)&dev->fsa_dev[cid].sense_data, + HARDWARE_ERROR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); @@ -1926,9 +1945,10 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) { dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0])); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, - ASENCODE_INVALID_COMMAND, 0, 0); + set_sense((u8 *) &dev->fsa_dev[cid].sense_data, + ILLEGAL_REQUEST, + SENCODE_INVALID_COMMAND, + ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); @@ -1975,9 +1995,10 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - ILLEGAL_REQUEST, SENCODE_INVALID_CDB_FIELD, - ASENCODE_NO_SENSE, 7, 2); + set_sense((u8 *) &dev->fsa_dev[cid].sense_data, + ILLEGAL_REQUEST, + SENCODE_INVALID_CDB_FIELD, + ASENCODE_NO_SENSE, 0, 7, 2, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, @@ -2233,9 +2254,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) */ dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0])); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, - ASENCODE_INVALID_COMMAND, 0, 0); + set_sense((u8 *) &dev->fsa_dev[cid].sense_data, + ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, + ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), diff --git a/trunk/drivers/scsi/aacraid/commctrl.c b/trunk/drivers/scsi/aacraid/commctrl.c index abef05146d75..f8afa358b6b6 100644 --- a/trunk/drivers/scsi/aacraid/commctrl.c +++ b/trunk/drivers/scsi/aacraid/commctrl.c @@ -243,7 +243,6 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) * Search the list of AdapterFibContext addresses on the adapter * to be sure this is a valid address */ - spin_lock_irqsave(&dev->fib_lock, flags); entry = dev->fib_list.next; fibctx = NULL; @@ -252,25 +251,24 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) /* * Extract the AdapterFibContext from the Input parameters. */ - if (fibctx->unique == f.fibctx) { /* We found a winner */ + if (fibctx->unique == f.fibctx) { /* We found a winner */ break; } entry = entry->next; fibctx = NULL; } if (!fibctx) { - spin_unlock_irqrestore(&dev->fib_lock, flags); dprintk ((KERN_INFO "Fib Context not found\n")); return -EINVAL; } if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || (fibctx->size != sizeof(struct aac_fib_context))) { - spin_unlock_irqrestore(&dev->fib_lock, flags); dprintk ((KERN_INFO "Fib Context corrupt?\n")); return -EINVAL; } status = 0; + spin_lock_irqsave(&dev->fib_lock, flags); /* * If there are no fibs to send back, then either wait or return * -EAGAIN @@ -416,8 +414,8 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) * @arg: ioctl arguments * * This routine returns the driver version. - * Under Linux, there have been no version incompatibilities, so this is - * simple! + * Under Linux, there have been no version incompatibilities, so this is + * simple! */ static int check_revision(struct aac_dev *dev, void __user *arg) @@ -465,7 +463,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) u32 data_dir; void __user *sg_user[32]; void *sg_list[32]; - u32 sg_indx = 0; + u32 sg_indx = 0; u32 byte_count = 0; u32 actual_fibsize64, actual_fibsize = 0; int i; @@ -519,11 +517,11 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) // Fix up srb for endian and force some values srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this - srbcmd->channel = cpu_to_le32(user_srbcmd->channel); + srbcmd->channel = cpu_to_le32(user_srbcmd->channel); srbcmd->id = cpu_to_le32(user_srbcmd->id); - srbcmd->lun = cpu_to_le32(user_srbcmd->lun); - srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); - srbcmd->flags = cpu_to_le32(flags); + srbcmd->lun = cpu_to_le32(user_srbcmd->lun); + srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); + srbcmd->flags = cpu_to_le32(flags); srbcmd->retry_limit = 0; // Obsolete parameter srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size); memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb)); @@ -788,9 +786,9 @@ static int aac_get_pci_info(struct aac_dev* dev, void __user *arg) pci_info.bus = dev->pdev->bus->number; pci_info.slot = PCI_SLOT(dev->pdev->devfn); - if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { - dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); - return -EFAULT; + if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { + dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); + return -EFAULT; } return 0; } diff --git a/trunk/drivers/scsi/aacraid/linit.c b/trunk/drivers/scsi/aacraid/linit.c index e80d2a0c46af..fb0886140dd7 100644 --- a/trunk/drivers/scsi/aacraid/linit.c +++ b/trunk/drivers/scsi/aacraid/linit.c @@ -1130,29 +1130,31 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, if (error < 0) goto out_deinit; + if (!(aac->adapter_info.options & AAC_OPT_NEW_COMM)) { + error = pci_set_dma_max_seg_size(pdev, 65536); + if (error) + goto out_deinit; + } + /* * Lets override negotiations and drop the maximum SG limit to 34 */ if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) && - (shost->sg_tablesize > 34)) { - shost->sg_tablesize = 34; - shost->max_sectors = (shost->sg_tablesize * 8) + 112; + (aac->scsi_host_ptr->sg_tablesize > 34)) { + aac->scsi_host_ptr->sg_tablesize = 34; + aac->scsi_host_ptr->max_sectors + = (aac->scsi_host_ptr->sg_tablesize * 8) + 112; } if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) && - (shost->sg_tablesize > 17)) { - shost->sg_tablesize = 17; - shost->max_sectors = (shost->sg_tablesize * 8) + 112; + (aac->scsi_host_ptr->sg_tablesize > 17)) { + aac->scsi_host_ptr->sg_tablesize = 17; + aac->scsi_host_ptr->max_sectors + = (aac->scsi_host_ptr->sg_tablesize * 8) + 112; } - error = pci_set_dma_max_seg_size(pdev, - (aac->adapter_info.options & AAC_OPT_NEW_COMM) ? - (shost->max_sectors << 9) : 65536); - if (error) - goto out_deinit; - /* - * Firmware printf works only with older firmware. + * Firware printf works only with older firmware. */ if (aac_drivers[index].quirks & AAC_QUIRK_34SG) aac->printf_enabled = 1; diff --git a/trunk/drivers/scsi/advansys.c b/trunk/drivers/scsi/advansys.c index ccef891d642f..374ed025dc5a 100644 --- a/trunk/drivers/scsi/advansys.c +++ b/trunk/drivers/scsi/advansys.c @@ -12261,7 +12261,7 @@ static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr) /* * Write the EEPROM from 'cfg_buf'. */ -static void __devinit +void __devinit AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) { ushort *wbuf; @@ -12328,7 +12328,7 @@ AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) /* * Write the EEPROM from 'cfg_buf'. */ -static void __devinit +void __devinit AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) { ushort *wbuf; @@ -12395,7 +12395,7 @@ AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) /* * Write the EEPROM from 'cfg_buf'. */ -static void __devinit +void __devinit AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf) { ushort *wbuf; diff --git a/trunk/drivers/scsi/arcmsr/arcmsr.h b/trunk/drivers/scsi/arcmsr/arcmsr.h index 57786502e3ec..a67e29f83ae5 100644 --- a/trunk/drivers/scsi/arcmsr/arcmsr.h +++ b/trunk/drivers/scsi/arcmsr/arcmsr.h @@ -48,7 +48,7 @@ struct class_device_attribute; /*The limit of outstanding scsi command that firmware can handle*/ #define ARCMSR_MAX_OUTSTANDING_CMD 256 #define ARCMSR_MAX_FREECCB_NUM 320 -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/12/24" +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/08/30" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 @@ -248,7 +248,6 @@ struct FIRMWARE_INFO #define ARCMSR_MESSAGE_START_BGRB 0x00060008 #define ARCMSR_MESSAGE_START_DRIVER_MODE 0x000E0008 #define ARCMSR_MESSAGE_SET_POST_WINDOW 0x000F0008 -#define ARCMSR_MESSAGE_ACTIVE_EOI_MODE 0x00100008 /* ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK */ #define ARCMSR_MESSAGE_FIRMWARE_OK 0x80000000 /* ioctl transfer */ @@ -257,7 +256,6 @@ struct FIRMWARE_INFO #define ARCMSR_DRV2IOP_DATA_READ_OK 0x00000002 #define ARCMSR_DRV2IOP_CDB_POSTED 0x00000004 #define ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED 0x00000008 -#define ARCMSR_DRV2IOP_END_OF_INTERRUPT 0x00000010 /* data tunnel buffer between user space program and its firmware */ /* user space data to iop 128bytes */ diff --git a/trunk/drivers/scsi/arcmsr/arcmsr_hba.c b/trunk/drivers/scsi/arcmsr/arcmsr_hba.c index 4f9ff32cfed0..f4a202e8df26 100644 --- a/trunk/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/trunk/drivers/scsi/arcmsr/arcmsr_hba.c @@ -315,6 +315,9 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); } + reg = (struct MessageUnit_B *)(dma_coherent + + ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock)); + dma_addr = dma_coherent_handle; ccb_tmp = (struct CommandControlBlock *)dma_coherent; for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { @@ -368,8 +371,8 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) out: dma_free_coherent(&acb->pdev->dev, - (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 + - sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle); + ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20, + acb->dma_coherent, acb->dma_coherent_handle); return -ENOMEM; } @@ -506,7 +509,6 @@ static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN , reg->iop2drv_doorbell_reg); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg); return 0x00; } msleep(10); @@ -746,7 +748,6 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t fla , ccb->startdone , atomic_read(&acb->ccboutstandingcount)); } - else arcmsr_report_ccb_state(acb, ccb, flag_ccb); } @@ -885,7 +886,7 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \ } } -static int arcmsr_build_ccb(struct AdapterControlBlock *acb, +static void arcmsr_build_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd) { struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; @@ -905,8 +906,6 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb, memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len); nseg = scsi_dma_map(pcmd); - if (nseg > ARCMSR_MAX_SG_ENTRIES) - return FAILED; BUG_ON(nseg < 0); if (nseg) { @@ -947,7 +946,6 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb, arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE; ccb->ccb_flags |= CCB_FLAG_WRITE; } - return SUCCESS; } static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) @@ -1038,22 +1036,18 @@ static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { iounmap(acb->pmuA); - dma_free_coherent(&acb->pdev->dev, - ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, - acb->dma_coherent, - acb->dma_coherent_handle); break; } case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; iounmap(reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL); iounmap(reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER); - dma_free_coherent(&acb->pdev->dev, - (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 + - sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle); } } - + dma_free_coherent(&acb->pdev->dev, + ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, + acb->dma_coherent, + acb->dma_coherent_handle); } void arcmsr_iop_message_read(struct AdapterControlBlock *acb) @@ -1279,9 +1273,7 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) return 1; writel(~outbound_doorbell, reg->iop2drv_doorbell_reg); - /*in case the last action of doorbell interrupt clearance is cached, this action can push HW to write down the clear bit*/ - readl(reg->iop2drv_doorbell_reg); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg); + if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { arcmsr_iop2drv_data_wrote_handle(acb); } @@ -1388,13 +1380,12 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \ case ARCMSR_MESSAGE_READ_RQBUFFER: { unsigned long *ver_addr; + dma_addr_t buf_handle; uint8_t *pQbuffer, *ptmpQbuffer; int32_t allxfer_len = 0; - void *tmp; - tmp = kmalloc(1032, GFP_KERNEL|GFP_DMA); - ver_addr = (unsigned long *)tmp; - if (!tmp) { + ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); + if (!ver_addr) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } @@ -1430,19 +1421,18 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \ memcpy(pcmdmessagefld->messagedatabuffer, (uint8_t *)ver_addr, allxfer_len); pcmdmessagefld->cmdmessage.Length = allxfer_len; pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; - kfree(tmp); + pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); } break; case ARCMSR_MESSAGE_WRITE_WQBUFFER: { unsigned long *ver_addr; + dma_addr_t buf_handle; int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; uint8_t *pQbuffer, *ptmpuserbuffer; - void *tmp; - tmp = kmalloc(1032, GFP_KERNEL|GFP_DMA); - ver_addr = (unsigned long *)tmp; - if (!tmp) { + ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); + if (!ver_addr) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } @@ -1492,7 +1482,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \ retvalue = ARCMSR_MESSAGE_FAIL; } } - kfree(tmp); + pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); } break; @@ -1692,11 +1682,8 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd, ccb = arcmsr_get_freeccb(acb); if (!ccb) return SCSI_MLQUEUE_HOST_BUSY; - if ( arcmsr_build_ccb( acb, ccb, cmd ) == FAILED ) { - cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1); - cmd->scsi_done(cmd); - return 0; - } + + arcmsr_build_ccb(acb, ccb, cmd); arcmsr_post_ccb(acb, ccb); return 0; } @@ -1857,7 +1844,7 @@ static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, } } -static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, +static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, \ struct CommandControlBlock *poll_ccb) { struct MessageUnit_B *reg = acb->pmuB; @@ -1891,7 +1878,7 @@ static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, (acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ poll_ccb_done = (ccb == poll_ccb) ? 1:0; if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { - if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { + if (ccb->startdone == ARCMSR_CCB_ABORTED) { printk(KERN_NOTICE "arcmsr%d: \ scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n" ,acb->host->host_no @@ -1914,7 +1901,7 @@ static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, } /*drain reply FIFO*/ } -static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, +static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, \ struct CommandControlBlock *poll_ccb) { switch (acb->adapter_type) { @@ -2039,7 +2026,6 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) do { firmware_state = readl(reg->iop2drv_doorbell_reg); } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg); } break; } @@ -2104,39 +2090,19 @@ static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb) } } -static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb) -{ - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: - return; - case ACB_ADAPTER_TYPE_B: - { - struct MessageUnit_B *reg = acb->pmuB; - writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell_reg); - if(arcmsr_hbb_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT"); - return; - } - } - break; - } - return; -} - static void arcmsr_iop_init(struct AdapterControlBlock *acb) { uint32_t intmask_org; - /* disable all outbound interrupt */ - intmask_org = arcmsr_disable_outbound_ints(acb); arcmsr_wait_firmware_ready(acb); arcmsr_iop_confirm(acb); + /* disable all outbound interrupt */ + intmask_org = arcmsr_disable_outbound_ints(acb); arcmsr_get_firmware_spec(acb); /*start background rebuild*/ arcmsr_start_adapter_bgrb(acb); /* empty doorbell Qbuffer if door bell ringed */ arcmsr_clear_doorbell_queue_buffer(acb); - arcmsr_enable_eoi_mode(acb); /* enable outbound Post Queue,outbound doorbell Interrupt */ arcmsr_enable_outbound_ints(acb, intmask_org); acb->acb_flags |= ACB_F_IOP_INITED; @@ -2309,7 +2275,6 @@ static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev) arcmsr_start_adapter_bgrb(acb); /* empty doorbell Qbuffer if door bell ringed */ arcmsr_clear_doorbell_queue_buffer(acb); - arcmsr_enable_eoi_mode(acb); /* enable outbound Post Queue,outbound doorbell Interrupt */ arcmsr_enable_outbound_ints(acb, intmask_org); acb->acb_flags |= ACB_F_IOP_INITED; diff --git a/trunk/drivers/scsi/arm/acornscsi.c b/trunk/drivers/scsi/arm/acornscsi.c index 3bedf2466bd1..eceacf6d49ea 100644 --- a/trunk/drivers/scsi/arm/acornscsi.c +++ b/trunk/drivers/scsi/arm/acornscsi.c @@ -1790,7 +1790,7 @@ int acornscsi_starttransfer(AS_Host *host) return 0; } - residual = scsi_bufflen(host->SCpnt) - host->scsi.SCp.scsi_xferred; + residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred; sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer); sbic_arm_writenext(host->scsi.io_port, residual >> 16); @@ -2270,7 +2270,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4b: /* -> PHASE_STATUSIN */ case 0x8b: /* -> PHASE_STATUSIN */ /* DATA IN -> STATUS */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - + host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_readstatusbyte(host); @@ -2281,7 +2281,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4e: /* -> PHASE_MSGOUT */ case 0x8e: /* -> PHASE_MSGOUT */ /* DATA IN -> MESSAGE OUT */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - + host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_sendmessage(host); @@ -2291,7 +2291,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4f: /* message in */ case 0x8f: /* message in */ /* DATA IN -> MESSAGE IN */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - + host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ @@ -2319,7 +2319,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4b: /* -> PHASE_STATUSIN */ case 0x8b: /* -> PHASE_STATUSIN */ /* DATA OUT -> STATUS */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - + host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_dma_adjust(host); @@ -2331,7 +2331,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4e: /* -> PHASE_MSGOUT */ case 0x8e: /* -> PHASE_MSGOUT */ /* DATA OUT -> MESSAGE OUT */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - + host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_dma_adjust(host); @@ -2342,7 +2342,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4f: /* message in */ case 0x8f: /* message in */ /* DATA OUT -> MESSAGE IN */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - + host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_dma_adjust(host); diff --git a/trunk/drivers/scsi/arm/scsi.h b/trunk/drivers/scsi/arm/scsi.h index 138a521ba1a8..bb6550e31926 100644 --- a/trunk/drivers/scsi/arm/scsi.h +++ b/trunk/drivers/scsi/arm/scsi.h @@ -18,32 +18,17 @@ * The scatter-gather list handling. This contains all * the yucky stuff that needs to be fixed properly. */ - -/* - * copy_SCp_to_sg() Assumes contiguous allocation at @sg of at-most @max - * entries of uninitialized memory. SCp is from scsi-ml and has a valid - * (possibly chained) sg-list - */ static inline int copy_SCp_to_sg(struct scatterlist *sg, struct scsi_pointer *SCp, int max) { int bufs = SCp->buffers_residual; - /* FIXME: It should be easy for drivers to loop on copy_SCp_to_sg(). - * and to remove this BUG_ON. Use min() in-its-place - */ BUG_ON(bufs + 1 > max); sg_set_buf(sg, SCp->ptr, SCp->this_residual); - if (bufs) { - struct scatterlist *src_sg; - unsigned i; - - for_each_sg(sg_next(SCp->buffer), src_sg, bufs, i) - *(++sg) = *src_sg; - sg_mark_end(sg); - } - + if (bufs) + memcpy(sg + 1, SCp->buffer + 1, + sizeof(struct scatterlist) * bufs); return bufs + 1; } @@ -51,7 +36,7 @@ static inline int next_SCp(struct scsi_pointer *SCp) { int ret = SCp->buffers_residual; if (ret) { - SCp->buffer = sg_next(SCp->buffer); + SCp->buffer++; SCp->buffers_residual--; SCp->ptr = sg_virt(SCp->buffer); SCp->this_residual = SCp->buffer->length; @@ -83,46 +68,46 @@ static inline void init_SCp(struct scsi_cmnd *SCpnt) { memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer)); - if (scsi_bufflen(SCpnt)) { + if (SCpnt->use_sg) { unsigned long len = 0; + int buf; - SCpnt->SCp.buffer = scsi_sglist(SCpnt); - SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1; + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; SCpnt->SCp.ptr = sg_virt(SCpnt->SCp.buffer); SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - SCpnt->SCp.phase = scsi_bufflen(SCpnt); + SCpnt->SCp.phase = SCpnt->request_bufflen; #ifdef BELT_AND_BRACES - { /* - * Calculate correct buffer length. Some commands - * come in with the wrong scsi_bufflen. - */ - struct scatterlist *sg; - unsigned i, sg_count = scsi_sg_count(SCpnt); - - scsi_for_each_sg(SCpnt, sg, sg_count, i) - len += sg->length; - - if (scsi_bufflen(SCpnt) != len) { - printk(KERN_WARNING - "scsi%d.%c: bad request buffer " - "length %d, should be %ld\n", - SCpnt->device->host->host_no, - '0' + SCpnt->device->id, - scsi_bufflen(SCpnt), len); - /* - * FIXME: Totaly naive fixup. We should abort - * with error - */ - SCpnt->SCp.phase = - min_t(unsigned long, len, - scsi_bufflen(SCpnt)); - } - } + /* + * Calculate correct buffer length. Some commands + * come in with the wrong request_bufflen. + */ + for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++) + len += SCpnt->SCp.buffer[buf].length; + + if (SCpnt->request_bufflen != len) + printk(KERN_WARNING "scsi%d.%c: bad request buffer " + "length %d, should be %ld\n", SCpnt->device->host->host_no, + '0' + SCpnt->device->id, SCpnt->request_bufflen, len); + SCpnt->request_bufflen = len; #endif } else { + SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.phase = SCpnt->request_bufflen; + } + + /* + * If the upper SCSI layers pass a buffer, but zero length, + * we aren't interested in the buffer pointer. + */ + if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.ptr) { +#if 0 //def BELT_AND_BRACES + printk(KERN_WARNING "scsi%d.%c: zero length buffer passed for " + "command ", SCpnt->host->host_no, '0' + SCpnt->target); + __scsi_print_command(SCpnt->cmnd); +#endif SCpnt->SCp.ptr = NULL; - SCpnt->SCp.this_residual = 0; - SCpnt->SCp.phase = 0; } } diff --git a/trunk/drivers/scsi/blz1230.c b/trunk/drivers/scsi/blz1230.c new file mode 100644 index 000000000000..23f7c24ab809 --- /dev/null +++ b/trunk/drivers/scsi/blz1230.c @@ -0,0 +1,353 @@ +/* blz1230.c: Driver for Blizzard 1230 SCSI IV Controller. + * + * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) + * + * This driver is based on the CyberStorm driver, hence the occasional + * reference to CyberStorm. + */ + +/* TODO: + * + * 1) Figure out how to make a cleaner merge with the sparc driver with regard + * to the caches and the Sparc MMU mapping. + * 2) Make as few routines required outside the generic driver. A lot of the + * routines in this file used to be inline! + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include + +#include + +#define MKIV 1 + +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define BLZ1230_ESP_ADDR 0x8000 +#define BLZ1230_DMA_ADDR 0x10000 +#define BLZ1230II_ESP_ADDR 0x10000 +#define BLZ1230II_DMA_ADDR 0x10021 + + +/* The Blizzard 1230 DMA interface + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Only two things can be programmed in the Blizzard DMA: + * 1) The data direction is controlled by the status of bit 31 (1 = write) + * 2) The source/dest address (word aligned, shifted one right) in bits 30-0 + * + * Program DMA by first latching the highest byte of the address/direction + * (i.e. bits 31-24 of the long word constructed as described in steps 1+2 + * above). Then write each byte of the address/direction (starting with the + * top byte, working down) to the DMA address register. + * + * Figure out interrupt status by reading the ESP status byte. + */ +struct blz1230_dma_registers { + volatile unsigned char dma_addr; /* DMA address [0x0000] */ + unsigned char dmapad2[0x7fff]; + volatile unsigned char dma_latch; /* DMA latch [0x8000] */ +}; + +struct blz1230II_dma_registers { + volatile unsigned char dma_addr; /* DMA address [0x0000] */ + unsigned char dmapad2[0xf]; + volatile unsigned char dma_latch; /* DMA latch [0x0010] */ +}; + +#define BLZ1230_DMA_WRITE 0x80000000 + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are transferred to the ESP chip + * via PIO. + */ + +/***************************************************************** Detection */ +int __init blz1230_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct zorro_dev *z = NULL; + unsigned long address; + struct ESP_regs *eregs; + unsigned long board; + +#if MKIV +#define REAL_BLZ1230_ID ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260 +#define REAL_BLZ1230_ESP_ADDR BLZ1230_ESP_ADDR +#define REAL_BLZ1230_DMA_ADDR BLZ1230_DMA_ADDR +#else +#define REAL_BLZ1230_ID ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060 +#define REAL_BLZ1230_ESP_ADDR BLZ1230II_ESP_ADDR +#define REAL_BLZ1230_DMA_ADDR BLZ1230II_DMA_ADDR +#endif + + if ((z = zorro_find_device(REAL_BLZ1230_ID, z))) { + board = z->resource.start; + if (request_mem_region(board+REAL_BLZ1230_ESP_ADDR, + sizeof(struct ESP_regs), "NCR53C9x")) { + /* Do some magic to figure out if the blizzard is + * equipped with a SCSI controller + */ + address = ZTWO_VADDR(board); + eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + REAL_BLZ1230_ESP_ADDR, + 0); + + esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); + udelay(5); + if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)) + goto err_out; + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = 0; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_led_on = 0; + esp->dma_led_off = 0; + esp->dma_poll = 0; + esp->dma_reset = 0; + + /* SCSI chip speed */ + esp->cfreq = 40000000; + + /* The DMA registers on the Blizzard are mapped + * relative to the device (i.e. in the same Zorro + * I/O block). + */ + esp->dregs = (void *)(address + REAL_BLZ1230_DMA_ADDR); + + /* ESP register base */ + esp->eregs = eregs; + + /* Set the command buffer */ + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); + + esp->irq = IRQ_AMIGA_PORTS; + esp->slot = board+REAL_BLZ1230_ESP_ADDR; + if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, + "Blizzard 1230 SCSI IV", esp->ehost)) + goto err_out; + + /* Figure out our scsi ID on the bus */ + esp->scsi_id = 7; + + /* We don't have a differential SCSI-bus. */ + esp->diff = 0; + + esp_initialize(esp); + + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + return esps_in_use; + } + } + return 0; + + err_out: + scsi_unregister(esp->ehost); + esp_deallocate(esp); + release_mem_region(board+REAL_BLZ1230_ESP_ADDR, + sizeof(struct ESP_regs)); + return 0; +} + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Since the Blizzard DMA is fully dedicated to the ESP chip, + * the number of bytes sent (to the ESP chip) equals the number + * of bytes in the FIFO - there is no buffering in the DMA controller. + * XXXX Do I read this right? It is from host to ESP, right? + */ + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + /* I don't think there's any limit on the Blizzard DMA. So we use what + * the ESP chip can handle (24 bit). + */ + unsigned long sz = sp->SCp.this_residual; + if(sz > 0x1000000) + sz = 0x1000000; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ + ESPLOG(("intreq:<%04x>, intena:<%04x>\n", + amiga_custom.intreqr, amiga_custom.intenar)); +} + +void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) +{ +#if MKIV + struct blz1230_dma_registers *dregs = + (struct blz1230_dma_registers *) (esp->dregs); +#else + struct blz1230II_dma_registers *dregs = + (struct blz1230II_dma_registers *) (esp->dregs); +#endif + + cache_clear(addr, length); + + addr >>= 1; + addr &= ~(BLZ1230_DMA_WRITE); + + /* First set latch */ + dregs->dma_latch = (addr >> 24) & 0xff; + + /* Then pump the address to the DMA address register */ +#if MKIV + dregs->dma_addr = (addr >> 24) & 0xff; +#endif + dregs->dma_addr = (addr >> 16) & 0xff; + dregs->dma_addr = (addr >> 8) & 0xff; + dregs->dma_addr = (addr ) & 0xff; +} + +void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) +{ +#if MKIV + struct blz1230_dma_registers *dregs = + (struct blz1230_dma_registers *) (esp->dregs); +#else + struct blz1230II_dma_registers *dregs = + (struct blz1230II_dma_registers *) (esp->dregs); +#endif + + cache_push(addr, length); + + addr >>= 1; + addr |= BLZ1230_DMA_WRITE; + + /* First set latch */ + dregs->dma_latch = (addr >> 24) & 0xff; + + /* Then pump the address to the DMA address register */ +#if MKIV + dregs->dma_addr = (addr >> 24) & 0xff; +#endif + dregs->dma_addr = (addr >> 16) & 0xff; + dregs->dma_addr = (addr >> 8) & 0xff; + dregs->dma_addr = (addr ) & 0xff; +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(esp->irq); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(esp->irq); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR); +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + return ((amiga_custom.intenar) & IF_PORTS); +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if(write){ + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +#define HOSTS_C + +int blz1230_esp_release(struct Scsi_Host *instance) +{ +#ifdef MODULE + unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; + esp_deallocate((struct NCR_ESP *)instance->hostdata); + esp_release(); + release_mem_region(address, sizeof(struct ESP_regs)); + free_irq(IRQ_AMIGA_PORTS, esp_intr); +#endif + return 1; +} + + +static struct scsi_host_template driver_template = { + .proc_name = "esp-blz1230", + .proc_info = esp_proc_info, + .name = "Blizzard1230 SCSI IV", + .detect = blz1230_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = blz1230_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/blz2060.c b/trunk/drivers/scsi/blz2060.c new file mode 100644 index 000000000000..b6203ec00961 --- /dev/null +++ b/trunk/drivers/scsi/blz2060.c @@ -0,0 +1,306 @@ +/* blz2060.c: Driver for Blizzard 2060 SCSI Controller. + * + * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) + * + * This driver is based on the CyberStorm driver, hence the occasional + * reference to CyberStorm. + */ + +/* TODO: + * + * 1) Figure out how to make a cleaner merge with the sparc driver with regard + * to the caches and the Sparc MMU mapping. + * 2) Make as few routines required outside the generic driver. A lot of the + * routines in this file used to be inline! + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include + +#include + +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define BLZ2060_ESP_ADDR 0x1ff00 +#define BLZ2060_DMA_ADDR 0x1ffe0 + + +/* The Blizzard 2060 DMA interface + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Only two things can be programmed in the Blizzard DMA: + * 1) The data direction is controlled by the status of bit 31 (1 = write) + * 2) The source/dest address (word aligned, shifted one right) in bits 30-0 + * + * Figure out interrupt status by reading the ESP status byte. + */ +struct blz2060_dma_registers { + volatile unsigned char dma_led_ctrl; /* DMA led control [0x000] */ + unsigned char dmapad1[0x0f]; + volatile unsigned char dma_addr0; /* DMA address (MSB) [0x010] */ + unsigned char dmapad2[0x03]; + volatile unsigned char dma_addr1; /* DMA address [0x014] */ + unsigned char dmapad3[0x03]; + volatile unsigned char dma_addr2; /* DMA address [0x018] */ + unsigned char dmapad4[0x03]; + volatile unsigned char dma_addr3; /* DMA address (LSB) [0x01c] */ +}; + +#define BLZ2060_DMA_WRITE 0x80000000 + +/* DMA control bits */ +#define BLZ2060_DMA_LED 0x02 /* HD led control 1 = off */ + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static void dma_led_off(struct NCR_ESP *esp); +static void dma_led_on(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are transferred to the ESP chip + * via PIO. + */ + +/***************************************************************** Detection */ +int __init blz2060_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct zorro_dev *z = NULL; + unsigned long address; + + if ((z = zorro_find_device(ZORRO_PROD_PHASE5_BLIZZARD_2060, z))) { + unsigned long board = z->resource.start; + if (request_mem_region(board+BLZ2060_ESP_ADDR, + sizeof(struct ESP_regs), "NCR53C9x")) { + esp = esp_allocate(tpnt, (void *)board + BLZ2060_ESP_ADDR, 0); + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = 0; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_led_on = &dma_led_on; + esp->dma_led_off = &dma_led_off; + esp->dma_poll = 0; + esp->dma_reset = 0; + + /* SCSI chip speed */ + esp->cfreq = 40000000; + + /* The DMA registers on the Blizzard are mapped + * relative to the device (i.e. in the same Zorro + * I/O block). + */ + address = (unsigned long)ZTWO_VADDR(board); + esp->dregs = (void *)(address + BLZ2060_DMA_ADDR); + + /* ESP register base */ + esp->eregs = (struct ESP_regs *)(address + BLZ2060_ESP_ADDR); + + /* Set the command buffer */ + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); + + esp->irq = IRQ_AMIGA_PORTS; + request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, + "Blizzard 2060 SCSI", esp->ehost); + + /* Figure out our scsi ID on the bus */ + esp->scsi_id = 7; + + /* We don't have a differential SCSI-bus. */ + esp->diff = 0; + + esp_initialize(esp); + + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + return esps_in_use; + } + } + return 0; +} + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Since the Blizzard DMA is fully dedicated to the ESP chip, + * the number of bytes sent (to the ESP chip) equals the number + * of bytes in the FIFO - there is no buffering in the DMA controller. + * XXXX Do I read this right? It is from host to ESP, right? + */ + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + /* I don't think there's any limit on the Blizzard DMA. So we use what + * the ESP chip can handle (24 bit). + */ + unsigned long sz = sp->SCp.this_residual; + if(sz > 0x1000000) + sz = 0x1000000; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ + ESPLOG(("intreq:<%04x>, intena:<%04x>\n", + amiga_custom.intreqr, amiga_custom.intenar)); +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct blz2060_dma_registers *dregs = + (struct blz2060_dma_registers *) (esp->dregs); + + cache_clear(addr, length); + + addr >>= 1; + addr &= ~(BLZ2060_DMA_WRITE); + dregs->dma_addr3 = (addr ) & 0xff; + dregs->dma_addr2 = (addr >> 8) & 0xff; + dregs->dma_addr1 = (addr >> 16) & 0xff; + dregs->dma_addr0 = (addr >> 24) & 0xff; +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct blz2060_dma_registers *dregs = + (struct blz2060_dma_registers *) (esp->dregs); + + cache_push(addr, length); + + addr >>= 1; + addr |= BLZ2060_DMA_WRITE; + dregs->dma_addr3 = (addr ) & 0xff; + dregs->dma_addr2 = (addr >> 8) & 0xff; + dregs->dma_addr1 = (addr >> 16) & 0xff; + dregs->dma_addr0 = (addr >> 24) & 0xff; +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(esp->irq); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(esp->irq); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR); +} + +static void dma_led_off(struct NCR_ESP *esp) +{ + ((struct blz2060_dma_registers *) (esp->dregs))->dma_led_ctrl = + BLZ2060_DMA_LED; +} + +static void dma_led_on(struct NCR_ESP *esp) +{ + ((struct blz2060_dma_registers *) (esp->dregs))->dma_led_ctrl = 0; +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + return ((amiga_custom.intenar) & IF_PORTS); +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if(write){ + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +#define HOSTS_C + +int blz2060_esp_release(struct Scsi_Host *instance) +{ +#ifdef MODULE + unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; + + esp_deallocate((struct NCR_ESP *)instance->hostdata); + esp_release(); + release_mem_region(address, sizeof(struct ESP_regs)); + free_irq(IRQ_AMIGA_PORTS, esp_intr); +#endif + return 1; +} + + +static struct scsi_host_template driver_template = { + .proc_name = "esp-blz2060", + .proc_info = esp_proc_info, + .name = "Blizzard2060 SCSI", + .detect = blz2060_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = blz2060_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/cyberstorm.c b/trunk/drivers/scsi/cyberstorm.c new file mode 100644 index 000000000000..c6b98a42e89d --- /dev/null +++ b/trunk/drivers/scsi/cyberstorm.c @@ -0,0 +1,377 @@ +/* cyberstorm.c: Driver for CyberStorm SCSI Controller. + * + * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) + * + * The CyberStorm SCSI driver is based on David S. Miller's ESP driver + * for the Sparc computers. + * + * This work was made possible by Phase5 who willingly (and most generously) + * supported me with hardware and all the information I needed. + */ + +/* TODO: + * + * 1) Figure out how to make a cleaner merge with the sparc driver with regard + * to the caches and the Sparc MMU mapping. + * 2) Make as few routines required outside the generic driver. A lot of the + * routines in this file used to be inline! + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include + +#include + +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define CYBER_ESP_ADDR 0xf400 +#define CYBER_DMA_ADDR 0xf800 + + +/* The CyberStorm DMA interface */ +struct cyber_dma_registers { + volatile unsigned char dma_addr0; /* DMA address (MSB) [0x000] */ + unsigned char dmapad1[1]; + volatile unsigned char dma_addr1; /* DMA address [0x002] */ + unsigned char dmapad2[1]; + volatile unsigned char dma_addr2; /* DMA address [0x004] */ + unsigned char dmapad3[1]; + volatile unsigned char dma_addr3; /* DMA address (LSB) [0x006] */ + unsigned char dmapad4[0x3fb]; + volatile unsigned char cond_reg; /* DMA cond (ro) [0x402] */ +#define ctrl_reg cond_reg /* DMA control (wo) [0x402] */ +}; + +/* DMA control bits */ +#define CYBER_DMA_LED 0x80 /* HD led control 1 = on */ +#define CYBER_DMA_WRITE 0x40 /* DMA direction. 1 = write */ +#define CYBER_DMA_Z3 0x20 /* 16 (Z2) or 32 (CHIP/Z3) bit DMA transfer */ + +/* DMA status bits */ +#define CYBER_DMA_HNDL_INTR 0x80 /* DMA IRQ pending? */ + +/* The bits below appears to be Phase5 Debug bits only; they were not + * described by Phase5 so using them may seem a bit stupid... + */ +#define CYBER_HOST_ID 0x02 /* If set, host ID should be 7, otherwise + * it should be 6. + */ +#define CYBER_SLOW_CABLE 0x08 /* If *not* set, assume SLOW_CABLE */ + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static void dma_led_off(struct NCR_ESP *esp); +static void dma_led_on(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); + +static unsigned char ctrl_data = 0; /* Keep backup of the stuff written + * to ctrl_reg. Always write a copy + * to this register when writing to + * the hardware register! + */ + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are transferred to the ESP chip + * via PIO. + */ + +/***************************************************************** Detection */ +int __init cyber_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct zorro_dev *z = NULL; + unsigned long address; + + while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { + unsigned long board = z->resource.start; + if ((z->id == ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM || + z->id == ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060) && + request_mem_region(board+CYBER_ESP_ADDR, + sizeof(struct ESP_regs), "NCR53C9x")) { + /* Figure out if this is a CyberStorm or really a + * Fastlane/Blizzard Mk II by looking at the board size. + * CyberStorm maps 64kB + * (ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM does anyway) + */ + if(z->resource.end-board != 0xffff) { + release_mem_region(board+CYBER_ESP_ADDR, + sizeof(struct ESP_regs)); + return 0; + } + esp = esp_allocate(tpnt, (void *)board + CYBER_ESP_ADDR, 0); + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = 0; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_led_on = &dma_led_on; + esp->dma_led_off = &dma_led_off; + esp->dma_poll = 0; + esp->dma_reset = 0; + + /* SCSI chip speed */ + esp->cfreq = 40000000; + + /* The DMA registers on the CyberStorm are mapped + * relative to the device (i.e. in the same Zorro + * I/O block). + */ + address = (unsigned long)ZTWO_VADDR(board); + esp->dregs = (void *)(address + CYBER_DMA_ADDR); + + /* ESP register base */ + esp->eregs = (struct ESP_regs *)(address + CYBER_ESP_ADDR); + + /* Set the command buffer */ + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); + + esp->irq = IRQ_AMIGA_PORTS; + request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, + "CyberStorm SCSI", esp->ehost); + /* Figure out our scsi ID on the bus */ + /* The DMA cond flag contains a hardcoded jumper bit + * which can be used to select host number 6 or 7. + * However, even though it may change, we use a hardcoded + * value of 7. + */ + esp->scsi_id = 7; + + /* We don't have a differential SCSI-bus. */ + esp->diff = 0; + + esp_initialize(esp); + + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + return esps_in_use; + } + } + return 0; +} + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Since the CyberStorm DMA is fully dedicated to the ESP chip, + * the number of bytes sent (to the ESP chip) equals the number + * of bytes in the FIFO - there is no buffering in the DMA controller. + * XXXX Do I read this right? It is from host to ESP, right? + */ + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + /* I don't think there's any limit on the CyberDMA. So we use what + * the ESP chip can handle (24 bit). + */ + unsigned long sz = sp->SCp.this_residual; + if(sz > 0x1000000) + sz = 0x1000000; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ + ESPLOG(("esp%d: dma -- cond_reg<%02x>\n", + esp->esp_id, ((struct cyber_dma_registers *) + (esp->dregs))->cond_reg)); + ESPLOG(("intreq:<%04x>, intena:<%04x>\n", + amiga_custom.intreqr, amiga_custom.intenar)); +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct cyber_dma_registers *dregs = + (struct cyber_dma_registers *) esp->dregs; + + cache_clear(addr, length); + + addr &= ~(1); + dregs->dma_addr0 = (addr >> 24) & 0xff; + dregs->dma_addr1 = (addr >> 16) & 0xff; + dregs->dma_addr2 = (addr >> 8) & 0xff; + dregs->dma_addr3 = (addr ) & 0xff; + ctrl_data &= ~(CYBER_DMA_WRITE); + + /* Check if physical address is outside Z2 space and of + * block length/block aligned in memory. If this is the + * case, enable 32 bit transfer. In all other cases, fall back + * to 16 bit transfer. + * Obviously 32 bit transfer should be enabled if the DMA address + * and length are 32 bit aligned. However, this leads to some + * strange behavior. Even 64 bit aligned addr/length fails. + * Until I've found a reason for this, 32 bit transfer is only + * used for full-block transfers (1kB). + * -jskov + */ +#if 0 + if((addr & 0x3fc) || length & 0x3ff || ((addr > 0x200000) && + (addr < 0xff0000))) + ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */ + else + ctrl_data |= CYBER_DMA_Z3; /* CHIP/Z3, do 32 bit DMA */ +#else + ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */ +#endif + dregs->ctrl_reg = ctrl_data; +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct cyber_dma_registers *dregs = + (struct cyber_dma_registers *) esp->dregs; + + cache_push(addr, length); + + addr |= 1; + dregs->dma_addr0 = (addr >> 24) & 0xff; + dregs->dma_addr1 = (addr >> 16) & 0xff; + dregs->dma_addr2 = (addr >> 8) & 0xff; + dregs->dma_addr3 = (addr ) & 0xff; + ctrl_data |= CYBER_DMA_WRITE; + + /* See comment above */ +#if 0 + if((addr & 0x3fc) || length & 0x3ff || ((addr > 0x200000) && + (addr < 0xff0000))) + ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */ + else + ctrl_data |= CYBER_DMA_Z3; /* CHIP/Z3, do 32 bit DMA */ +#else + ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */ +#endif + dregs->ctrl_reg = ctrl_data; +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(esp->irq); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(esp->irq); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + /* It's important to check the DMA IRQ bit in the correct way! */ + return ((esp_read(esp->eregs->esp_status) & ESP_STAT_INTR) && + ((((struct cyber_dma_registers *)(esp->dregs))->cond_reg) & + CYBER_DMA_HNDL_INTR)); +} + +static void dma_led_off(struct NCR_ESP *esp) +{ + ctrl_data &= ~CYBER_DMA_LED; + ((struct cyber_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data; +} + +static void dma_led_on(struct NCR_ESP *esp) +{ + ctrl_data |= CYBER_DMA_LED; + ((struct cyber_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data; +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + return ((amiga_custom.intenar) & IF_PORTS); +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if(write){ + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +#define HOSTS_C + +int cyber_esp_release(struct Scsi_Host *instance) +{ +#ifdef MODULE + unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; + + esp_deallocate((struct NCR_ESP *)instance->hostdata); + esp_release(); + release_mem_region(address, sizeof(struct ESP_regs)); + free_irq(IRQ_AMIGA_PORTS, esp_intr); +#endif + return 1; +} + + +static struct scsi_host_template driver_template = { + .proc_name = "esp-cyberstorm", + .proc_info = esp_proc_info, + .name = "CyberStorm SCSI", + .detect = cyber_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = cyber_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/cyberstormII.c b/trunk/drivers/scsi/cyberstormII.c new file mode 100644 index 000000000000..e336e853e66f --- /dev/null +++ b/trunk/drivers/scsi/cyberstormII.c @@ -0,0 +1,314 @@ +/* cyberstormII.c: Driver for CyberStorm SCSI Mk II + * + * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) + * + * This driver is based on cyberstorm.c + */ + +/* TODO: + * + * 1) Figure out how to make a cleaner merge with the sparc driver with regard + * to the caches and the Sparc MMU mapping. + * 2) Make as few routines required outside the generic driver. A lot of the + * routines in this file used to be inline! + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include + +#include + +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define CYBERII_ESP_ADDR 0x1ff03 +#define CYBERII_DMA_ADDR 0x1ff43 + + +/* The CyberStorm II DMA interface */ +struct cyberII_dma_registers { + volatile unsigned char cond_reg; /* DMA cond (ro) [0x000] */ +#define ctrl_reg cond_reg /* DMA control (wo) [0x000] */ + unsigned char dmapad4[0x3f]; + volatile unsigned char dma_addr0; /* DMA address (MSB) [0x040] */ + unsigned char dmapad1[3]; + volatile unsigned char dma_addr1; /* DMA address [0x044] */ + unsigned char dmapad2[3]; + volatile unsigned char dma_addr2; /* DMA address [0x048] */ + unsigned char dmapad3[3]; + volatile unsigned char dma_addr3; /* DMA address (LSB) [0x04c] */ +}; + +/* DMA control bits */ +#define CYBERII_DMA_LED 0x02 /* HD led control 1 = on */ + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static void dma_led_off(struct NCR_ESP *esp); +static void dma_led_on(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are transferred to the ESP chip + * via PIO. + */ + +/***************************************************************** Detection */ +int __init cyberII_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct zorro_dev *z = NULL; + unsigned long address; + struct ESP_regs *eregs; + + if ((z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERSTORM_MK_II, z))) { + unsigned long board = z->resource.start; + if (request_mem_region(board+CYBERII_ESP_ADDR, + sizeof(struct ESP_regs), "NCR53C9x")) { + /* Do some magic to figure out if the CyberStorm Mk II + * is equipped with a SCSI controller + */ + address = (unsigned long)ZTWO_VADDR(board); + eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR); + + esp = esp_allocate(tpnt, (void *)board + CYBERII_ESP_ADDR, 0); + + esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); + udelay(5); + if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)) { + esp_deallocate(esp); + scsi_unregister(esp->ehost); + release_mem_region(board+CYBERII_ESP_ADDR, + sizeof(struct ESP_regs)); + return 0; /* Bail out if address did not hold data */ + } + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = 0; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_led_on = &dma_led_on; + esp->dma_led_off = &dma_led_off; + esp->dma_poll = 0; + esp->dma_reset = 0; + + /* SCSI chip speed */ + esp->cfreq = 40000000; + + /* The DMA registers on the CyberStorm are mapped + * relative to the device (i.e. in the same Zorro + * I/O block). + */ + esp->dregs = (void *)(address + CYBERII_DMA_ADDR); + + /* ESP register base */ + esp->eregs = eregs; + + /* Set the command buffer */ + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); + + esp->irq = IRQ_AMIGA_PORTS; + request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, + "CyberStorm SCSI Mk II", esp->ehost); + + /* Figure out our scsi ID on the bus */ + esp->scsi_id = 7; + + /* We don't have a differential SCSI-bus. */ + esp->diff = 0; + + esp_initialize(esp); + + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + return esps_in_use; + } + } + return 0; +} + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Since the CyberStorm DMA is fully dedicated to the ESP chip, + * the number of bytes sent (to the ESP chip) equals the number + * of bytes in the FIFO - there is no buffering in the DMA controller. + * XXXX Do I read this right? It is from host to ESP, right? + */ + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + /* I don't think there's any limit on the CyberDMA. So we use what + * the ESP chip can handle (24 bit). + */ + unsigned long sz = sp->SCp.this_residual; + if(sz > 0x1000000) + sz = 0x1000000; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ + ESPLOG(("esp%d: dma -- cond_reg<%02x>\n", + esp->esp_id, ((struct cyberII_dma_registers *) + (esp->dregs))->cond_reg)); + ESPLOG(("intreq:<%04x>, intena:<%04x>\n", + amiga_custom.intreqr, amiga_custom.intenar)); +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct cyberII_dma_registers *dregs = + (struct cyberII_dma_registers *) esp->dregs; + + cache_clear(addr, length); + + addr &= ~(1); + dregs->dma_addr0 = (addr >> 24) & 0xff; + dregs->dma_addr1 = (addr >> 16) & 0xff; + dregs->dma_addr2 = (addr >> 8) & 0xff; + dregs->dma_addr3 = (addr ) & 0xff; +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct cyberII_dma_registers *dregs = + (struct cyberII_dma_registers *) esp->dregs; + + cache_push(addr, length); + + addr |= 1; + dregs->dma_addr0 = (addr >> 24) & 0xff; + dregs->dma_addr1 = (addr >> 16) & 0xff; + dregs->dma_addr2 = (addr >> 8) & 0xff; + dregs->dma_addr3 = (addr ) & 0xff; +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(esp->irq); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(esp->irq); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + /* It's important to check the DMA IRQ bit in the correct way! */ + return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR); +} + +static void dma_led_off(struct NCR_ESP *esp) +{ + ((struct cyberII_dma_registers *)(esp->dregs))->ctrl_reg &= ~CYBERII_DMA_LED; +} + +static void dma_led_on(struct NCR_ESP *esp) +{ + ((struct cyberII_dma_registers *)(esp->dregs))->ctrl_reg |= CYBERII_DMA_LED; +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + return ((amiga_custom.intenar) & IF_PORTS); +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if(write){ + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +#define HOSTS_C + +int cyberII_esp_release(struct Scsi_Host *instance) +{ +#ifdef MODULE + unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; + + esp_deallocate((struct NCR_ESP *)instance->hostdata); + esp_release(); + release_mem_region(address, sizeof(struct ESP_regs)); + free_irq(IRQ_AMIGA_PORTS, esp_intr); +#endif + return 1; +} + + +static struct scsi_host_template driver_template = { + .proc_name = "esp-cyberstormII", + .proc_info = esp_proc_info, + .name = "CyberStorm Mk II SCSI", + .detect = cyberII_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = cyberII_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/dc395x.c b/trunk/drivers/scsi/dc395x.c index e351db6c0077..22ef3716e786 100644 --- a/trunk/drivers/scsi/dc395x.c +++ b/trunk/drivers/scsi/dc395x.c @@ -4267,7 +4267,7 @@ static int __devinit adapter_sg_tables_alloc(struct AdapterCtlBlk *acb) const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN; int srb_idx = 0; unsigned i = 0; - struct SGentry *uninitialized_var(ptr); + struct SGentry *ptr; for (i = 0; i < DC395x_MAX_SRB_CNT; i++) acb->srb_array[i].segment_x = NULL; diff --git a/trunk/drivers/scsi/dec_esp.c b/trunk/drivers/scsi/dec_esp.c new file mode 100644 index 000000000000..d42ad663ffee --- /dev/null +++ b/trunk/drivers/scsi/dec_esp.c @@ -0,0 +1,687 @@ +/* + * dec_esp.c: Driver for SCSI chips on IOASIC based TURBOchannel DECstations + * and TURBOchannel PMAZ-A cards + * + * TURBOchannel changes by Harald Koerfgen + * PMAZ-A support by David Airlie + * + * based on jazz_esp.c: + * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * + * jazz_esp is based on David S. Miller's ESP driver and cyber_esp + * + * 20000819 - Small PMAZ-AA fixes by Florian Lohoff + * Be warned the PMAZ-AA works currently as a single card. + * Dont try to put multiple cards in one machine - They are + * both detected but it may crash under high load garbling your + * data. + * 20001005 - Initialization fixes for 2.4.0-test9 + * Florian Lohoff + * + * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define DEC_SCSI_SREG 0 +#define DEC_SCSI_DMAREG 0x40000 +#define DEC_SCSI_SRAM 0x80000 +#define DEC_SCSI_DIAG 0xC0000 + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static void dma_drain(struct NCR_ESP *esp); +static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length); +static void dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write); +static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp); +static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp); +static void dma_advance_sg(struct scsi_cmnd * sp); + +static void pmaz_dma_drain(struct NCR_ESP *esp); +static void pmaz_dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length); +static void pmaz_dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length); +static void pmaz_dma_ints_off(struct NCR_ESP *esp); +static void pmaz_dma_ints_on(struct NCR_ESP *esp); +static void pmaz_dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write); +static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp); + +#define TC_ESP_RAM_SIZE 0x20000 +#define ESP_TGT_DMA_SIZE ((TC_ESP_RAM_SIZE/7) & ~(sizeof(int)-1)) +#define ESP_NCMD 7 + +#define TC_ESP_DMAR_MASK 0x1ffff +#define TC_ESP_DMAR_WRITE 0x80000000 +#define TC_ESP_DMA_ADDR(x) ((unsigned)(x) & TC_ESP_DMAR_MASK) + +u32 esp_virt_buffer; +int scsi_current_length; + +volatile unsigned char cmd_buffer[16]; +volatile unsigned char pmaz_cmd_buffer[16]; + /* This is where all commands are put + * before they are trasfered to the ESP chip + * via PIO. + */ + +static irqreturn_t scsi_dma_merr_int(int, void *); +static irqreturn_t scsi_dma_err_int(int, void *); +static irqreturn_t scsi_dma_int(int, void *); + +static struct scsi_host_template dec_esp_template = { + .module = THIS_MODULE, + .name = "NCR53C94", + .info = esp_info, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .proc_info = esp_proc_info, + .proc_name = "dec_esp", + .can_queue = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING, +}; + +static struct NCR_ESP *dec_esp_platform; + +/***************************************************************** Detection */ +static int dec_esp_platform_probe(void) +{ + struct NCR_ESP *esp; + int err = 0; + + if (IOASIC) { + esp = esp_allocate(&dec_esp_template, NULL, 1); + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = &dma_drain; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_poll = 0; + esp->dma_reset = 0; + esp->dma_led_off = 0; + esp->dma_led_on = 0; + + /* virtual DMA functions */ + esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; + esp->dma_mmu_release_scsi_one = 0; + esp->dma_mmu_release_scsi_sgl = 0; + esp->dma_advance_sg = &dma_advance_sg; + + + /* SCSI chip speed */ + esp->cfreq = 25000000; + + esp->dregs = 0; + + /* ESP register base */ + esp->eregs = (void *)CKSEG1ADDR(dec_kn_slot_base + + IOASIC_SCSI); + + /* Set the command buffer */ + esp->esp_command = (volatile unsigned char *) cmd_buffer; + + /* get virtual dma address for command buffer */ + esp->esp_command_dvma = virt_to_phys(cmd_buffer); + + esp->irq = dec_interrupt[DEC_IRQ_ASC]; + + esp->scsi_id = 7; + + /* Check for differential SCSI-bus */ + esp->diff = 0; + + err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, + "ncr53c94", esp->ehost); + if (err) + goto err_alloc; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_MERR], + scsi_dma_merr_int, IRQF_DISABLED, + "ncr53c94 error", esp->ehost); + if (err) + goto err_irq; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_ERR], + scsi_dma_err_int, IRQF_DISABLED, + "ncr53c94 overrun", esp->ehost); + if (err) + goto err_irq_merr; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], scsi_dma_int, + IRQF_DISABLED, "ncr53c94 dma", esp->ehost); + if (err) + goto err_irq_err; + + esp_initialize(esp); + + err = scsi_add_host(esp->ehost, NULL); + if (err) { + printk(KERN_ERR "ESP: Unable to register adapter\n"); + goto err_irq_dma; + } + + scsi_scan_host(esp->ehost); + + dec_esp_platform = esp; + } + + return 0; + +err_irq_dma: + free_irq(dec_interrupt[DEC_IRQ_ASC_DMA], esp->ehost); +err_irq_err: + free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], esp->ehost); +err_irq_merr: + free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], esp->ehost); +err_irq: + free_irq(esp->irq, esp->ehost); +err_alloc: + esp_deallocate(esp); + scsi_host_put(esp->ehost); + return err; +} + +static int __init dec_esp_probe(struct device *dev) +{ + struct NCR_ESP *esp; + resource_size_t start, len; + int err; + + esp = esp_allocate(&dec_esp_template, NULL, 1); + + dev_set_drvdata(dev, esp); + + start = to_tc_dev(dev)->resource.start; + len = to_tc_dev(dev)->resource.end - start + 1; + + if (!request_mem_region(start, len, dev->bus_id)) { + printk(KERN_ERR "%s: Unable to reserve MMIO resource\n", + dev->bus_id); + err = -EBUSY; + goto err_alloc; + } + + /* Store base addr into esp struct. */ + esp->slot = start; + + esp->dregs = 0; + esp->eregs = (void *)CKSEG1ADDR(start + DEC_SCSI_SREG); + esp->do_pio_cmds = 1; + + /* Set the command buffer. */ + esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer; + + /* Get virtual dma address for command buffer. */ + esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer); + + esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus); + + esp->irq = to_tc_dev(dev)->interrupt; + + /* Required functions. */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &pmaz_dma_init_read; + esp->dma_init_write = &pmaz_dma_init_write; + esp->dma_ints_off = &pmaz_dma_ints_off; + esp->dma_ints_on = &pmaz_dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &pmaz_dma_setup; + + /* Optional functions. */ + esp->dma_barrier = 0; + esp->dma_drain = &pmaz_dma_drain; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_poll = 0; + esp->dma_reset = 0; + esp->dma_led_off = 0; + esp->dma_led_on = 0; + + esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = 0; + esp->dma_mmu_release_scsi_one = 0; + esp->dma_mmu_release_scsi_sgl = 0; + esp->dma_advance_sg = 0; + + err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, "PMAZ_AA", + esp->ehost); + if (err) { + printk(KERN_ERR "%s: Unable to get IRQ %d\n", + dev->bus_id, esp->irq); + goto err_resource; + } + + esp->scsi_id = 7; + esp->diff = 0; + esp_initialize(esp); + + err = scsi_add_host(esp->ehost, dev); + if (err) { + printk(KERN_ERR "%s: Unable to register adapter\n", + dev->bus_id); + goto err_irq; + } + + scsi_scan_host(esp->ehost); + + return 0; + +err_irq: + free_irq(esp->irq, esp->ehost); + +err_resource: + release_mem_region(start, len); + +err_alloc: + esp_deallocate(esp); + scsi_host_put(esp->ehost); + return err; +} + +static void __exit dec_esp_platform_remove(void) +{ + struct NCR_ESP *esp = dec_esp_platform; + + free_irq(esp->irq, esp->ehost); + esp_deallocate(esp); + scsi_host_put(esp->ehost); + dec_esp_platform = NULL; +} + +static void __exit dec_esp_remove(struct device *dev) +{ + struct NCR_ESP *esp = dev_get_drvdata(dev); + + free_irq(esp->irq, esp->ehost); + esp_deallocate(esp); + scsi_host_put(esp->ehost); +} + + +/************************************************************* DMA Functions */ +static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id) +{ + printk("Got unexpected SCSI DMA Interrupt! < "); + printk("SCSI_DMA_MEMRDERR "); + printk(">\n"); + + return IRQ_HANDLED; +} + +static irqreturn_t scsi_dma_err_int(int irq, void *dev_id) +{ + /* empty */ + + return IRQ_HANDLED; +} + +static irqreturn_t scsi_dma_int(int irq, void *dev_id) +{ + u32 scsi_next_ptr; + + scsi_next_ptr = ioasic_read(IO_REG_SCSI_DMA_P); + + /* next page */ + scsi_next_ptr = (((scsi_next_ptr >> 3) + PAGE_SIZE) & PAGE_MASK) << 3; + ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr); + fast_iob(); + + return IRQ_HANDLED; +} + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + return fifo_count; +} + +static void dma_drain(struct NCR_ESP *esp) +{ + u32 nw, data0, data1, scsi_data_ptr; + u16 *p; + + nw = ioasic_read(IO_REG_SCSI_SCR); + + /* + * Is there something in the dma buffers left? + */ + if (nw) { + scsi_data_ptr = ioasic_read(IO_REG_SCSI_DMA_P) >> 3; + p = phys_to_virt(scsi_data_ptr); + switch (nw) { + case 1: + data0 = ioasic_read(IO_REG_SCSI_SDR0); + p[0] = data0 & 0xffff; + break; + case 2: + data0 = ioasic_read(IO_REG_SCSI_SDR0); + p[0] = data0 & 0xffff; + p[1] = (data0 >> 16) & 0xffff; + break; + case 3: + data0 = ioasic_read(IO_REG_SCSI_SDR0); + data1 = ioasic_read(IO_REG_SCSI_SDR1); + p[0] = data0 & 0xffff; + p[1] = (data0 >> 16) & 0xffff; + p[2] = data1 & 0xffff; + break; + default: + printk("Strange: %d words in dma buffer left\n", nw); + break; + } + } +} + +static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd * sp) +{ + return sp->SCp.this_residual; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ +} + +static void dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length) +{ + u32 scsi_next_ptr, ioasic_ssr; + unsigned long flags; + + if (vaddress & 3) + panic("dec_esp.c: unable to handle partial word transfers, yet..."); + + dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length); + + spin_lock_irqsave(&ioasic_ssr_lock, flags); + + fast_mb(); + ioasic_ssr = ioasic_read(IO_REG_SSR); + + ioasic_ssr &= ~IO_SSR_SCSI_DMA_EN; + ioasic_write(IO_REG_SSR, ioasic_ssr); + + fast_wmb(); + ioasic_write(IO_REG_SCSI_SCR, 0); + ioasic_write(IO_REG_SCSI_DMA_P, vaddress << 3); + + /* prepare for next page */ + scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; + ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr); + + ioasic_ssr |= (IO_SSR_SCSI_DMA_DIR | IO_SSR_SCSI_DMA_EN); + fast_wmb(); + ioasic_write(IO_REG_SSR, ioasic_ssr); + + fast_iob(); + spin_unlock_irqrestore(&ioasic_ssr_lock, flags); +} + +static void dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length) +{ + u32 scsi_next_ptr, ioasic_ssr; + unsigned long flags; + + if (vaddress & 3) + panic("dec_esp.c: unable to handle partial word transfers, yet..."); + + dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length); + + spin_lock_irqsave(&ioasic_ssr_lock, flags); + + fast_mb(); + ioasic_ssr = ioasic_read(IO_REG_SSR); + + ioasic_ssr &= ~(IO_SSR_SCSI_DMA_DIR | IO_SSR_SCSI_DMA_EN); + ioasic_write(IO_REG_SSR, ioasic_ssr); + + fast_wmb(); + ioasic_write(IO_REG_SCSI_SCR, 0); + ioasic_write(IO_REG_SCSI_DMA_P, vaddress << 3); + + /* prepare for next page */ + scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; + ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr); + + ioasic_ssr |= IO_SSR_SCSI_DMA_EN; + fast_wmb(); + ioasic_write(IO_REG_SSR, ioasic_ssr); + + fast_iob(); + spin_unlock_irqrestore(&ioasic_ssr_lock, flags); +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + return (esp->eregs->esp_status & ESP_STAT_INTR); +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + /* + * FIXME: what's this good for? + */ + return 1; +} + +static void dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write) +{ + /* + * DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if (write) + dma_init_read(esp, addr, count); + else + dma_init_write(esp, addr, count); +} + +static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp) +{ + sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer); +} + +static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp) +{ + int sz = sp->SCp.buffers_residual; + struct scatterlist *sg = sp->SCp.buffer; + + while (sz >= 0) { + sg[sz].dma_address = page_to_phys(sg[sz].page) + sg[sz].offset; + sz--; + } + sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address); +} + +static void dma_advance_sg(struct scsi_cmnd * sp) +{ + sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address); +} + +static void pmaz_dma_drain(struct NCR_ESP *esp) +{ + memcpy(phys_to_virt(esp_virt_buffer), + (void *)CKSEG1ADDR(esp->slot + DEC_SCSI_SRAM + + ESP_TGT_DMA_SIZE), + scsi_current_length); +} + +static void pmaz_dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length) +{ + volatile u32 *dmareg = + (volatile u32 *)CKSEG1ADDR(esp->slot + DEC_SCSI_DMAREG); + + if (length > ESP_TGT_DMA_SIZE) + length = ESP_TGT_DMA_SIZE; + + *dmareg = TC_ESP_DMA_ADDR(ESP_TGT_DMA_SIZE); + + iob(); + + esp_virt_buffer = vaddress; + scsi_current_length = length; +} + +static void pmaz_dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length) +{ + volatile u32 *dmareg = + (volatile u32 *)CKSEG1ADDR(esp->slot + DEC_SCSI_DMAREG); + + memcpy((void *)CKSEG1ADDR(esp->slot + DEC_SCSI_SRAM + + ESP_TGT_DMA_SIZE), + phys_to_virt(vaddress), length); + + wmb(); + *dmareg = TC_ESP_DMAR_WRITE | TC_ESP_DMA_ADDR(ESP_TGT_DMA_SIZE); + + iob(); +} + +static void pmaz_dma_ints_off(struct NCR_ESP *esp) +{ +} + +static void pmaz_dma_ints_on(struct NCR_ESP *esp) +{ +} + +static void pmaz_dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write) +{ + /* + * DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if (write) + pmaz_dma_init_read(esp, addr, count); + else + pmaz_dma_init_write(esp, addr, count); +} + +static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp) +{ + sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer); +} + + +#ifdef CONFIG_TC +static int __init dec_esp_tc_probe(struct device *dev); +static int __exit dec_esp_tc_remove(struct device *dev); + +static const struct tc_device_id dec_esp_tc_table[] = { + { "DEC ", "PMAZ-AA " }, + { } +}; +MODULE_DEVICE_TABLE(tc, dec_esp_tc_table); + +static struct tc_driver dec_esp_tc_driver = { + .id_table = dec_esp_tc_table, + .driver = { + .name = "dec_esp", + .bus = &tc_bus_type, + .probe = dec_esp_tc_probe, + .remove = __exit_p(dec_esp_tc_remove), + }, +}; + +static int __init dec_esp_tc_probe(struct device *dev) +{ + int status = dec_esp_probe(dev); + if (!status) + get_device(dev); + return status; +} + +static int __exit dec_esp_tc_remove(struct device *dev) +{ + put_device(dev); + dec_esp_remove(dev); + return 0; +} +#endif + +static int __init dec_esp_init(void) +{ + int status; + + status = tc_register_driver(&dec_esp_tc_driver); + if (!status) + dec_esp_platform_probe(); + + if (nesps) { + pr_info("ESP: Total of %d ESP hosts found, " + "%d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + } + + return status; +} + +static void __exit dec_esp_exit(void) +{ + dec_esp_platform_remove(); + tc_unregister_driver(&dec_esp_tc_driver); +} + + +module_init(dec_esp_init); +module_exit(dec_esp_exit); diff --git a/trunk/drivers/scsi/fastlane.c b/trunk/drivers/scsi/fastlane.c new file mode 100644 index 000000000000..4266a2139b5f --- /dev/null +++ b/trunk/drivers/scsi/fastlane.c @@ -0,0 +1,421 @@ +/* fastlane.c: Driver for Phase5's Fastlane SCSI Controller. + * + * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) + * + * This driver is based on the CyberStorm driver, hence the occasional + * reference to CyberStorm. + * + * Betatesting & crucial adjustments by + * Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz) + * + */ + +/* TODO: + * + * o According to the doc from laire, it is required to reset the DMA when + * the transfer is done. ATM we reset DMA just before every new + * dma_init_(read|write). + * + * 1) Figure out how to make a cleaner merge with the sparc driver with regard + * to the caches and the Sparc MMU mapping. + * 2) Make as few routines required outside the generic driver. A lot of the + * routines in this file used to be inline! + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include + +#include +#include + +#include + +/* Such day has just come... */ +#if 0 +/* Let this defined unless you really need to enable DMA IRQ one day */ +#define NODMAIRQ +#endif + +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define FASTLANE_ESP_ADDR 0x1000001 +#define FASTLANE_DMA_ADDR 0x1000041 + + +/* The Fastlane DMA interface */ +struct fastlane_dma_registers { + volatile unsigned char cond_reg; /* DMA status (ro) [0x0000] */ +#define ctrl_reg cond_reg /* DMA control (wo) [0x0000] */ + unsigned char dmapad1[0x3f]; + volatile unsigned char clear_strobe; /* DMA clear (wo) [0x0040] */ +}; + + +/* DMA status bits */ +#define FASTLANE_DMA_MINT 0x80 +#define FASTLANE_DMA_IACT 0x40 +#define FASTLANE_DMA_CREQ 0x20 + +/* DMA control bits */ +#define FASTLANE_DMA_FCODE 0xa0 +#define FASTLANE_DMA_MASK 0xf3 +#define FASTLANE_DMA_LED 0x10 /* HD led control 1 = on */ +#define FASTLANE_DMA_WRITE 0x08 /* 1 = write */ +#define FASTLANE_DMA_ENABLE 0x04 /* Enable DMA */ +#define FASTLANE_DMA_EDI 0x02 /* Enable DMA IRQ ? */ +#define FASTLANE_DMA_ESI 0x01 /* Enable SCSI IRQ */ + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddr, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static void dma_irq_exit(struct NCR_ESP *esp); +static void dma_led_off(struct NCR_ESP *esp); +static void dma_led_on(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); + +static unsigned char ctrl_data = 0; /* Keep backup of the stuff written + * to ctrl_reg. Always write a copy + * to this register when writing to + * the hardware register! + */ + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are transferred to the ESP chip + * via PIO. + */ + +static inline void dma_clear(struct NCR_ESP *esp) +{ + struct fastlane_dma_registers *dregs = + (struct fastlane_dma_registers *) (esp->dregs); + unsigned long *t; + + ctrl_data = (ctrl_data & FASTLANE_DMA_MASK); + dregs->ctrl_reg = ctrl_data; + + t = (unsigned long *)(esp->edev); + + dregs->clear_strobe = 0; + *t = 0 ; +} + +/***************************************************************** Detection */ +int __init fastlane_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct zorro_dev *z = NULL; + unsigned long address; + + if ((z = zorro_find_device(ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060, z))) { + unsigned long board = z->resource.start; + if (request_mem_region(board+FASTLANE_ESP_ADDR, + sizeof(struct ESP_regs), "NCR53C9x")) { + /* Check if this is really a fastlane controller. The problem + * is that also the cyberstorm and blizzard controllers use + * this ID value. Fortunately only Fastlane maps in Z3 space + */ + if (board < 0x1000000) { + goto err_release; + } + esp = esp_allocate(tpnt, (void *)board + FASTLANE_ESP_ADDR, 0); + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = 0; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = &dma_irq_exit; + esp->dma_led_on = &dma_led_on; + esp->dma_led_off = &dma_led_off; + esp->dma_poll = 0; + esp->dma_reset = 0; + + /* Initialize the portBits (enable IRQs) */ + ctrl_data = (FASTLANE_DMA_FCODE | +#ifndef NODMAIRQ + FASTLANE_DMA_EDI | +#endif + FASTLANE_DMA_ESI); + + + /* SCSI chip clock */ + esp->cfreq = 40000000; + + + /* Map the physical address space into virtual kernel space */ + address = (unsigned long) + z_ioremap(board, z->resource.end-board+1); + + if(!address){ + printk("Could not remap Fastlane controller memory!"); + goto err_unregister; + } + + + /* The DMA registers on the Fastlane are mapped + * relative to the device (i.e. in the same Zorro + * I/O block). + */ + esp->dregs = (void *)(address + FASTLANE_DMA_ADDR); + + /* ESP register base */ + esp->eregs = (struct ESP_regs *)(address + FASTLANE_ESP_ADDR); + + /* Board base */ + esp->edev = (void *) address; + + /* Set the command buffer */ + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); + + esp->irq = IRQ_AMIGA_PORTS; + esp->slot = board+FASTLANE_ESP_ADDR; + if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, + "Fastlane SCSI", esp->ehost)) { + printk(KERN_WARNING "Fastlane: Could not get IRQ%d, aborting.\n", IRQ_AMIGA_PORTS); + goto err_unmap; + } + + /* Controller ID */ + esp->scsi_id = 7; + + /* We don't have a differential SCSI-bus. */ + esp->diff = 0; + + dma_clear(esp); + esp_initialize(esp); + + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + return esps_in_use; + } + } + return 0; + + err_unmap: + z_iounmap((void *)address); + err_unregister: + scsi_unregister (esp->ehost); + err_release: + release_mem_region(z->resource.start+FASTLANE_ESP_ADDR, + sizeof(struct ESP_regs)); + return 0; +} + + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Since the Fastlane DMA is fully dedicated to the ESP chip, + * the number of bytes sent (to the ESP chip) equals the number + * of bytes in the FIFO - there is no buffering in the DMA controller. + * XXXX Do I read this right? It is from host to ESP, right? + */ + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + unsigned long sz = sp->SCp.this_residual; + if(sz > 0xfffc) + sz = 0xfffc; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ + ESPLOG(("esp%d: dma -- cond_reg<%02x>\n", + esp->esp_id, ((struct fastlane_dma_registers *) + (esp->dregs))->cond_reg)); + ESPLOG(("intreq:<%04x>, intena:<%04x>\n", + amiga_custom.intreqr, amiga_custom.intenar)); +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct fastlane_dma_registers *dregs = + (struct fastlane_dma_registers *) (esp->dregs); + unsigned long *t; + + cache_clear(addr, length); + + dma_clear(esp); + + t = (unsigned long *)((addr & 0x00ffffff) + esp->edev); + + dregs->clear_strobe = 0; + *t = addr; + + ctrl_data = (ctrl_data & FASTLANE_DMA_MASK) | FASTLANE_DMA_ENABLE; + dregs->ctrl_reg = ctrl_data; +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct fastlane_dma_registers *dregs = + (struct fastlane_dma_registers *) (esp->dregs); + unsigned long *t; + + cache_push(addr, length); + + dma_clear(esp); + + t = (unsigned long *)((addr & 0x00ffffff) + (esp->edev)); + + dregs->clear_strobe = 0; + *t = addr; + + ctrl_data = ((ctrl_data & FASTLANE_DMA_MASK) | + FASTLANE_DMA_ENABLE | + FASTLANE_DMA_WRITE); + dregs->ctrl_reg = ctrl_data; +} + + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(esp->irq); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(esp->irq); +} + +static void dma_irq_exit(struct NCR_ESP *esp) +{ + struct fastlane_dma_registers *dregs = + (struct fastlane_dma_registers *) (esp->dregs); + + dregs->ctrl_reg = ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI); +#ifdef __mc68000__ + nop(); +#endif + dregs->ctrl_reg = ctrl_data; +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + struct fastlane_dma_registers *dregs = + (struct fastlane_dma_registers *) (esp->dregs); + unsigned char dma_status; + + dma_status = dregs->cond_reg; + + if(dma_status & FASTLANE_DMA_IACT) + return 0; /* not our IRQ */ + + /* Return non-zero if ESP requested IRQ */ + return ( +#ifndef NODMAIRQ + (dma_status & FASTLANE_DMA_CREQ) && +#endif + (!(dma_status & FASTLANE_DMA_MINT)) && + (esp_read(((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR)); +} + +static void dma_led_off(struct NCR_ESP *esp) +{ + ctrl_data &= ~FASTLANE_DMA_LED; + ((struct fastlane_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data; +} + +static void dma_led_on(struct NCR_ESP *esp) +{ + ctrl_data |= FASTLANE_DMA_LED; + ((struct fastlane_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data; +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + return ((amiga_custom.intenar) & IF_PORTS); +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if(write){ + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +#define HOSTS_C + +int fastlane_esp_release(struct Scsi_Host *instance) +{ +#ifdef MODULE + unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; + esp_deallocate((struct NCR_ESP *)instance->hostdata); + esp_release(); + release_mem_region(address, sizeof(struct ESP_regs)); + free_irq(IRQ_AMIGA_PORTS, esp_intr); +#endif + return 1; +} + + +static struct scsi_host_template driver_template = { + .proc_name = "esp-fastlane", + .proc_info = esp_proc_info, + .name = "Fastlane SCSI", + .detect = fastlane_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = fastlane_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/iscsi_tcp.c b/trunk/drivers/scsi/iscsi_tcp.c index 8a178674cb18..b6f99dfbb038 100644 --- a/trunk/drivers/scsi/iscsi_tcp.c +++ b/trunk/drivers/scsi/iscsi_tcp.c @@ -629,9 +629,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) int rc; if (tcp_conn->in.datalen) { - iscsi_conn_printk(KERN_ERR, conn, - "invalid R2t with datalen %d\n", - tcp_conn->in.datalen); + printk(KERN_ERR "iscsi_tcp: invalid R2t with datalen %d\n", + tcp_conn->in.datalen); return ISCSI_ERR_DATALEN; } @@ -645,9 +644,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) { - iscsi_conn_printk(KERN_INFO, conn, - "dropping R2T itt %d in recovery.\n", - ctask->itt); + printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " + "recovery...\n", ctask->itt); return 0; } @@ -657,8 +655,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->exp_statsn = rhdr->statsn; r2t->data_length = be32_to_cpu(rhdr->data_length); if (r2t->data_length == 0) { - iscsi_conn_printk(KERN_ERR, conn, - "invalid R2T with zero data len\n"); + printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n"); __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); return ISCSI_ERR_DATALEN; @@ -671,10 +668,9 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_offset = be32_to_cpu(rhdr->data_offset); if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) { - iscsi_conn_printk(KERN_ERR, conn, - "invalid R2T with data len %u at offset %u " - "and total length %d\n", r2t->data_length, - r2t->data_offset, scsi_bufflen(ctask->sc)); + printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at " + "offset %u and total length %d\n", r2t->data_length, + r2t->data_offset, scsi_bufflen(ctask->sc)); __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); return ISCSI_ERR_DATALEN; @@ -740,9 +736,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) /* verify PDU length */ tcp_conn->in.datalen = ntoh24(hdr->dlength); if (tcp_conn->in.datalen > conn->max_recv_dlength) { - iscsi_conn_printk(KERN_ERR, conn, - "iscsi_tcp: datalen %d > %d\n", - tcp_conn->in.datalen, conn->max_recv_dlength); + printk(KERN_ERR "iscsi_tcp: datalen %d > %d\n", + tcp_conn->in.datalen, conn->max_recv_dlength); return ISCSI_ERR_DATALEN; } @@ -824,12 +819,10 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) * For now we fail until we find a vendor that needs it */ if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) { - iscsi_conn_printk(KERN_ERR, conn, - "iscsi_tcp: received buffer of " - "len %u but conn buffer is only %u " - "(opcode %0x)\n", - tcp_conn->in.datalen, - ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); + printk(KERN_ERR "iscsi_tcp: received buffer of len %u " + "but conn buffer is only %u (opcode %0x)\n", + tcp_conn->in.datalen, + ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); rc = ISCSI_ERR_PROTO; break; } @@ -1503,25 +1496,30 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); tcp_conn->tx_hash.flags = 0; - if (IS_ERR(tcp_conn->tx_hash.tfm)) + if (IS_ERR(tcp_conn->tx_hash.tfm)) { + printk(KERN_ERR "Could not create connection due to crc32c " + "loading error %ld. Make sure the crc32c module is " + "built as a module or into the kernel\n", + PTR_ERR(tcp_conn->tx_hash.tfm)); goto free_tcp_conn; + } tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); tcp_conn->rx_hash.flags = 0; - if (IS_ERR(tcp_conn->rx_hash.tfm)) + if (IS_ERR(tcp_conn->rx_hash.tfm)) { + printk(KERN_ERR "Could not create connection due to crc32c " + "loading error %ld. Make sure the crc32c module is " + "built as a module or into the kernel\n", + PTR_ERR(tcp_conn->rx_hash.tfm)); goto free_tx_tfm; + } return cls_conn; free_tx_tfm: crypto_free_hash(tcp_conn->tx_hash.tfm); free_tcp_conn: - iscsi_conn_printk(KERN_ERR, conn, - "Could not create connection due to crc32c " - "loading error. Make sure the crc32c " - "module is built as a module or into the " - "kernel\n"); kfree(tcp_conn); tcp_conn_alloc_fail: iscsi_conn_teardown(cls_conn); @@ -1629,8 +1627,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, /* lookup for existing socket */ sock = sockfd_lookup((int)transport_eph, &err); if (!sock) { - iscsi_conn_printk(KERN_ERR, conn, - "sockfd_lookup failed %d\n", err); + printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err); return -EEXIST; } /* diff --git a/trunk/drivers/scsi/libiscsi.c b/trunk/drivers/scsi/libiscsi.c index 59f8445eab0d..553168ae44f1 100644 --- a/trunk/drivers/scsi/libiscsi.c +++ b/trunk/drivers/scsi/libiscsi.c @@ -160,7 +160,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) hdr->opcode = ISCSI_OP_SCSI_CMD; hdr->flags = ISCSI_ATTR_SIMPLE; int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); - hdr->itt = build_itt(ctask->itt, session->age); + hdr->itt = build_itt(ctask->itt, conn->id, session->age); hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); hdr->cmdsn = cpu_to_be32(session->cmdsn); session->cmdsn++; @@ -416,9 +416,8 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (datalen < 2) { invalid_datalen: - iscsi_conn_printk(KERN_ERR, conn, - "Got CHECK_CONDITION but invalid data " - "buffer size of %d\n", datalen); + printk(KERN_ERR "iscsi: Got CHECK_CONDITION but " + "invalid data buffer size of %d\n", datalen); sc->result = DID_BAD_TARGET << 16; goto out; } @@ -495,7 +494,7 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); if (!mtask) { - iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n"); + printk(KERN_ERR "Could not send nopout\n"); return; } @@ -523,10 +522,9 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); itt = get_itt(rejected_pdu.itt); - iscsi_conn_printk(KERN_ERR, conn, - "itt 0x%x had pdu (op 0x%x) rejected " - "due to DataDigest error.\n", itt, - rejected_pdu.opcode); + printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected " + "due to DataDigest error.\n", itt, + rejected_pdu.opcode); } } return 0; @@ -543,8 +541,8 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, * queuecommand or send generic. session lock must be held and verify * itt must have been called. */ -static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, - char *data, int datalen) +int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + char *data, int datalen) { struct iscsi_session *session = conn->session; int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; @@ -674,6 +672,7 @@ static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, return rc; } +EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, char *data, int datalen) @@ -698,13 +697,18 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (hdr->itt != RESERVED_ITT) { if (((__force u32)hdr->itt & ISCSI_AGE_MASK) != (session->age << ISCSI_AGE_SHIFT)) { - iscsi_conn_printk(KERN_ERR, conn, - "received itt %x expected session " - "age (%x)\n", (__force u32)hdr->itt, - session->age & ISCSI_AGE_MASK); + printk(KERN_ERR "iscsi: received itt %x expected " + "session age (%x)\n", (__force u32)hdr->itt, + session->age & ISCSI_AGE_MASK); return ISCSI_ERR_BAD_ITT; } + if (((__force u32)hdr->itt & ISCSI_CID_MASK) != + (conn->id << ISCSI_CID_SHIFT)) { + printk(KERN_ERR "iscsi: received itt %x, expected " + "CID (%x)\n", (__force u32)hdr->itt, conn->id); + return ISCSI_ERR_BAD_ITT; + } itt = get_itt(hdr->itt); } else itt = ~0U; @@ -713,17 +717,16 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, ctask = session->cmds[itt]; if (!ctask->sc) { - iscsi_conn_printk(KERN_INFO, conn, "dropping ctask " - "with itt 0x%x\n", ctask->itt); + printk(KERN_INFO "iscsi: dropping ctask with " + "itt 0x%x\n", ctask->itt); /* force drop */ return ISCSI_ERR_NO_SCSI_CMD; } if (ctask->sc->SCp.phase != session->age) { - iscsi_conn_printk(KERN_ERR, conn, - "iscsi: ctask's session age %d, " - "expected %d\n", ctask->sc->SCp.phase, - session->age); + printk(KERN_ERR "iscsi: ctask's session age %d, " + "expected %d\n", ctask->sc->SCp.phase, + session->age); return ISCSI_ERR_SESSION_FAILED; } } @@ -768,7 +771,7 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn, */ nop->cmdsn = cpu_to_be32(session->cmdsn); if (hdr->itt != RESERVED_ITT) { - hdr->itt = build_itt(mtask->itt, session->age); + hdr->itt = build_itt(mtask->itt, conn->id, session->age); /* * TODO: We always use immediate, so we never hit this. * If we start to send tmfs or nops as non-immediate then @@ -994,7 +997,6 @@ enum { FAILURE_SESSION_IN_RECOVERY, FAILURE_SESSION_RECOVERY_TIMEOUT, FAILURE_SESSION_LOGGING_OUT, - FAILURE_SESSION_NOT_READY, }; int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) @@ -1015,12 +1017,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) session = iscsi_hostdata(host->hostdata); spin_lock(&session->lock); - reason = iscsi_session_chkready(session_to_cls(session)); - if (reason) { - sc->result = reason; - goto fault; - } - /* * ISCSI_STATE_FAILED is a temp. state. The recovery * code will decide what is best to do with command queued @@ -1037,23 +1033,18 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) switch (session->state) { case ISCSI_STATE_IN_RECOVERY: reason = FAILURE_SESSION_IN_RECOVERY; - sc->result = DID_IMM_RETRY << 16; - break; + goto reject; case ISCSI_STATE_LOGGING_OUT: reason = FAILURE_SESSION_LOGGING_OUT; - sc->result = DID_IMM_RETRY << 16; - break; + goto reject; case ISCSI_STATE_RECOVERY_FAILED: reason = FAILURE_SESSION_RECOVERY_TIMEOUT; - sc->result = DID_NO_CONNECT << 16; break; case ISCSI_STATE_TERMINATE: reason = FAILURE_SESSION_TERMINATE; - sc->result = DID_NO_CONNECT << 16; break; default: reason = FAILURE_SESSION_FREED; - sc->result = DID_NO_CONNECT << 16; } goto fault; } @@ -1061,7 +1052,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) conn = session->leadconn; if (!conn) { reason = FAILURE_SESSION_FREED; - sc->result = DID_NO_CONNECT << 16; goto fault; } @@ -1101,7 +1091,9 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) fault: spin_unlock(&session->lock); - debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); + printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n", + sc->cmnd[0], reason); + sc->result = (DID_NO_CONNECT << 16); scsi_set_resid(sc, scsi_bufflen(sc)); sc->scsi_done(sc); spin_lock(host->host_lock); @@ -1168,8 +1160,7 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc) mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_LOGGED_IN) - iscsi_session_printk(KERN_INFO, session, - "host reset succeeded\n"); + printk(KERN_INFO "iscsi: host reset succeeded\n"); else goto failed; spin_unlock_bh(&session->lock); @@ -1248,8 +1239,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, * Fail commands. session lock held and recv side suspended and xmit * thread flushed */ -static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, - int error) +static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) { struct iscsi_cmd_task *ctask, *tmp; @@ -1261,7 +1251,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, if (lun == ctask->sc->device->lun || lun == -1) { debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, ctask->itt); - fail_command(conn, ctask, error << 16); + fail_command(conn, ctask, DID_BUS_BUSY << 16); } } @@ -1269,7 +1259,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, if (lun == ctask->sc->device->lun || lun == -1) { debug_scsi("failing requeued sc %p itt 0x%x\n", ctask->sc, ctask->itt); - fail_command(conn, ctask, error << 16); + fail_command(conn, ctask, DID_BUS_BUSY << 16); } } @@ -1367,10 +1357,10 @@ static void iscsi_check_transport_timeouts(unsigned long data) last_recv = conn->last_recv; if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ), jiffies)) { - iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs " - "expired, last rx %lu, last ping %lu, " - "now %lu\n", conn->ping_timeout, last_recv, - conn->last_ping, jiffies); + printk(KERN_ERR "ping timeout of %d secs expired, " + "last rx %lu, last ping %lu, now %lu\n", + conn->ping_timeout, last_recv, + conn->last_ping, jiffies); spin_unlock(&session->lock); iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return; @@ -1383,11 +1373,14 @@ static void iscsi_check_transport_timeouts(unsigned long data) iscsi_send_nopout(conn, NULL); } next_timeout = last_recv + timeout + (conn->ping_timeout * HZ); - } else + } else { next_timeout = last_recv + timeout; + } - debug_scsi("Setting next tmo %lu\n", next_timeout); - mod_timer(&conn->transport_timer, next_timeout); + if (next_timeout) { + debug_scsi("Setting next tmo %lu\n", next_timeout); + mod_timer(&conn->transport_timer, next_timeout); + } done: spin_unlock(&session->lock); } @@ -1580,7 +1573,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) /* need to grab the recv lock then session lock */ write_lock_bh(conn->recv_lock); spin_lock(&session->lock); - fail_all_commands(conn, sc->device->lun, DID_ERROR); + fail_all_commands(conn, sc->device->lun); conn->tmf_state = TMF_INITIAL; spin_unlock(&session->lock); write_unlock_bh(conn->recv_lock); @@ -1951,10 +1944,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) } spin_unlock_irqrestore(session->host->host_lock, flags); msleep_interruptible(500); - iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): " - "host_busy %d host_failed %d\n", - session->host->host_busy, - session->host->host_failed); + printk(KERN_INFO "iscsi: scsi conn_destroy(): host_busy %d " + "host_failed %d\n", session->host->host_busy, + session->host->host_failed); /* * force eh_abort() to unblock */ @@ -1983,28 +1975,27 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) struct iscsi_session *session = conn->session; if (!session) { - iscsi_conn_printk(KERN_ERR, conn, - "can't start unbound connection\n"); + printk(KERN_ERR "iscsi: can't start unbound connection\n"); return -EPERM; } if ((session->imm_data_en || !session->initial_r2t_en) && session->first_burst > session->max_burst) { - iscsi_conn_printk(KERN_INFO, conn, "invalid burst lengths: " - "first_burst %d max_burst %d\n", - session->first_burst, session->max_burst); + printk("iscsi: invalid burst lengths: " + "first_burst %d max_burst %d\n", + session->first_burst, session->max_burst); return -EINVAL; } if (conn->ping_timeout && !conn->recv_timeout) { - iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of " - "zero. Using 5 seconds\n."); + printk(KERN_ERR "iscsi: invalid recv timeout of zero " + "Using 5 seconds\n."); conn->recv_timeout = 5; } if (conn->recv_timeout && !conn->ping_timeout) { - iscsi_conn_printk(KERN_ERR, conn, "invalid ping timeout of " - "zero. Using 5 seconds.\n"); + printk(KERN_ERR "iscsi: invalid ping timeout of zero " + "Using 5 seconds.\n"); conn->ping_timeout = 5; } @@ -2028,9 +2019,11 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) conn->stop_stage = 0; conn->tmf_state = TMF_INITIAL; session->age++; - if (session->age == 16) - session->age = 0; - break; + spin_unlock_bh(&session->lock); + + iscsi_unblock_session(session_to_cls(session)); + wake_up(&conn->ehwait); + return 0; case STOP_CONN_TERM: conn->stop_stage = 0; break; @@ -2039,8 +2032,6 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) } spin_unlock_bh(&session->lock); - iscsi_unblock_session(session_to_cls(session)); - wake_up(&conn->ehwait); return 0; } EXPORT_SYMBOL_GPL(iscsi_conn_start); @@ -2132,8 +2123,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, * flush queues. */ spin_lock_bh(&session->lock); - fail_all_commands(conn, -1, - STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR); + fail_all_commands(conn, -1); flush_control_queues(session, conn); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); @@ -2150,8 +2140,7 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) iscsi_start_session_recovery(session, conn, flag); break; default: - iscsi_conn_printk(KERN_ERR, conn, - "invalid stop flag %d\n", flag); + printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); } } EXPORT_SYMBOL_GPL(iscsi_conn_stop); diff --git a/trunk/drivers/scsi/mac_esp.c b/trunk/drivers/scsi/mac_esp.c new file mode 100644 index 000000000000..bcb49021b7e2 --- /dev/null +++ b/trunk/drivers/scsi/mac_esp.c @@ -0,0 +1,751 @@ +/* + * 68k mac 53c9[46] scsi driver + * + * copyright (c) 1998, David Weis weisd3458@uni.edu + * + * debugging on Quadra 800 and 660AV Michael Schmitz, Dave Kilzer 7/98 + * + * based loosely on cyber_esp.c + */ + +/* these are unused for now */ +#define myreadl(addr) (*(volatile unsigned int *) (addr)) +#define mywritel(b, addr) ((*(volatile unsigned int *) (addr)) = (b)) + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +/* #define DEBUG_MAC_ESP */ + +extern void esp_handle(struct NCR_ESP *esp); +extern void mac_esp_intr(int irq, void *dev_id); + +static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP * esp); +static void dma_init_read(struct NCR_ESP * esp, char * vaddress, int length); +static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length); +static void dma_ints_off(struct NCR_ESP * esp); +static void dma_ints_on(struct NCR_ESP * esp); +static int dma_irq_p(struct NCR_ESP * esp); +static int dma_irq_p_quick(struct NCR_ESP * esp); +static void dma_led_off(struct NCR_ESP * esp); +static void dma_led_on(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP * esp, __u32 addr, int count, int write); +static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int write); + +static int esp_dafb_dma_irq_p(struct NCR_ESP * espdev); +static int esp_iosb_dma_irq_p(struct NCR_ESP * espdev); + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are transferred to the ESP chip + * via PIO. + */ + +static int esp_initialized = 0; + +static int setup_num_esps = -1; +static int setup_disconnect = -1; +static int setup_nosync = -1; +static int setup_can_queue = -1; +static int setup_cmd_per_lun = -1; +static int setup_sg_tablesize = -1; +#ifdef SUPPORT_TAGS +static int setup_use_tagged_queuing = -1; +#endif +static int setup_hostid = -1; + +/* + * Experimental ESP inthandler; check macints.c to make sure dev_id is + * set up properly! + */ + +void mac_esp_intr(int irq, void *dev_id) +{ + struct NCR_ESP *esp = (struct NCR_ESP *) dev_id; + int irq_p = 0; + + /* Handle the one ESP interrupt showing at this IRQ level. */ + if(((esp)->irq & 0xff) == irq) { + /* + * Debug .. + */ + irq_p = esp->dma_irq_p(esp); + printk("mac_esp: irq_p %x current %p disconnected %p\n", + irq_p, esp->current_SC, esp->disconnected_SC); + + /* + * Mac: if we're here, it's an ESP interrupt for sure! + */ + if((esp->current_SC || esp->disconnected_SC)) { + esp->dma_ints_off(esp); + + ESPIRQ(("I%d(", esp->esp_id)); + esp_handle(esp); + ESPIRQ((")")); + + esp->dma_ints_on(esp); + } + } +} + +/* + * Debug hooks; use for playing with the interrupt flag testing and interrupt + * acknowledge on the various machines + */ + +void scsi_esp_polled(int irq, void *dev_id) +{ + if (esp_initialized == 0) + return; + + mac_esp_intr(irq, dev_id); +} + +void fake_intr(int irq, void *dev_id) +{ +#ifdef DEBUG_MAC_ESP + printk("mac_esp: got irq\n"); +#endif + + mac_esp_intr(irq, dev_id); +} + +irqreturn_t fake_drq(int irq, void *dev_id) +{ + printk("mac_esp: got drq\n"); + return IRQ_HANDLED; +} + +#define DRIVER_SETUP + +/* + * Function : mac_esp_setup(char *str) + * + * Purpose : booter command line initialization of the overrides array, + * + * Inputs : str - parameters, separated by commas. + * + * Currently unused in the new driver; need to add settable parameters to the + * detect function. + * + */ + +static int __init mac_esp_setup(char *str) { +#ifdef DRIVER_SETUP + /* Format of mac53c9x parameter is: + * mac53c9x=,,,,,,, + * Negative values mean don't change. + */ + + char *this_opt; + long opt; + + this_opt = strsep (&str, ","); + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + if (opt >= 0 && opt <= 2) + setup_num_esps = opt; + else if (opt > 2) + printk( "mac_esp_setup: invalid number of hosts %ld !\n", opt ); + + this_opt = strsep (&str, ","); + } + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + if (opt > 0) + setup_disconnect = opt; + + this_opt = strsep (&str, ","); + } + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + if (opt >= 0) + setup_nosync = opt; + + this_opt = strsep (&str, ","); + } + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + if (opt > 0) + setup_can_queue = opt; + + this_opt = strsep (&str, ","); + } + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + if (opt > 0) + setup_cmd_per_lun = opt; + + this_opt = strsep (&str, ","); + } + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + if (opt >= 0) { + setup_sg_tablesize = opt; + /* Must be <= SG_ALL (255) */ + if (setup_sg_tablesize > SG_ALL) + setup_sg_tablesize = SG_ALL; + } + + this_opt = strsep (&str, ","); + } + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + /* Must be between 0 and 7 */ + if (opt >= 0 && opt <= 7) + setup_hostid = opt; + else if (opt > 7) + printk( "mac_esp_setup: invalid host ID %ld !\n", opt); + + this_opt = strsep (&str, ","); + } +#ifdef SUPPORT_TAGS + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + if (opt >= 0) + setup_use_tagged_queuing = !!opt; + } +#endif +#endif + return 1; +} + +__setup("mac53c9x=", mac_esp_setup); + + +/* + * ESP address 'detection' + */ + +unsigned long get_base(int chip_num) +{ + /* + * using the chip_num and mac model, figure out where the + * chips are mapped + */ + + unsigned long io_base = 0x50f00000; + unsigned int second_offset = 0x402; + unsigned long scsi_loc = 0; + + switch (macintosh_config->scsi_type) { + + /* 950, 900, 700 */ + case MAC_SCSI_QUADRA2: + scsi_loc = io_base + 0xf000 + ((chip_num == 0) ? 0 : second_offset); + break; + + /* av's */ + case MAC_SCSI_QUADRA3: + scsi_loc = io_base + 0x18000 + ((chip_num == 0) ? 0 : second_offset); + break; + + /* most quadra/centris models are like this */ + case MAC_SCSI_QUADRA: + scsi_loc = io_base + 0x10000; + break; + + default: + printk("mac_esp: get_base: hit default!\n"); + scsi_loc = io_base + 0x10000; + break; + + } /* switch */ + + printk("mac_esp: io base at 0x%lx\n", scsi_loc); + + return scsi_loc; +} + +/* + * Model dependent ESP setup + */ + +int mac_esp_detect(struct scsi_host_template * tpnt) +{ + int quick = 0; + int chipnum, chipspresent = 0; +#if 0 + unsigned long timeout; +#endif + + if (esp_initialized > 0) + return -ENODEV; + + /* what do we have in this machine... */ + if (MACHW_PRESENT(MAC_SCSI_96)) { + chipspresent ++; + } + + if (MACHW_PRESENT(MAC_SCSI_96_2)) { + chipspresent ++; + } + + /* number of ESPs present ? */ + if (setup_num_esps >= 0) { + if (chipspresent >= setup_num_esps) + chipspresent = setup_num_esps; + else + printk("mac_esp_detect: num_hosts detected %d setup %d \n", + chipspresent, setup_num_esps); + } + + /* TODO: add disconnect / nosync flags */ + + /* setup variables */ + tpnt->can_queue = + (setup_can_queue > 0) ? setup_can_queue : 7; + tpnt->cmd_per_lun = + (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : 1; + tpnt->sg_tablesize = + (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_ALL; + + if (setup_hostid >= 0) + tpnt->this_id = setup_hostid; + else { + /* use 7 as default */ + tpnt->this_id = 7; + } + +#ifdef SUPPORT_TAGS + if (setup_use_tagged_queuing < 0) + setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING; +#endif + + for (chipnum = 0; chipnum < chipspresent; chipnum ++) { + struct NCR_ESP * esp; + + esp = esp_allocate(tpnt, NULL, 0); + esp->eregs = (struct ESP_regs *) get_base(chipnum); + + esp->dma_irq_p = &esp_dafb_dma_irq_p; + if (chipnum == 0) { + + if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) { + /* most machines except those below :-) */ + quick = 1; + esp->dma_irq_p = &esp_iosb_dma_irq_p; + } else if (macintosh_config->scsi_type == MAC_SCSI_QUADRA3) { + /* mostly av's */ + quick = 0; + } else { + /* q950, 900, 700 */ + quick = 1; + out_be32(0xf9800024, 0x1d1); + esp->dregs = (void *) 0xf9800024; + } + + } else { /* chipnum */ + + quick = 1; + out_be32(0xf9800028, 0x1d1); + esp->dregs = (void *) 0xf9800028; + + } /* chipnum == 0 */ + + /* use pio for command bytes; pio for message/data: TBI */ + esp->do_pio_cmds = 1; + + /* Set the command buffer */ + esp->esp_command = (volatile unsigned char*) cmd_buffer; + esp->esp_command_dvma = (__u32) cmd_buffer; + + /* various functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = NULL; + esp->dma_init_write = NULL; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + + esp->dma_ports_p = &dma_ports_p; + + + /* Optional functions */ + esp->dma_barrier = NULL; + esp->dma_drain = NULL; + esp->dma_invalidate = NULL; + esp->dma_irq_entry = NULL; + esp->dma_irq_exit = NULL; + esp->dma_led_on = NULL; + esp->dma_led_off = NULL; + esp->dma_poll = NULL; + esp->dma_reset = NULL; + + /* SCSI chip speed */ + /* below esp->cfreq = 40000000; */ + + + if (quick) { + /* 'quick' means there's handshake glue logic like in the 5380 case */ + esp->dma_setup = &dma_setup_quick; + } else { + esp->dma_setup = &dma_setup; + } + + if (chipnum == 0) { + + esp->irq = IRQ_MAC_SCSI; + + request_irq(IRQ_MAC_SCSI, esp_intr, 0, "Mac ESP SCSI", esp->ehost); +#if 0 /* conflicts with IOP ADB */ + request_irq(IRQ_MAC_SCSIDRQ, fake_drq, 0, "Mac ESP DRQ", esp->ehost); +#endif + + if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) { + esp->cfreq = 16500000; + } else { + esp->cfreq = 25000000; + } + + + } else { /* chipnum == 1 */ + + esp->irq = IRQ_MAC_SCSIDRQ; +#if 0 /* conflicts with IOP ADB */ + request_irq(IRQ_MAC_SCSIDRQ, esp_intr, 0, "Mac ESP SCSI 2", esp->ehost); +#endif + + esp->cfreq = 25000000; + + } + + if (quick) { + printk("esp: using quick version\n"); + } + + printk("esp: addr at 0x%p\n", esp->eregs); + + esp->scsi_id = 7; + esp->diff = 0; + + esp_initialize(esp); + + } /* for chipnum */ + + if (chipspresent) + printk("\nmac_esp: %d esp controllers found\n", chipspresent); + + esp_initialized = chipspresent; + + return chipspresent; +} + +static int mac_esp_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + +/* + * I've been wondering what this is supposed to do, for some time. Talking + * to Allen Briggs: These machines have an extra register someplace where the + * DRQ pin of the ESP can be monitored. That isn't useful for determining + * anything else (such as reselect interrupt or other magic) though. + * Maybe make the semantics should be changed like + * if (esp->current_SC) + * ... check DRQ flag ... + * else + * ... disconnected, check pending VIA interrupt ... + * + * There's a problem with using the dabf flag or mac_irq_pending() here: both + * seem to return 1 even though no interrupt is currently pending, resulting + * in esp_exec_cmd() holding off the next command, and possibly infinite loops + * in esp_intr(). + * Short term fix: just use esp_status & ESP_STAT_INTR here, as long as we + * use simple PIO. The DRQ status will be important when implementing pseudo + * DMA mode (set up ESP transfer count, return, do a batch of bytes in PIO or + * 'hardware handshake' mode upon DRQ). + * If you plan on changing this (i.e. to save the esp_status register access in + * favor of a VIA register access or a shadow register for the IFR), make sure + * to try a debug version of this first to monitor what registers would be a good + * indicator of the ESP interrupt. + */ + +static int esp_dafb_dma_irq_p(struct NCR_ESP * esp) +{ + unsigned int ret; + int sreg = esp_read(esp->eregs->esp_status); + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: esp_dafb_dma_irq_p dafb %d irq %d\n", + readl(esp->dregs), mac_irq_pending(IRQ_MAC_SCSI)); +#endif + + sreg &= ESP_STAT_INTR; + + /* + * maybe working; this is essentially what's used for iosb_dma_irq_p + */ + if (sreg) + return 1; + else + return 0; + + /* + * didn't work ... + */ +#if 0 + if (esp->current_SC) + ret = readl(esp->dregs) & 0x200; + else if (esp->disconnected_SC) + ret = 1; /* sreg ?? */ + else + ret = mac_irq_pending(IRQ_MAC_SCSI); + + return(ret); +#endif + +} + +/* + * See above: testing mac_irq_pending always returned 8 (SCSI IRQ) regardless + * of the actual ESP status. + */ + +static int esp_iosb_dma_irq_p(struct NCR_ESP * esp) +{ + int ret = mac_irq_pending(IRQ_MAC_SCSI) || mac_irq_pending(IRQ_MAC_SCSIDRQ); + int sreg = esp_read(esp->eregs->esp_status); + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_irq_p drq %d irq %d sreg %x curr %p disc %p\n", + mac_irq_pending(IRQ_MAC_SCSIDRQ), mac_irq_pending(IRQ_MAC_SCSI), + sreg, esp->current_SC, esp->disconnected_SC); +#endif + + sreg &= ESP_STAT_INTR; + + if (sreg) + return (sreg); + else + return 0; +} + +/* + * This seems to be OK for PIO at least ... usually 0 after PIO. + */ + +static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count) +{ + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma bytes sent = %x\n", fifo_count); +#endif + + return fifo_count; +} + +/* + * dma_can_transfer is used to switch between DMA and PIO, if DMA (pseudo) + * is ever implemented. Returning 0 here will use PIO. + */ + +static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd * sp) +{ + unsigned long sz = sp->SCp.this_residual; +#if 0 /* no DMA yet; make conditional */ + if (sz > 0x10000000) { + sz = 0x10000000; + } + printk("mac_esp: dma can transfer = 0lx%x\n", sz); +#else + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: pio to transfer = %ld\n", sz); +#endif + + sz = 0; +#endif + return sz; +} + +/* + * Not yet ... + */ + +static void dma_dump_state(struct NCR_ESP * esp) +{ +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_dump_state: called\n"); +#endif +#if 0 + ESPLOG(("esp%d: dma -- cond_reg<%02x>\n", + esp->esp_id, ((struct mac_dma_registers *) + (esp->dregs))->cond_reg)); +#endif +} + +/* + * DMA setup: should be used to set up the ESP transfer count for pseudo + * DMA transfers; need a DRQ transfer function to do the actual transfer + */ + +static void dma_init_read(struct NCR_ESP * esp, char * vaddress, int length) +{ + printk("mac_esp: dma_init_read\n"); +} + + +static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length) +{ + printk("mac_esp: dma_init_write\n"); +} + + +static void dma_ints_off(struct NCR_ESP * esp) +{ + disable_irq(esp->irq); +} + + +static void dma_ints_on(struct NCR_ESP * esp) +{ + enable_irq(esp->irq); +} + +/* + * generic dma_irq_p(), unused + */ + +static int dma_irq_p(struct NCR_ESP * esp) +{ + int i = esp_read(esp->eregs->esp_status); + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_irq_p status %d\n", i); +#endif + + return (i & ESP_STAT_INTR); +} + +static int dma_irq_p_quick(struct NCR_ESP * esp) +{ + /* + * Copied from iosb_dma_irq_p() + */ + int ret = mac_irq_pending(IRQ_MAC_SCSI) || mac_irq_pending(IRQ_MAC_SCSIDRQ); + int sreg = esp_read(esp->eregs->esp_status); + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_irq_p drq %d irq %d sreg %x curr %p disc %p\n", + mac_irq_pending(IRQ_MAC_SCSIDRQ), mac_irq_pending(IRQ_MAC_SCSI), + sreg, esp->current_SC, esp->disconnected_SC); +#endif + + sreg &= ESP_STAT_INTR; + + if (sreg) + return (sreg); + else + return 0; + +} + +static void dma_led_off(struct NCR_ESP * esp) +{ +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_led_off: called\n"); +#endif +} + + +static void dma_led_on(struct NCR_ESP * esp) +{ +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_led_on: called\n"); +#endif +} + + +static int dma_ports_p(struct NCR_ESP * esp) +{ + return 0; +} + + +static void dma_setup(struct NCR_ESP * esp, __u32 addr, int count, int write) +{ + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_setup\n"); +#endif + + if (write) { + dma_init_read(esp, (char *) addr, count); + } else { + dma_init_write(esp, (char *) addr, count); + } +} + + +static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int write) +{ +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_setup_quick\n"); +#endif +} + +static struct scsi_host_template driver_template = { + .proc_name = "mac_esp", + .name = "Mac 53C9x SCSI", + .detect = mac_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = mac_esp_release, + .info = esp_info, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/mca_53c9x.c b/trunk/drivers/scsi/mca_53c9x.c new file mode 100644 index 000000000000..d693d0f21395 --- /dev/null +++ b/trunk/drivers/scsi/mca_53c9x.c @@ -0,0 +1,520 @@ +/* mca_53c9x.c: Driver for the SCSI adapter found on NCR 35xx + * (and maybe some other) Microchannel machines + * + * Code taken mostly from Cyberstorm SCSI drivers + * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) + * + * Hacked to work with the NCR MCA stuff by Tymm Twillman (tymm@computer.org) + * + * The CyberStorm SCSI driver (and this driver) is based on David S. Miller's + * ESP driver * for the Sparc computers. + * + * Special thanks to Ken Stewart at Symbios (LSI) for helping with info on + * the 86C01. I was on the brink of going ga-ga... + * + * Also thanks to Jesper Skov for helping me with info on how the Amiga + * does things... + */ + +/* + * This is currently only set up to use one 53c9x card at a time; it could be + * changed fairly easily to detect/use more than one, but I'm not too sure how + * many cards that use the 53c9x on MCA systems there are (if, in fact, there + * are cards that use them, other than the one built into some NCR systems)... + * If anyone requests this, I'll throw it in, otherwise it's not worth the + * effort. + */ + +/* + * Info on the 86C01 MCA interface chip at the bottom, if you care enough to + * look. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include + +/* + * From ibmmca.c (IBM scsi controller card driver) -- used for turning PS2 disk + * activity LED on and off + */ + +#define PS2_SYS_CTR 0x92 + +/* Ports the ncr's 53c94 can be put at; indexed by pos register value */ + +#define MCA_53C9X_IO_PORTS { \ + 0x0000, 0x0240, 0x0340, 0x0400, \ + 0x0420, 0x3240, 0x8240, 0xA240, \ + } + +/* + * Supposedly there were some cards put together with the 'c9x and 86c01. If + * they have different ID's from the ones on the 3500 series machines, + * you can add them here and hopefully things will work out. + */ + +#define MCA_53C9X_IDS { \ + 0x7F4C, \ + 0x0000, \ + } + +static int dma_bytes_sent(struct NCR_ESP *, int); +static int dma_can_transfer(struct NCR_ESP *, Scsi_Cmnd *); +static void dma_dump_state(struct NCR_ESP *); +static void dma_init_read(struct NCR_ESP *, __u32, int); +static void dma_init_write(struct NCR_ESP *, __u32, int); +static void dma_ints_off(struct NCR_ESP *); +static void dma_ints_on(struct NCR_ESP *); +static int dma_irq_p(struct NCR_ESP *); +static int dma_ports_p(struct NCR_ESP *); +static void dma_setup(struct NCR_ESP *, __u32, int, int); +static void dma_led_on(struct NCR_ESP *); +static void dma_led_off(struct NCR_ESP *); + +/* This is where all commands are put before they are trasfered to the + * 53c9x via PIO. + */ + +static volatile unsigned char cmd_buffer[16]; + +/* + * We keep the structure that is used to access the registers on the 53c9x + * here. + */ + +static struct ESP_regs eregs; + +/***************************************************************** Detection */ +static int mca_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + static int io_port_by_pos[] = MCA_53C9X_IO_PORTS; + int mca_53c9x_ids[] = MCA_53C9X_IDS; + int *id_to_check = mca_53c9x_ids; + int slot; + int pos[3]; + unsigned int tmp_io_addr; + unsigned char tmp_byte; + + + if (!MCA_bus) + return 0; + + while (*id_to_check) { + if ((slot = mca_find_adapter(*id_to_check, 0)) != + MCA_NOTFOUND) + { + esp = esp_allocate(tpnt, NULL, 0); + + pos[0] = mca_read_stored_pos(slot, 2); + pos[1] = mca_read_stored_pos(slot, 3); + pos[2] = mca_read_stored_pos(slot, 4); + + esp->eregs = &eregs; + + /* + * IO port base is given in the first (non-ID) pos + * register, like so: + * + * Bits 3 2 1 IO base + * ---------------------------- + * 0 0 0 + * 0 0 1 0x0240 + * 0 1 0 0x0340 + * 0 1 1 0x0400 + * 1 0 0 0x0420 + * 1 0 1 0x3240 + * 1 1 0 0x8240 + * 1 1 1 0xA240 + */ + + tmp_io_addr = + io_port_by_pos[(pos[0] & 0x0E) >> 1]; + + esp->eregs->io_addr = tmp_io_addr + 0x10; + + if (esp->eregs->io_addr == 0x0000) { + printk("Adapter is disabled.\n"); + break; + } + + /* + * IRQ is specified in bits 4 and 5: + * + * Bits 4 5 IRQ + * ----------------------- + * 0 0 3 + * 0 1 5 + * 1 0 7 + * 1 1 9 + */ + + esp->irq = ((pos[0] & 0x30) >> 3) + 3; + + /* + * DMA channel is in the low 3 bits of the second + * POS register + */ + + esp->dma = pos[1] & 7; + esp->slot = slot; + + if (request_irq(esp->irq, esp_intr, 0, + "NCR 53c9x SCSI", esp->ehost)) + { + printk("Unable to request IRQ %d.\n", esp->irq); + esp_deallocate(esp); + scsi_unregister(esp->ehost); + return 0; + } + + if (request_dma(esp->dma, "NCR 53c9x SCSI")) { + printk("Unable to request DMA channel %d.\n", + esp->dma); + free_irq(esp->irq, esp_intr); + esp_deallocate(esp); + scsi_unregister(esp->ehost); + return 0; + } + + request_region(tmp_io_addr, 32, "NCR 53c9x SCSI"); + + /* + * 86C01 handles DMA, IO mode, from address + * (base + 0x0a) + */ + + mca_disable_dma(esp->dma); + mca_set_dma_io(esp->dma, tmp_io_addr + 0x0a); + mca_enable_dma(esp->dma); + + /* Tell the 86C01 to give us interrupts */ + + tmp_byte = inb(tmp_io_addr + 0x02) | 0x40; + outb(tmp_byte, tmp_io_addr + 0x02); + + /* + * Scsi ID -- general purpose register, hi + * 2 bits; add 4 to this number to get the + * ID + */ + + esp->scsi_id = ((pos[2] & 0xC0) >> 6) + 4; + + /* Do command transfer with programmed I/O */ + + esp->do_pio_cmds = 1; + + /* Required functions */ + + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + + esp->dma_barrier = NULL; + esp->dma_drain = NULL; + esp->dma_invalidate = NULL; + esp->dma_irq_entry = NULL; + esp->dma_irq_exit = NULL; + esp->dma_led_on = dma_led_on; + esp->dma_led_off = dma_led_off; + esp->dma_poll = NULL; + esp->dma_reset = NULL; + + /* Set the command buffer */ + + esp->esp_command = (volatile unsigned char*) + cmd_buffer; + esp->esp_command_dvma = isa_virt_to_bus(cmd_buffer); + + /* SCSI chip speed */ + + esp->cfreq = 25000000; + + /* Differential SCSI? I think not. */ + + esp->diff = 0; + + esp_initialize(esp); + + printk(" Adapter found in slot %2d: io port 0x%x " + "irq %d dma channel %d\n", slot + 1, tmp_io_addr, + esp->irq, esp->dma); + + mca_set_adapter_name(slot, "NCR 53C9X SCSI Adapter"); + mca_mark_as_used(slot); + + break; + } + + id_to_check++; + } + + return esps_in_use; +} + + +/******************************************************************* Release */ + +static int mca_esp_release(struct Scsi_Host *host) +{ + struct NCR_ESP *esp = (struct NCR_ESP *)host->hostdata; + unsigned char tmp_byte; + + esp_deallocate(esp); + /* + * Tell the 86C01 to stop sending interrupts + */ + + tmp_byte = inb(esp->eregs->io_addr - 0x0E); + tmp_byte &= ~0x40; + outb(tmp_byte, esp->eregs->io_addr - 0x0E); + + free_irq(esp->irq, esp_intr); + free_dma(esp->dma); + + mca_mark_as_unused(esp->slot); + + return 0; +} + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Ask the 53c9x. It knows. */ + + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + /* + * The MCA dma channels can only do up to 128K bytes at a time. + * (16 bit mode) + */ + + unsigned long sz = sp->SCp.this_residual; + if(sz > 0x20000) + sz = 0x20000; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ + /* + * Doesn't quite match up to the other drivers, but we do what we + * can. + */ + + ESPLOG(("esp%d: dma channel <%d>\n", esp->esp_id, esp->dma)); + ESPLOG(("bytes left to dma: %d\n", mca_get_dma_residue(esp->dma))); +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) +{ + unsigned long flags; + + + save_flags(flags); + cli(); + + mca_disable_dma(esp->dma); + mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_16 | + MCA_DMA_MODE_IO); + mca_set_dma_addr(esp->dma, addr); + mca_set_dma_count(esp->dma, length / 2); /* !!! */ + mca_enable_dma(esp->dma); + + restore_flags(flags); +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) +{ + unsigned long flags; + + + save_flags(flags); + cli(); + + mca_disable_dma(esp->dma); + mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_WRITE | + MCA_DMA_MODE_16 | MCA_DMA_MODE_IO); + mca_set_dma_addr(esp->dma, addr); + mca_set_dma_count(esp->dma, length / 2); /* !!! */ + mca_enable_dma(esp->dma); + + restore_flags(flags); +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + /* + * Tell the 'C01 to shut up. All interrupts are routed through it. + */ + + outb(inb(esp->eregs->io_addr - 0x0E) & ~0x40, + esp->eregs->io_addr - 0x0E); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + /* + * Ok. You can speak again. + */ + + outb(inb(esp->eregs->io_addr - 0x0E) | 0x40, + esp->eregs->io_addr - 0x0E); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + /* + * DaveM says that this should return a "yes" if there is an interrupt + * or a DMA error occurred. I copied the Amiga driver's semantics, + * though, because it seems to work and we can't really tell if + * a DMA error happened. This gives the "yes" if the scsi chip + * is sending an interrupt and no DMA activity is taking place + */ + + return (!(inb(esp->eregs->io_addr - 0x04) & 1) && + !(inb(esp->eregs->io_addr - 0x04) & 2) ); +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + /* + * Check to see if interrupts are enabled on the 'C01 (in case abort + * is entered multiple times, so we only do the abort once) + */ + + return (inb(esp->eregs->io_addr - 0x0E) & 0x40) ? 1:0; +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + if(write){ + dma_init_write(esp, addr, count); + } else { + dma_init_read(esp, addr, count); + } +} + +/* + * These will not play nicely with other disk controllers that try to use the + * disk active LED... but what can you do? Don't answer that. + * + * Stolen shamelessly from ibmmca.c -- IBM Microchannel SCSI adapter driver + * + */ + +static void dma_led_on(struct NCR_ESP *esp) +{ + outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); +} + +static void dma_led_off(struct NCR_ESP *esp) +{ + outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); +} + +static struct scsi_host_template driver_template = { + .proc_name = "mca_53c9x", + .name = "NCR 53c9x SCSI", + .detect = mca_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = mca_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .unchecked_isa_dma = 1, + .use_clustering = DISABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +/* + * OK, here's the goods I promised. The NCR 86C01 is an MCA interface chip + * that handles enabling/diabling IRQ, dma interfacing, IO port selection + * and other fun stuff. It takes up 16 addresses, and the chip it is + * connnected to gets the following 16. Registers are as follows: + * + * Offsets 0-1 : Card ID + * + * Offset 2 : Mode enable register -- + * Bit 7 : Data Word width (1 = 16, 0 = 8) + * Bit 6 : IRQ enable (1 = enabled) + * Bits 5,4 : IRQ select + * 0 0 : IRQ 3 + * 0 1 : IRQ 5 + * 1 0 : IRQ 7 + * 1 1 : IRQ 9 + * Bits 3-1 : Base Address + * 0 0 0 : + * 0 0 1 : 0x0240 + * 0 1 0 : 0x0340 + * 0 1 1 : 0x0400 + * 1 0 0 : 0x0420 + * 1 0 1 : 0x3240 + * 1 1 0 : 0x8240 + * 1 1 1 : 0xA240 + * Bit 0 : Card enable (1 = enabled) + * + * Offset 3 : DMA control register -- + * Bit 7 : DMA enable (1 = enabled) + * Bits 6,5 : Preemt Count Select (transfers to complete after + * 'C01 has been preempted on MCA bus) + * 0 0 : 0 + * 0 1 : 1 + * 1 0 : 3 + * 1 1 : 7 + * (all these wacky numbers; I'm sure there's a reason somewhere) + * Bit 4 : Fairness enable (1 = fair bus priority) + * Bits 3-0 : Arbitration level (0-15 consecutive) + * + * Offset 4 : General purpose register + * Bits 7-3 : User definable (here, 7,6 are SCSI ID) + * Bits 2-0 : reserved + * + * Offset 10 : DMA decode register (used for IO based DMA; also can do + * PIO through this port) + * + * Offset 12 : Status + * Bits 7-2 : reserved + * Bit 1 : DMA pending (1 = pending) + * Bit 0 : IRQ pending (0 = pending) + * + * Exciting, huh? + * + */ diff --git a/trunk/drivers/scsi/oktagon_esp.c b/trunk/drivers/scsi/oktagon_esp.c new file mode 100644 index 000000000000..8e5eadbd5c51 --- /dev/null +++ b/trunk/drivers/scsi/oktagon_esp.c @@ -0,0 +1,606 @@ +/* + * Oktagon_esp.c -- Driver for bsc Oktagon + * + * Written by Carsten Pluntke 1998 + * + * Based on cyber_esp.c + */ + + +#if defined(CONFIG_AMIGA) || defined(CONFIG_APUS) +#define USE_BOTTOM_HALF +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include + +#ifdef USE_BOTTOM_HALF +#include +#include +#endif + +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define OKTAGON_ESP_ADDR 0x03000 +#define OKTAGON_DMA_ADDR 0x01000 + + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static void dma_led_off(struct NCR_ESP *esp); +static void dma_led_on(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); + +static void dma_irq_exit(struct NCR_ESP *esp); +static void dma_invalidate(struct NCR_ESP *esp); + +static void dma_mmu_get_scsi_one(struct NCR_ESP *,Scsi_Cmnd *); +static void dma_mmu_get_scsi_sgl(struct NCR_ESP *,Scsi_Cmnd *); +static void dma_mmu_release_scsi_one(struct NCR_ESP *,Scsi_Cmnd *); +static void dma_mmu_release_scsi_sgl(struct NCR_ESP *,Scsi_Cmnd *); +static void dma_advance_sg(Scsi_Cmnd *); +static int oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x); + +#ifdef USE_BOTTOM_HALF +static void dma_commit(struct work_struct *unused); + +long oktag_to_io(long *paddr, long *addr, long len); +long oktag_from_io(long *addr, long *paddr, long len); + +static DECLARE_WORK(tq_fake_dma, dma_commit); + +#define DMA_MAXTRANSFER 0x8000 + +#else + +/* + * No bottom half. Use transfer directly from IRQ. Find a narrow path + * between too much IRQ overhead and clogging the IRQ for too long. + */ + +#define DMA_MAXTRANSFER 0x1000 + +#endif + +static struct notifier_block oktagon_notifier = { + oktagon_notify_reboot, + NULL, + 0 +}; + +static long *paddress; +static long *address; +static long len; +static long dma_on; +static int direction; +static struct NCR_ESP *current_esp; + + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are trasfered to the ESP chip + * via PIO. + */ + +/***************************************************************** Detection */ +int oktagon_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct zorro_dev *z = NULL; + unsigned long address; + struct ESP_regs *eregs; + + while ((z = zorro_find_device(ZORRO_PROD_BSC_OKTAGON_2008, z))) { + unsigned long board = z->resource.start; + if (request_mem_region(board+OKTAGON_ESP_ADDR, + sizeof(struct ESP_regs), "NCR53C9x")) { + /* + * It is a SCSI controller. + * Hardwire Host adapter to SCSI ID 7 + */ + + address = (unsigned long)ZTWO_VADDR(board); + eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR); + + /* This line was 5 lines lower */ + esp = esp_allocate(tpnt, (void *)board + OKTAGON_ESP_ADDR, 0); + + /* we have to shift the registers only one bit for oktagon */ + esp->shift = 1; + + esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); + udelay(5); + if (esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)) + return 0; /* Bail out if address did not hold data */ + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = 0; + esp->dma_invalidate = &dma_invalidate; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = &dma_irq_exit; + esp->dma_led_on = &dma_led_on; + esp->dma_led_off = &dma_led_off; + esp->dma_poll = 0; + esp->dma_reset = 0; + + esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; + esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one; + esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl; + esp->dma_advance_sg = &dma_advance_sg; + + /* SCSI chip speed */ + /* Looking at the quartz of the SCSI board... */ + esp->cfreq = 25000000; + + /* The DMA registers on the CyberStorm are mapped + * relative to the device (i.e. in the same Zorro + * I/O block). + */ + esp->dregs = (void *)(address + OKTAGON_DMA_ADDR); + + paddress = (long *) esp->dregs; + + /* ESP register base */ + esp->eregs = eregs; + + /* Set the command buffer */ + esp->esp_command = (volatile unsigned char*) cmd_buffer; + + /* Yes, the virtual address. See below. */ + esp->esp_command_dvma = (__u32) cmd_buffer; + + esp->irq = IRQ_AMIGA_PORTS; + request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, + "BSC Oktagon SCSI", esp->ehost); + + /* Figure out our scsi ID on the bus */ + esp->scsi_id = 7; + + /* We don't have a differential SCSI-bus. */ + esp->diff = 0; + + esp_initialize(esp); + + printk("ESP_Oktagon Driver 1.1" +#ifdef USE_BOTTOM_HALF + " [BOTTOM_HALF]" +#else + " [IRQ]" +#endif + " registered.\n"); + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,esps_in_use); + esps_running = esps_in_use; + current_esp = esp; + register_reboot_notifier(&oktagon_notifier); + return esps_in_use; + } + } + return 0; +} + + +/* + * On certain configurations the SCSI equipment gets confused on reboot, + * so we have to reset it then. + */ + +static int +oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x) +{ + struct NCR_ESP *esp; + + if((code == SYS_DOWN || code == SYS_HALT) && (esp = current_esp)) + { + esp_bootup_reset(esp,esp->eregs); + udelay(500); /* Settle time. Maybe unnecessary. */ + } + return NOTIFY_DONE; +} + + + +#ifdef USE_BOTTOM_HALF + + +/* + * The bsc Oktagon controller has no real DMA, so we have to do the 'DMA + * transfer' in the interrupt (Yikes!) or use a bottom half to not to clutter + * IRQ's for longer-than-good. + * + * FIXME + * BIG PROBLEM: 'len' is usually the buffer length, not the expected length + * of the data. So DMA may finish prematurely, further reads lead to + * 'machine check' on APUS systems (don't know about m68k systems, AmigaOS + * deliberately ignores the bus faults) and a normal copy-loop can't + * be exited prematurely just at the right moment by the dma_invalidate IRQ. + * So do it the hard way, write an own copier in assembler and + * catch the exception. + * -- Carsten + */ + + +static void dma_commit(struct work_struct *unused) +{ + long wait,len2,pos; + struct NCR_ESP *esp; + + ESPDATA(("Transfer: %ld bytes, Address 0x%08lX, Direction: %d\n", + len,(long) address,direction)); + dma_ints_off(current_esp); + + pos = 0; + wait = 1; + if(direction) /* write? (memory to device) */ + { + while(len > 0) + { + len2 = oktag_to_io(paddress, address+pos, len); + if(!len2) + { + if(wait > 1000) + { + printk("Expedited DMA exit (writing) %ld\n",len); + break; + } + mdelay(wait); + wait *= 2; + } + pos += len2; + len -= len2*sizeof(long); + } + } else { + while(len > 0) + { + len2 = oktag_from_io(address+pos, paddress, len); + if(!len2) + { + if(wait > 1000) + { + printk("Expedited DMA exit (reading) %ld\n",len); + break; + } + mdelay(wait); + wait *= 2; + } + pos += len2; + len -= len2*sizeof(long); + } + } + + /* to make esp->shift work */ + esp=current_esp; + +#if 0 + len2 = (esp_read(current_esp->eregs->esp_tclow) & 0xff) | + ((esp_read(current_esp->eregs->esp_tcmed) & 0xff) << 8); + + /* + * Uh uh. If you see this, len and transfer count registers were out of + * sync. That means really serious trouble. + */ + + if(len2) + printk("Eeeek!! Transfer count still %ld!\n",len2); +#endif + + /* + * Normally we just need to exit and wait for the interrupt to come. + * But at least one device (my Microtek ScanMaker 630) regularly mis- + * calculates the bytes it should send which is really ugly because + * it locks up the SCSI bus if not accounted for. + */ + + if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR)) + { + long len = 100; + long trash[10]; + + /* + * Interrupt bit was not set. Either the device is just plain lazy + * so we give it a 10 ms chance or... + */ + while(len-- && (!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR))) + udelay(100); + + + if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR)) + { + /* + * So we think that the transfer count is out of sync. Since we + * have all we want we are happy and can ditch the trash. + */ + + len = DMA_MAXTRANSFER; + + while(len-- && (!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR))) + oktag_from_io(trash,paddress,2); + + if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR)) + { + /* + * Things really have gone wrong. If we leave the system in that + * state, the SCSI bus is locked forever. I hope that this will + * turn the system in a more or less running state. + */ + printk("Device is bolixed, trying bus reset...\n"); + esp_bootup_reset(current_esp,current_esp->eregs); + } + } + } + + ESPDATA(("Transfer_finale: do_data_finale should come\n")); + + len = 0; + dma_on = 0; + dma_ints_on(current_esp); +} + +#endif + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Since the CyberStorm DMA is fully dedicated to the ESP chip, + * the number of bytes sent (to the ESP chip) equals the number + * of bytes in the FIFO - there is no buffering in the DMA controller. + * XXXX Do I read this right? It is from host to ESP, right? + */ + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + unsigned long sz = sp->SCp.this_residual; + if(sz > DMA_MAXTRANSFER) + sz = DMA_MAXTRANSFER; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ +} + +/* + * What the f$@& is this? + * + * Some SCSI devices (like my Microtek ScanMaker 630 scanner) want to transfer + * more data than requested. How much? Dunno. So ditch the bogus data into + * the sink, hoping the device will advance to the next phase sooner or later. + * + * -- Carsten + */ + +static long oktag_eva_buffer[16]; /* The data sink */ + +static void oktag_check_dma(void) +{ + struct NCR_ESP *esp; + + esp=current_esp; + if(!len) + { + address = oktag_eva_buffer; + len = 2; + /* esp_do_data sets them to zero like len */ + esp_write(current_esp->eregs->esp_tclow,2); + esp_write(current_esp->eregs->esp_tcmed,0); + } +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) +{ + /* Zorro is noncached, everything else done using processor. */ + /* cache_clear(addr, length); */ + + if(dma_on) + panic("dma_init_read while dma process is initialized/running!\n"); + direction = 0; + address = (long *) vaddress; + current_esp = esp; + len = length; + oktag_check_dma(); + dma_on = 1; +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length) +{ + /* cache_push(addr, length); */ + + if(dma_on) + panic("dma_init_write while dma process is initialized/running!\n"); + direction = 1; + address = (long *) vaddress; + current_esp = esp; + len = length; + oktag_check_dma(); + dma_on = 1; +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(esp->irq); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(esp->irq); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + /* It's important to check the DMA IRQ bit in the correct way! */ + return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR); +} + +static void dma_led_off(struct NCR_ESP *esp) +{ +} + +static void dma_led_on(struct NCR_ESP *esp) +{ +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + return ((amiga_custom.intenar) & IF_PORTS); +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if(write){ + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +/* + * IRQ entry when DMA transfer is ready to be started + */ + +static void dma_irq_exit(struct NCR_ESP *esp) +{ +#ifdef USE_BOTTOM_HALF + if(dma_on) + { + schedule_work(&tq_fake_dma); + } +#else + while(len && !dma_irq_p(esp)) + { + if(direction) + *paddress = *address++; + else + *address++ = *paddress; + len -= (sizeof(long)); + } + len = 0; + dma_on = 0; +#endif +} + +/* + * IRQ entry when DMA has just finished + */ + +static void dma_invalidate(struct NCR_ESP *esp) +{ +} + +/* + * Since the processor does the data transfer we have to use the custom + * mmu interface to pass the virtual address, not the physical. + */ + +void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + sp->SCp.ptr = + sp->request_buffer; +} + +void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + sp->SCp.ptr = sg_virt(sp->SCp.buffer); +} + +void dma_mmu_release_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ +} + +void dma_mmu_release_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ +} + +void dma_advance_sg(Scsi_Cmnd *sp) +{ + sp->SCp.ptr = sg_virt(sp->SCp.buffer); +} + + +#define HOSTS_C + +int oktagon_esp_release(struct Scsi_Host *instance) +{ +#ifdef MODULE + unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; + esp_release(); + release_mem_region(address, sizeof(struct ESP_regs)); + free_irq(IRQ_AMIGA_PORTS, esp_intr); + unregister_reboot_notifier(&oktagon_notifier); +#endif + return 1; +} + + +static struct scsi_host_template driver_template = { + .proc_name = "esp-oktagon", + .proc_info = &esp_proc_info, + .name = "BSC Oktagon SCSI", + .detect = oktagon_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = oktagon_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/oktagon_io.S b/trunk/drivers/scsi/oktagon_io.S new file mode 100644 index 000000000000..8a7340b02707 --- /dev/null +++ b/trunk/drivers/scsi/oktagon_io.S @@ -0,0 +1,194 @@ +/* -*- mode: asm -*- + * Due to problems while transferring data I've put these routines as assembly + * code. + * Since I'm no PPC assembler guru, the code is just the assembler version of + +int oktag_to_io(long *paddr,long *addr,long len) +{ + long *addr2 = addr; + for(len=(len+sizeof(long)-1)/sizeof(long);len--;) + *paddr = *addr2++; + return addr2 - addr; +} + +int oktag_from_io(long *addr,long *paddr,long len) +{ + long *addr2 = addr; + for(len=(len+sizeof(long)-1)/sizeof(long);len--;) + *addr2++ = *paddr; + return addr2 - addr; +} + + * assembled using gcc -O2 -S, with two exception catch points where data + * is moved to/from the IO register. + */ + + +#ifdef CONFIG_APUS + + .file "oktagon_io.c" + +gcc2_compiled.: +/* + .section ".text" +*/ + .align 2 + .globl oktag_to_io + .type oktag_to_io,@function +oktag_to_io: + addi 5,5,3 + srwi 5,5,2 + cmpwi 1,5,0 + mr 9,3 + mr 3,4 + addi 5,5,-1 + bc 12,6,.L3 +.L5: + cmpwi 1,5,0 + lwz 0,0(3) + addi 3,3,4 + addi 5,5,-1 +exp1: stw 0,0(9) + bc 4,6,.L5 +.L3: +ret1: subf 3,4,3 + srawi 3,3,2 + blr +.Lfe1: + .size oktag_to_io,.Lfe1-oktag_to_io + .align 2 + .globl oktag_from_io + .type oktag_from_io,@function +oktag_from_io: + addi 5,5,3 + srwi 5,5,2 + cmpwi 1,5,0 + mr 9,3 + addi 5,5,-1 + bc 12,6,.L9 +.L11: + cmpwi 1,5,0 +exp2: lwz 0,0(4) + addi 5,5,-1 + stw 0,0(3) + addi 3,3,4 + bc 4,6,.L11 +.L9: +ret2: subf 3,9,3 + srawi 3,3,2 + blr +.Lfe2: + .size oktag_from_io,.Lfe2-oktag_from_io + .ident "GCC: (GNU) egcs-2.90.29 980515 (egcs-1.0.3 release)" + +/* + * Exception table. + * Second longword shows where to jump when an exception at the addr the first + * longword is pointing to is caught. + */ + +.section __ex_table,"a" + .align 2 +oktagon_except: + .long exp1,ret1 + .long exp2,ret2 + +#else + +/* +The code which follows is for 680x0 based assembler and is meant for +Linux/m68k. It was created by cross compiling the code using the +instructions given above. I then added the four labels used in the +exception handler table at the bottom of this file. +- Kevin +*/ + +#ifdef CONFIG_AMIGA + + .file "oktagon_io.c" + .version "01.01" +gcc2_compiled.: +.text + .align 2 +.globl oktag_to_io + .type oktag_to_io,@function +oktag_to_io: + link.w %a6,#0 + move.l %d2,-(%sp) + move.l 8(%a6),%a1 + move.l 12(%a6),%d1 + move.l %d1,%a0 + move.l 16(%a6),%d0 + addq.l #3,%d0 + lsr.l #2,%d0 + subq.l #1,%d0 + moveq.l #-1,%d2 + cmp.l %d0,%d2 + jbeq .L3 +.L5: +exp1: + move.l (%a0)+,(%a1) + dbra %d0,.L5 + clr.w %d0 + subq.l #1,%d0 + jbcc .L5 +.L3: +ret1: + move.l %a0,%d0 + sub.l %d1,%d0 + asr.l #2,%d0 + move.l -4(%a6),%d2 + unlk %a6 + rts + +.Lfe1: + .size oktag_to_io,.Lfe1-oktag_to_io + .align 2 +.globl oktag_from_io + .type oktag_from_io,@function +oktag_from_io: + link.w %a6,#0 + move.l %d2,-(%sp) + move.l 8(%a6),%d1 + move.l 12(%a6),%a1 + move.l %d1,%a0 + move.l 16(%a6),%d0 + addq.l #3,%d0 + lsr.l #2,%d0 + subq.l #1,%d0 + moveq.l #-1,%d2 + cmp.l %d0,%d2 + jbeq .L9 +.L11: +exp2: + move.l (%a1),(%a0)+ + dbra %d0,.L11 + clr.w %d0 + subq.l #1,%d0 + jbcc .L11 +.L9: +ret2: + move.l %a0,%d0 + sub.l %d1,%d0 + asr.l #2,%d0 + move.l -4(%a6),%d2 + unlk %a6 + rts +.Lfe2: + .size oktag_from_io,.Lfe2-oktag_from_io + .ident "GCC: (GNU) 2.7.2.1" + +/* + * Exception table. + * Second longword shows where to jump when an exception at the addr the first + * longword is pointing to is caught. + */ + +.section __ex_table,"a" + .align 2 +oktagon_except: + .long exp1,ret1 + .long exp2,ret2 + +#endif +#endif diff --git a/trunk/drivers/scsi/ps3rom.c b/trunk/drivers/scsi/ps3rom.c index 0cd614a0fa73..17b4a7c4618c 100644 --- a/trunk/drivers/scsi/ps3rom.c +++ b/trunk/drivers/scsi/ps3rom.c @@ -35,7 +35,7 @@ #define BOUNCE_SIZE (64*1024) -#define PS3ROM_MAX_SECTORS (BOUNCE_SIZE >> 9) +#define PS3ROM_MAX_SECTORS (BOUNCE_SIZE / CD_FRAMESIZE) struct ps3rom_private { diff --git a/trunk/drivers/scsi/qla2xxx/qla_attr.c b/trunk/drivers/scsi/qla2xxx/qla_attr.c index 4894dc886b62..adf97320574b 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_attr.c +++ b/trunk/drivers/scsi/qla2xxx/qla_attr.c @@ -428,19 +428,6 @@ qla2x00_sysfs_read_sfp(struct kobject *kobj, if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2) return 0; - if (ha->sfp_data) - goto do_read; - - ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, - &ha->sfp_data_dma); - if (!ha->sfp_data) { - qla_printk(KERN_WARNING, ha, - "Unable to allocate memory for SFP read-data.\n"); - return 0; - } - -do_read: - memset(ha->sfp_data, 0, SFP_BLOCK_SIZE); addr = 0xa0; for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE; iter++, offset += SFP_BLOCK_SIZE) { @@ -848,7 +835,7 @@ qla2x00_get_host_port_id(struct Scsi_Host *shost) static void qla2x00_get_host_speed(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); + scsi_qla_host_t *ha = shost_priv(shost); uint32_t speed = 0; switch (ha->link_data_rate) { @@ -861,9 +848,6 @@ qla2x00_get_host_speed(struct Scsi_Host *shost) case PORT_SPEED_4GB: speed = 4; break; - case PORT_SPEED_8GB: - speed = 8; - break; } fc_host_speed(shost) = speed; } @@ -871,7 +855,7 @@ qla2x00_get_host_speed(struct Scsi_Host *shost) static void qla2x00_get_host_port_type(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); + scsi_qla_host_t *ha = shost_priv(shost); uint32_t port_type = FC_PORTTYPE_UNKNOWN; switch (ha->current_topology) { @@ -981,7 +965,7 @@ qla2x00_issue_lip(struct Scsi_Host *shost) static struct fc_host_statistics * qla2x00_get_fc_host_stats(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); + scsi_qla_host_t *ha = shost_priv(shost); int rval; struct link_statistics *stats; dma_addr_t stats_dma; @@ -1065,7 +1049,7 @@ qla2x00_get_host_fabric_name(struct Scsi_Host *shost) static void qla2x00_get_host_port_state(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); + scsi_qla_host_t *ha = shost_priv(shost); if (!ha->flags.online) fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; diff --git a/trunk/drivers/scsi/qla2xxx/qla_def.h b/trunk/drivers/scsi/qla2xxx/qla_def.h index 3750319f4968..b72c7f170854 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_def.h +++ b/trunk/drivers/scsi/qla2xxx/qla_def.h @@ -2041,6 +2041,8 @@ typedef struct vport_params { #define VP_RET_CODE_NO_MEM 5 #define VP_RET_CODE_NOT_FOUND 6 +#define to_qla_parent(x) (((x)->parent) ? (x)->parent : (x)) + /* * ISP operations */ diff --git a/trunk/drivers/scsi/qla2xxx/qla_gbl.h b/trunk/drivers/scsi/qla2xxx/qla_gbl.h index 193f688ec3d7..ba35fc26ce6b 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_gbl.h +++ b/trunk/drivers/scsi/qla2xxx/qla_gbl.h @@ -66,7 +66,6 @@ extern int ql2xqfullrampup; extern int num_hosts; extern int qla2x00_loop_reset(scsi_qla_host_t *); -extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); /* * Global Functions in qla_mid.c source file. diff --git a/trunk/drivers/scsi/qla2xxx/qla_init.c b/trunk/drivers/scsi/qla2xxx/qla_init.c index d5c7853e7eba..d0633ca894be 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_init.c +++ b/trunk/drivers/scsi/qla2xxx/qla_init.c @@ -925,16 +925,6 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) { int rval; uint32_t srisc_address = 0; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - unsigned long flags; - - if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) { - /* Disable SRAM, Instruction RAM and GP RAM parity. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - WRT_REG_WORD(®->hccr, (HCCR_ENABLE_PARITY + 0x0)); - RD_REG_WORD(®->hccr); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } /* Load firmware sequences */ rval = ha->isp_ops->load_risc(ha, &srisc_address); @@ -978,19 +968,6 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) } } - if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) { - /* Enable proper parity. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - if (IS_QLA2300(ha)) - /* SRAM parity */ - WRT_REG_WORD(®->hccr, HCCR_ENABLE_PARITY + 0x1); - else - /* SRAM, Instruction RAM and GP RAM parity */ - WRT_REG_WORD(®->hccr, HCCR_ENABLE_PARITY + 0x7); - RD_REG_WORD(®->hccr); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } - if (rval) { DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n", ha->host_no)); @@ -3236,6 +3213,9 @@ int qla2x00_abort_isp(scsi_qla_host_t *ha) { int rval; + unsigned long flags = 0; + uint16_t cnt; + srb_t *sp; uint8_t status = 0; if (ha->flags.online) { @@ -3256,8 +3236,19 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) LOOP_DOWN_TIME); } + spin_lock_irqsave(&ha->hardware_lock, flags); /* Requeue all commands in outstanding command list. */ - qla2x00_abort_all_cmds(ha, DID_RESET << 16); + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + sp = ha->outstanding_cmds[cnt]; + if (sp) { + ha->outstanding_cmds[cnt] = NULL; + sp->flags = 0; + sp->cmd->result = DID_RESET << 16; + sp->cmd->host_scribble = (unsigned char *)NULL; + qla2x00_sp_compl(ha, sp); + } + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); ha->isp_ops->get_flash_version(ha, ha->request_ring); @@ -3282,7 +3273,6 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags); if (ha->eft) { - memset(ha->eft, 0, EFT_SIZE); rval = qla2x00_enable_eft_trace(ha, ha->eft_dma, EFT_NUM_BUFFERS); if (rval) { @@ -3367,15 +3357,60 @@ static int qla2x00_restart_isp(scsi_qla_host_t *ha) { uint8_t status = 0; + struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + unsigned long flags = 0; uint32_t wait_time; /* If firmware needs to be loaded */ if (qla2x00_isp_firmware(ha)) { ha->flags.online = 0; - if (!(status = ha->isp_ops->chip_diag(ha))) + if (!(status = ha->isp_ops->chip_diag(ha))) { + if (IS_QLA2100(ha) || IS_QLA2200(ha)) { + status = qla2x00_setup_chip(ha); + goto done; + } + + spin_lock_irqsave(&ha->hardware_lock, flags); + + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha) && + !IS_QLA25XX(ha)) { + /* + * Disable SRAM, Instruction RAM and GP RAM + * parity. + */ + WRT_REG_WORD(®->hccr, + (HCCR_ENABLE_PARITY + 0x0)); + RD_REG_WORD(®->hccr); + } + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + status = qla2x00_setup_chip(ha); + + spin_lock_irqsave(&ha->hardware_lock, flags); + + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha) && + !IS_QLA25XX(ha)) { + /* Enable proper parity */ + if (IS_QLA2300(ha)) + /* SRAM parity */ + WRT_REG_WORD(®->hccr, + (HCCR_ENABLE_PARITY + 0x1)); + else + /* + * SRAM, Instruction RAM and GP RAM + * parity. + */ + WRT_REG_WORD(®->hccr, + (HCCR_ENABLE_PARITY + 0x7)); + RD_REG_WORD(®->hccr); + } + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } } + done: if (!status && !(status = qla2x00_init_rings(ha))) { clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); if (!(status = qla2x00_fw_ready(ha))) { diff --git a/trunk/drivers/scsi/qla2xxx/qla_inline.h b/trunk/drivers/scsi/qla2xxx/qla_inline.h index 5d1a3f7c408f..8e3b04464cff 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_inline.h +++ b/trunk/drivers/scsi/qla2xxx/qla_inline.h @@ -119,13 +119,6 @@ static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *ha) qla2x00_get_firmware_state(ha, &fw_state); } -static __inline__ scsi_qla_host_t * to_qla_parent(scsi_qla_host_t *); -static __inline__ scsi_qla_host_t * -to_qla_parent(scsi_qla_host_t *ha) -{ - return ha->parent ? ha->parent : ha; -} - /** * qla2x00_issue_marker() - Issue a Marker IOCB if necessary. * @ha: HA context diff --git a/trunk/drivers/scsi/qla2xxx/qla_isr.c b/trunk/drivers/scsi/qla2xxx/qla_isr.c index 14e6f22944b7..642a0c3f09c6 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_isr.c +++ b/trunk/drivers/scsi/qla2xxx/qla_isr.c @@ -1815,8 +1815,6 @@ int qla2x00_request_irqs(scsi_qla_host_t *ha) { int ret; - device_reg_t __iomem *reg = ha->iobase; - unsigned long flags; /* If possible, enable MSI-X. */ if (!IS_QLA2432(ha) && !IS_QLA2532(ha)) @@ -1848,7 +1846,7 @@ qla2x00_request_irqs(scsi_qla_host_t *ha) DEBUG2(qla_printk(KERN_INFO, ha, "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision, ha->fw_attributes)); - goto clear_risc_ints; + return ret; } qla_printk(KERN_WARNING, ha, "MSI-X: Falling back-to INTa mode -- %d.\n", ret); @@ -1866,30 +1864,15 @@ qla2x00_request_irqs(scsi_qla_host_t *ha) ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler, IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha); - if (ret) { + if (!ret) { + ha->flags.inta_enabled = 1; + ha->host->irq = ha->pdev->irq; + } else { qla_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d already in use.\n", ha->pdev->irq); - goto fail; - } - ha->flags.inta_enabled = 1; - ha->host->irq = ha->pdev->irq; -clear_risc_ints: - - ha->isp_ops->disable_intrs(ha); - spin_lock_irqsave(&ha->hardware_lock, flags); - if (IS_FWI2_CAPABLE(ha)) { - WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_HOST_INT); - WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_RISC_INT); - } else { - WRT_REG_WORD(®->isp.semaphore, 0); - WRT_REG_WORD(®->isp.hccr, HCCR_CLR_RISC_INT); - WRT_REG_WORD(®->isp.hccr, HCCR_CLR_HOST_INT); } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - ha->isp_ops->enable_intrs(ha); -fail: return ret; } diff --git a/trunk/drivers/scsi/qla2xxx/qla_mbx.c b/trunk/drivers/scsi/qla2xxx/qla_mbx.c index 99d29fff836d..0c10c0b0fb73 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_mbx.c +++ b/trunk/drivers/scsi/qla2xxx/qla_mbx.c @@ -980,7 +980,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size) DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n", ha->host_no)); - if (ha->flags.npiv_supported) + if (ha->fw_attributes & BIT_2) mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE; else mcp->mb[0] = MBC_INITIALIZE_FIRMWARE; diff --git a/trunk/drivers/scsi/qla2xxx/qla_os.c b/trunk/drivers/scsi/qla2xxx/qla_os.c index 3c1b43356adb..8f69caf83272 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_os.c +++ b/trunk/drivers/scsi/qla2xxx/qla_os.c @@ -204,8 +204,10 @@ static int qla2x00_do_dpc(void *data); static void qla2x00_rst_aen(scsi_qla_host_t *); -static int qla2x00_mem_alloc(scsi_qla_host_t *); +static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *); static void qla2x00_mem_free(scsi_qla_host_t *ha); +static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha); +static void qla2x00_free_sp_pool(scsi_qla_host_t *ha); static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *); /* -------------------------------------------------------------------------- */ @@ -1115,27 +1117,6 @@ qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport) return ha->isp_ops->abort_target(reset_fcport); } -void -qla2x00_abort_all_cmds(scsi_qla_host_t *ha, int res) -{ - int cnt; - unsigned long flags; - srb_t *sp; - - spin_lock_irqsave(&ha->hardware_lock, flags); - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = ha->outstanding_cmds[cnt]; - if (sp) { - ha->outstanding_cmds[cnt] = NULL; - sp->flags = 0; - sp->cmd->result = res; - sp->cmd->host_scribble = (unsigned char *)NULL; - qla2x00_sp_compl(ha, sp); - } - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - static int qla2xxx_slave_alloc(struct scsi_device *sdev) { @@ -1576,8 +1557,10 @@ static int __devinit qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { int ret = -ENODEV; + device_reg_t __iomem *reg; struct Scsi_Host *host; scsi_qla_host_t *ha; + unsigned long flags = 0; char pci_info[30]; char fw_str[30]; struct scsi_host_template *sht; @@ -1625,7 +1608,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->parent = NULL; ha->bars = bars; ha->mem_only = mem_only; - spin_lock_init(&ha->hardware_lock); /* Set ISP-type information. */ qla2x00_set_isp_flags(ha); @@ -1639,6 +1621,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) "Found an ISP%04X, irq %d, iobase 0x%p\n", pdev->device, pdev->irq, ha->iobase); + spin_lock_init(&ha->hardware_lock); + ha->prev_topology = 0; ha->init_cb_size = sizeof(init_cb_t); ha->mgmt_svr_loop_id = MANAGEMENT_SERVER + ha->vp_idx; @@ -1767,6 +1751,34 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n", ha->host_no, ha)); + ha->isp_ops->disable_intrs(ha); + + spin_lock_irqsave(&ha->hardware_lock, flags); + reg = ha->iobase; + if (IS_FWI2_CAPABLE(ha)) { + WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_HOST_INT); + WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_RISC_INT); + } else { + WRT_REG_WORD(®->isp.semaphore, 0); + WRT_REG_WORD(®->isp.hccr, HCCR_CLR_RISC_INT); + WRT_REG_WORD(®->isp.hccr, HCCR_CLR_HOST_INT); + + /* Enable proper parity */ + if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) { + if (IS_QLA2300(ha)) + /* SRAM parity */ + WRT_REG_WORD(®->isp.hccr, + (HCCR_ENABLE_PARITY + 0x1)); + else + /* SRAM, Instruction RAM and GP RAM parity */ + WRT_REG_WORD(®->isp.hccr, + (HCCR_ENABLE_PARITY + 0x7)); + } + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + ha->isp_ops->enable_intrs(ha); + pci_set_drvdata(pdev, ha); ha->flags.init_done = 1; @@ -1836,14 +1848,10 @@ qla2x00_remove_one(struct pci_dev *pdev) static void qla2x00_free_device(scsi_qla_host_t *ha) { - qla2x00_abort_all_cmds(ha, DID_NO_CONNECT << 16); - /* Disable timer */ if (ha->timer_active) qla2x00_stop_timer(ha); - ha->flags.online = 0; - /* Kill the kernel thread for this host */ if (ha->dpc_thread) { struct task_struct *t = ha->dpc_thread; @@ -1862,6 +1870,8 @@ qla2x00_free_device(scsi_qla_host_t *ha) if (ha->eft) qla2x00_disable_eft_trace(ha); + ha->flags.online = 0; + /* Stop currently executing firmware. */ qla2x00_try_to_stop_firmware(ha); @@ -2000,109 +2010,196 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer) * * Returns: * 0 = success. -* !0 = failure. +* 1 = failure. */ -static int +static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *ha) { char name[16]; + uint8_t status = 1; + int retry= 10; - ha->request_ring = dma_alloc_coherent(&ha->pdev->dev, - (ha->request_q_length + 1) * sizeof(request_t), &ha->request_dma, - GFP_KERNEL); - if (!ha->request_ring) - goto fail; - - ha->response_ring = dma_alloc_coherent(&ha->pdev->dev, - (ha->response_q_length + 1) * sizeof(response_t), - &ha->response_dma, GFP_KERNEL); - if (!ha->response_ring) - goto fail_free_request_ring; - - ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE, - &ha->gid_list_dma, GFP_KERNEL); - if (!ha->gid_list) - goto fail_free_response_ring; - - ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, ha->init_cb_size, - &ha->init_cb_dma, GFP_KERNEL); - if (!ha->init_cb) - goto fail_free_gid_list; - - snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME, - ha->host_no); - ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev, - DMA_POOL_SIZE, 8, 0); - if (!ha->s_dma_pool) - goto fail_free_init_cb; + do { + /* + * This will loop only once if everything goes well, else some + * number of retries will be performed to get around a kernel + * bug where available mem is not allocated until after a + * little delay and a retry. + */ + ha->request_ring = dma_alloc_coherent(&ha->pdev->dev, + (ha->request_q_length + 1) * sizeof(request_t), + &ha->request_dma, GFP_KERNEL); + if (ha->request_ring == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - request_ring\n"); - ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep); - if (!ha->srb_mempool) - goto fail_free_s_dma_pool; - - /* Get memory for cached NVRAM */ - ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL); - if (!ha->nvram) - goto fail_free_srb_mempool; - - /* Allocate memory for SNS commands */ - if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - /* Get consistent memory allocated for SNS commands */ - ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, GFP_KERNEL); - if (!ha->sns_cmd) - goto fail_free_nvram; - } else { - /* Get consistent memory allocated for MS IOCB */ - ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, - &ha->ms_iocb_dma); - if (!ha->ms_iocb) - goto fail_free_nvram; + qla2x00_mem_free(ha); + msleep(100); - /* Get consistent memory allocated for CT SNS commands */ - ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL); - if (!ha->ct_sns) - goto fail_free_ms_iocb; - } + continue; + } - return 0; + ha->response_ring = dma_alloc_coherent(&ha->pdev->dev, + (ha->response_q_length + 1) * sizeof(response_t), + &ha->response_dma, GFP_KERNEL); + if (ha->response_ring == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - response_ring\n"); -fail_free_ms_iocb: - dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); - ha->ms_iocb = NULL; - ha->ms_iocb_dma = 0; -fail_free_nvram: - kfree(ha->nvram); - ha->nvram = NULL; -fail_free_srb_mempool: - mempool_destroy(ha->srb_mempool); - ha->srb_mempool = NULL; -fail_free_s_dma_pool: - dma_pool_destroy(ha->s_dma_pool); - ha->s_dma_pool = NULL; -fail_free_init_cb: - dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, - ha->init_cb_dma); - ha->init_cb = NULL; - ha->init_cb_dma = 0; -fail_free_gid_list: - dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list, - ha->gid_list_dma); - ha->gid_list = NULL; - ha->gid_list_dma = 0; -fail_free_response_ring: - dma_free_coherent(&ha->pdev->dev, (ha->response_q_length + 1) * - sizeof(response_t), ha->response_ring, ha->response_dma); - ha->response_ring = NULL; - ha->response_dma = 0; -fail_free_request_ring: - dma_free_coherent(&ha->pdev->dev, (ha->request_q_length + 1) * - sizeof(request_t), ha->request_ring, ha->request_dma); - ha->request_ring = NULL; - ha->request_dma = 0; -fail: - return -ENOMEM; + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + + ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE, + &ha->gid_list_dma, GFP_KERNEL); + if (ha->gid_list == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - gid_list\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + + /* get consistent memory allocated for init control block */ + ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, + ha->init_cb_size, &ha->init_cb_dma, GFP_KERNEL); + if (ha->init_cb == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - init_cb\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + memset(ha->init_cb, 0, ha->init_cb_size); + + snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME, + ha->host_no); + ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev, + DMA_POOL_SIZE, 8, 0); + if (ha->s_dma_pool == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - s_dma_pool\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + + if (qla2x00_allocate_sp_pool(ha)) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - " + "qla2x00_allocate_sp_pool()\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + + /* Allocate memory for SNS commands */ + if (IS_QLA2100(ha) || IS_QLA2200(ha)) { + /* Get consistent memory allocated for SNS commands */ + ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, + GFP_KERNEL); + if (ha->sns_cmd == NULL) { + /* error */ + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - sns_cmd\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + memset(ha->sns_cmd, 0, sizeof(struct sns_cmd_pkt)); + } else { + /* Get consistent memory allocated for MS IOCB */ + ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, + &ha->ms_iocb_dma); + if (ha->ms_iocb == NULL) { + /* error */ + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - ms_iocb\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + memset(ha->ms_iocb, 0, sizeof(ms_iocb_entry_t)); + + /* + * Get consistent memory allocated for CT SNS + * commands + */ + ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, + GFP_KERNEL); + if (ha->ct_sns == NULL) { + /* error */ + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - ct_sns\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt)); + + if (IS_FWI2_CAPABLE(ha)) { + /* + * Get consistent memory allocated for SFP + * block. + */ + ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, + GFP_KERNEL, &ha->sfp_data_dma); + if (ha->sfp_data == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - " + "sfp_data\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + memset(ha->sfp_data, 0, SFP_BLOCK_SIZE); + } + } + + /* Get memory for cached NVRAM */ + ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL); + if (ha->nvram == NULL) { + /* error */ + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - nvram cache\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + + /* Done all allocations without any error. */ + status = 0; + + } while (retry-- && status != 0); + + if (status) { + printk(KERN_WARNING + "%s(): **** FAILED ****\n", __func__); + } + + return(status); } /* @@ -2118,8 +2215,14 @@ qla2x00_mem_free(scsi_qla_host_t *ha) struct list_head *fcpl, *fcptemp; fc_port_t *fcport; - if (ha->srb_mempool) - mempool_destroy(ha->srb_mempool); + if (ha == NULL) { + /* error */ + DEBUG2(printk("%s(): ERROR invalid ha pointer.\n", __func__)); + return; + } + + /* free sp pool */ + qla2x00_free_sp_pool(ha); if (ha->fce) dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce, @@ -2167,7 +2270,6 @@ qla2x00_mem_free(scsi_qla_host_t *ha) (ha->request_q_length + 1) * sizeof(request_t), ha->request_ring, ha->request_dma); - ha->srb_mempool = NULL; ha->eft = NULL; ha->eft_dma = 0; ha->sns_cmd = NULL; @@ -2206,6 +2308,44 @@ qla2x00_mem_free(scsi_qla_host_t *ha) kfree(ha->nvram); } +/* + * qla2x00_allocate_sp_pool + * This routine is called during initialization to allocate + * memory for local srb_t. + * + * Input: + * ha = adapter block pointer. + * + * Context: + * Kernel context. + */ +static int +qla2x00_allocate_sp_pool(scsi_qla_host_t *ha) +{ + int rval; + + rval = QLA_SUCCESS; + ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep); + if (ha->srb_mempool == NULL) { + qla_printk(KERN_INFO, ha, "Unable to allocate SRB mempool.\n"); + rval = QLA_FUNCTION_FAILED; + } + return (rval); +} + +/* + * This routine frees all adapter allocated memory. + * + */ +static void +qla2x00_free_sp_pool( scsi_qla_host_t *ha) +{ + if (ha->srb_mempool) { + mempool_destroy(ha->srb_mempool); + ha->srb_mempool = NULL; + } +} + /************************************************************************** * qla2x00_do_dpc * This kernel thread is a task that is schedule by the interrupt handler @@ -2227,9 +2367,6 @@ qla2x00_do_dpc(void *data) fc_port_t *fcport; uint8_t status; uint16_t next_loopid; - struct scsi_qla_host *vha; - int i; - ha = (scsi_qla_host_t *)data; @@ -2272,18 +2409,6 @@ qla2x00_do_dpc(void *data) } clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); } - - for_each_mapped_vp_idx(ha, i) { - list_for_each_entry(vha, &ha->vp_list, - vp_list) { - if (i == vha->vp_idx) { - set_bit(ISP_ABORT_NEEDED, - &vha->dpc_flags); - break; - } - } - } - DEBUG(printk("scsi(%ld): dpc: qla2x00_abort_isp end\n", ha->host_no)); } @@ -2904,4 +3029,3 @@ MODULE_FIRMWARE(FW_FILE_ISP22XX); MODULE_FIRMWARE(FW_FILE_ISP2300); MODULE_FIRMWARE(FW_FILE_ISP2322); MODULE_FIRMWARE(FW_FILE_ISP24XX); -MODULE_FIRMWARE(FW_FILE_ISP25XX); diff --git a/trunk/drivers/scsi/qla2xxx/qla_sup.c b/trunk/drivers/scsi/qla2xxx/qla_sup.c index 26822c8807ee..b68fb73613ed 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_sup.c +++ b/trunk/drivers/scsi/qla2xxx/qla_sup.c @@ -893,8 +893,6 @@ qla2x00_flip_colors(scsi_qla_host_t *ha, uint16_t *pflags) } } -#define PIO_REG(h, r) ((h)->pio_address + offsetof(struct device_reg_2xxx, r)) - void qla2x00_beacon_blink(struct scsi_qla_host *ha) { @@ -904,12 +902,15 @@ qla2x00_beacon_blink(struct scsi_qla_host *ha) unsigned long flags; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + if (ha->pio_address) + reg = (struct device_reg_2xxx __iomem *)ha->pio_address; + spin_lock_irqsave(&ha->hardware_lock, flags); /* Save the Original GPIOE. */ if (ha->pio_address) { - gpio_enable = RD_REG_WORD_PIO(PIO_REG(ha, gpioe)); - gpio_data = RD_REG_WORD_PIO(PIO_REG(ha, gpiod)); + gpio_enable = RD_REG_WORD_PIO(®->gpioe); + gpio_data = RD_REG_WORD_PIO(®->gpiod); } else { gpio_enable = RD_REG_WORD(®->gpioe); gpio_data = RD_REG_WORD(®->gpiod); @@ -919,7 +920,7 @@ qla2x00_beacon_blink(struct scsi_qla_host *ha) gpio_enable |= GPIO_LED_MASK; if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, gpioe), gpio_enable); + WRT_REG_WORD_PIO(®->gpioe, gpio_enable); } else { WRT_REG_WORD(®->gpioe, gpio_enable); RD_REG_WORD(®->gpioe); @@ -935,7 +936,7 @@ qla2x00_beacon_blink(struct scsi_qla_host *ha) /* Set the modified gpio_data values */ if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, gpiod), gpio_data); + WRT_REG_WORD_PIO(®->gpiod, gpio_data); } else { WRT_REG_WORD(®->gpiod, gpio_data); RD_REG_WORD(®->gpiod); @@ -961,11 +962,14 @@ qla2x00_beacon_on(struct scsi_qla_host *ha) return QLA_FUNCTION_FAILED; } + if (ha->pio_address) + reg = (struct device_reg_2xxx __iomem *)ha->pio_address; + /* Turn off LEDs. */ spin_lock_irqsave(&ha->hardware_lock, flags); if (ha->pio_address) { - gpio_enable = RD_REG_WORD_PIO(PIO_REG(ha, gpioe)); - gpio_data = RD_REG_WORD_PIO(PIO_REG(ha, gpiod)); + gpio_enable = RD_REG_WORD_PIO(®->gpioe); + gpio_data = RD_REG_WORD_PIO(®->gpiod); } else { gpio_enable = RD_REG_WORD(®->gpioe); gpio_data = RD_REG_WORD(®->gpiod); @@ -974,7 +978,7 @@ qla2x00_beacon_on(struct scsi_qla_host *ha) /* Set the modified gpio_enable values. */ if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, gpioe), gpio_enable); + WRT_REG_WORD_PIO(®->gpioe, gpio_enable); } else { WRT_REG_WORD(®->gpioe, gpio_enable); RD_REG_WORD(®->gpioe); @@ -983,7 +987,7 @@ qla2x00_beacon_on(struct scsi_qla_host *ha) /* Clear out previously set LED colour. */ gpio_data &= ~GPIO_LED_MASK; if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, gpiod), gpio_data); + WRT_REG_WORD_PIO(®->gpiod, gpio_data); } else { WRT_REG_WORD(®->gpiod, gpio_data); RD_REG_WORD(®->gpiod); @@ -1240,12 +1244,13 @@ qla2x00_read_flash_byte(scsi_qla_host_t *ha, uint32_t addr) if (ha->pio_address) { uint16_t data2; - WRT_REG_WORD_PIO(PIO_REG(ha, flash_address), (uint16_t)addr); + reg = (struct device_reg_2xxx __iomem *)ha->pio_address; + WRT_REG_WORD_PIO(®->flash_address, (uint16_t)addr); do { - data = RD_REG_WORD_PIO(PIO_REG(ha, flash_data)); + data = RD_REG_WORD_PIO(®->flash_data); barrier(); cpu_relax(); - data2 = RD_REG_WORD_PIO(PIO_REG(ha, flash_data)); + data2 = RD_REG_WORD_PIO(®->flash_data); } while (data != data2); } else { WRT_REG_WORD(®->flash_address, (uint16_t)addr); @@ -1299,8 +1304,9 @@ qla2x00_write_flash_byte(scsi_qla_host_t *ha, uint32_t addr, uint8_t data) /* Always perform IO mapped accesses to the FLASH registers. */ if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, flash_address), (uint16_t)addr); - WRT_REG_WORD_PIO(PIO_REG(ha, flash_data), (uint16_t)data); + reg = (struct device_reg_2xxx __iomem *)ha->pio_address; + WRT_REG_WORD_PIO(®->flash_address, (uint16_t)addr); + WRT_REG_WORD_PIO(®->flash_data, (uint16_t)data); } else { WRT_REG_WORD(®->flash_address, (uint16_t)addr); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ diff --git a/trunk/drivers/scsi/qla2xxx/qla_version.h b/trunk/drivers/scsi/qla2xxx/qla_version.h index c5742cc15abb..2c2f6b4697c7 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_version.h +++ b/trunk/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.02.00-k8" +#define QLA2XXX_VERSION "8.02.00-k7" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 2 diff --git a/trunk/drivers/scsi/qla4xxx/ql4_init.c b/trunk/drivers/scsi/qla4xxx/ql4_init.c index 10b3b9a620f3..49925f92555e 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_init.c +++ b/trunk/drivers/scsi/qla4xxx/ql4_init.c @@ -1306,7 +1306,6 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, atomic_set(&ddb_entry->relogin_timer, 0); clear_bit(DF_RELOGIN, &ddb_entry->flags); clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); - iscsi_unblock_session(ddb_entry->sess); iscsi_session_event(ddb_entry->sess, ISCSI_KEVENT_CREATE_SESSION); /* diff --git a/trunk/drivers/scsi/qla4xxx/ql4_os.c b/trunk/drivers/scsi/qla4xxx/ql4_os.c index c3c59d763037..2e2b9fedffcc 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_os.c +++ b/trunk/drivers/scsi/qla4xxx/ql4_os.c @@ -63,6 +63,8 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, enum iscsi_param param, char *buf); static int qla4xxx_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf); +static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag); +static int qla4xxx_conn_start(struct iscsi_cls_conn *conn); static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session); /* @@ -89,8 +91,6 @@ static struct scsi_host_template qla4xxx_driver_template = { .slave_alloc = qla4xxx_slave_alloc, .slave_destroy = qla4xxx_slave_destroy, - .scan_finished = iscsi_scan_finished, - .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, @@ -116,6 +116,8 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { .get_conn_param = qla4xxx_conn_get_param, .get_session_param = qla4xxx_sess_get_param, .get_host_param = qla4xxx_host_get_param, + .start_conn = qla4xxx_conn_start, + .stop_conn = qla4xxx_conn_stop, .session_recovery_timedout = qla4xxx_recovery_timedout, }; @@ -126,19 +128,48 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) struct ddb_entry *ddb_entry = session->dd_data; struct scsi_qla_host *ha = ddb_entry->ha; - if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { - atomic_set(&ddb_entry->state, DDB_STATE_DEAD); + DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count of (%d) " + "secs exhausted, marking device DEAD.\n", ha->host_no, + __func__, ddb_entry->fw_ddb_index, + ha->port_down_retry_count)); - DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count " - "of (%d) secs exhausted, marking device DEAD.\n", - ha->host_no, __func__, ddb_entry->fw_ddb_index, - ha->port_down_retry_count)); + atomic_set(&ddb_entry->state, DDB_STATE_DEAD); - DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc " - "flags = 0x%lx\n", - ha->host_no, __func__, ha->dpc_flags)); - queue_work(ha->dpc_thread, &ha->dpc_work); - } + DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc flags = " + "0x%lx\n", ha->host_no, __func__, ha->dpc_flags)); + queue_work(ha->dpc_thread, &ha->dpc_work); +} + +static int qla4xxx_conn_start(struct iscsi_cls_conn *conn) +{ + struct iscsi_cls_session *session; + struct ddb_entry *ddb_entry; + + session = iscsi_dev_to_session(conn->dev.parent); + ddb_entry = session->dd_data; + + DEBUG2(printk("scsi%ld: %s: index [%d] starting conn\n", + ddb_entry->ha->host_no, __func__, + ddb_entry->fw_ddb_index)); + iscsi_unblock_session(session); + return 0; +} + +static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag) +{ + struct iscsi_cls_session *session; + struct ddb_entry *ddb_entry; + + session = iscsi_dev_to_session(conn->dev.parent); + ddb_entry = session->dd_data; + + DEBUG2(printk("scsi%ld: %s: index [%d] stopping conn\n", + ddb_entry->ha->host_no, __func__, + ddb_entry->fw_ddb_index)); + if (flag == STOP_CONN_RECOVER) + iscsi_block_session(session); + else + printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); } static int qla4xxx_host_get_param(struct Scsi_Host *shost, @@ -277,9 +308,6 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) DEBUG2(printk(KERN_ERR "Could not add connection.\n")); return -ENOMEM; } - - /* finally ready to go */ - iscsi_unblock_session(ddb_entry->sess); return 0; } @@ -336,7 +364,6 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n", ha->host_no, ddb_entry->bus, ddb_entry->target, ddb_entry->fw_ddb_index)); - iscsi_block_session(ddb_entry->sess); iscsi_conn_error(ddb_entry->conn, ISCSI_ERR_CONN_FAILED); } @@ -403,21 +430,9 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, { struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; - struct iscsi_cls_session *sess = ddb_entry->sess; struct srb *srb; int rval; - if (!sess) { - cmd->result = DID_IMM_RETRY << 16; - goto qc_fail_command; - } - - rval = iscsi_session_chkready(sess); - if (rval) { - cmd->result = rval; - goto qc_fail_command; - } - if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) { cmd->result = DID_NO_CONNECT << 16; @@ -1308,7 +1323,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), ha->host_no, ha->firmware_version[0], ha->firmware_version[1], ha->patch_number, ha->build_number); - scsi_scan_host(host); + return 0; remove_host: diff --git a/trunk/drivers/scsi/scsi.c b/trunk/drivers/scsi/scsi.c index fecba05b4e77..b35d19472caa 100644 --- a/trunk/drivers/scsi/scsi.c +++ b/trunk/drivers/scsi/scsi.c @@ -969,10 +969,9 @@ void starget_for_each_device(struct scsi_target *starget, void *data, EXPORT_SYMBOL(starget_for_each_device); /** - * __starget_for_each_device - helper to walk all devices of a target (UNLOCKED) + * __starget_for_each_device - helper to walk all devices of a target + * (UNLOCKED) * @starget: target whose devices we want to iterate over. - * @data: parameter for callback @fn() - * @fn: callback function that is invoked for each device * * This traverses over each device of @starget. It does _not_ * take a reference on the scsi_device, so the whole loop must be diff --git a/trunk/drivers/scsi/scsi_lib.c b/trunk/drivers/scsi/scsi_lib.c index 135c1d054701..f243fc30c908 100644 --- a/trunk/drivers/scsi/scsi_lib.c +++ b/trunk/drivers/scsi/scsi_lib.c @@ -301,6 +301,7 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, page = sg_page(sg); off = sg->offset; len = sg->length; + data_len += len; while (len > 0 && data_len > 0) { /* diff --git a/trunk/drivers/scsi/scsi_transport_iscsi.c b/trunk/drivers/scsi/scsi_transport_iscsi.c index fac7534f3ec4..0d7b4e79415c 100644 --- a/trunk/drivers/scsi/scsi_transport_iscsi.c +++ b/trunk/drivers/scsi/scsi_transport_iscsi.c @@ -30,10 +30,10 @@ #include #include -#define ISCSI_SESSION_ATTRS 19 -#define ISCSI_CONN_ATTRS 13 +#define ISCSI_SESSION_ATTRS 18 +#define ISCSI_CONN_ATTRS 11 #define ISCSI_HOST_ATTRS 4 -#define ISCSI_TRANSPORT_VERSION "2.0-868" +#define ISCSI_TRANSPORT_VERSION "2.0-867" struct iscsi_internal { int daemon_pid; @@ -127,13 +127,12 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, memset(ihost, 0, sizeof(*ihost)); INIT_LIST_HEAD(&ihost->sessions); mutex_init(&ihost->mutex); - atomic_set(&ihost->nr_scans, 0); - snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", + snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d", shost->host_no); - ihost->scan_workq = create_singlethread_workqueue( - ihost->scan_workq_name); - if (!ihost->scan_workq) + ihost->unbind_workq = create_singlethread_workqueue( + ihost->unbind_workq_name); + if (!ihost->unbind_workq) return -ENOMEM; return 0; } @@ -144,7 +143,7 @@ static int iscsi_remove_host(struct transport_container *tc, struct device *dev, struct Scsi_Host *shost = dev_to_shost(dev); struct iscsi_host *ihost = shost->shost_data; - destroy_workqueue(ihost->scan_workq); + destroy_workqueue(ihost->unbind_workq); return 0; } @@ -222,54 +221,6 @@ static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid) * The following functions can be used by LLDs that allocate * their own scsi_hosts or by software iscsi LLDs */ -static struct { - int value; - char *name; -} iscsi_session_state_names[] = { - { ISCSI_SESSION_LOGGED_IN, "LOGGED_IN" }, - { ISCSI_SESSION_FAILED, "FAILED" }, - { ISCSI_SESSION_FREE, "FREE" }, -}; - -const char *iscsi_session_state_name(int state) -{ - int i; - char *name = NULL; - - for (i = 0; i < ARRAY_SIZE(iscsi_session_state_names); i++) { - if (iscsi_session_state_names[i].value == state) { - name = iscsi_session_state_names[i].name; - break; - } - } - return name; -} - -int iscsi_session_chkready(struct iscsi_cls_session *session) -{ - unsigned long flags; - int err; - - spin_lock_irqsave(&session->lock, flags); - switch (session->state) { - case ISCSI_SESSION_LOGGED_IN: - err = 0; - break; - case ISCSI_SESSION_FAILED: - err = DID_IMM_RETRY << 16; - break; - case ISCSI_SESSION_FREE: - err = DID_NO_CONNECT << 16; - break; - default: - err = DID_NO_CONNECT << 16; - break; - } - spin_unlock_irqrestore(&session->lock, flags); - return err; -} -EXPORT_SYMBOL_GPL(iscsi_session_chkready); - static void iscsi_session_release(struct device *dev) { struct iscsi_cls_session *session = iscsi_dev_to_session(dev); @@ -285,25 +236,6 @@ static int iscsi_is_session_dev(const struct device *dev) return dev->release == iscsi_session_release; } -/** - * iscsi_scan_finished - helper to report when running scans are done - * @shost: scsi host - * @time: scan run time - * - * This function can be used by drives like qla4xxx to report to the scsi - * layer when the scans it kicked off at module load time are done. - */ -int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - struct iscsi_host *ihost = shost->shost_data; - /* - * qla4xxx will have kicked off some session unblocks before calling - * scsi_scan_host, so just wait for them to complete. - */ - return !atomic_read(&ihost->nr_scans); -} -EXPORT_SYMBOL_GPL(iscsi_scan_finished); - static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, uint id, uint lun) { @@ -322,50 +254,14 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, return 0; } -static void iscsi_scan_session(struct work_struct *work) -{ - struct iscsi_cls_session *session = - container_of(work, struct iscsi_cls_session, scan_work); - struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_host *ihost = shost->shost_data; - unsigned long flags; - - spin_lock_irqsave(&session->lock, flags); - if (session->state != ISCSI_SESSION_LOGGED_IN) { - spin_unlock_irqrestore(&session->lock, flags); - goto done; - } - spin_unlock_irqrestore(&session->lock, flags); - - scsi_scan_target(&session->dev, 0, session->target_id, - SCAN_WILD_CARD, 1); -done: - atomic_dec(&ihost->nr_scans); -} - static void session_recovery_timedout(struct work_struct *work) { struct iscsi_cls_session *session = container_of(work, struct iscsi_cls_session, recovery_work.work); - unsigned long flags; - - iscsi_cls_session_printk(KERN_INFO, session, - "session recovery timed out after %d secs\n", - session->recovery_tmo); - spin_lock_irqsave(&session->lock, flags); - switch (session->state) { - case ISCSI_SESSION_FAILED: - session->state = ISCSI_SESSION_FREE; - break; - case ISCSI_SESSION_LOGGED_IN: - case ISCSI_SESSION_FREE: - /* we raced with the unblock's flush */ - spin_unlock_irqrestore(&session->lock, flags); - return; - } - spin_unlock_irqrestore(&session->lock, flags); + dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed " + "out after %d secs\n", session->recovery_tmo); if (session->transport->session_recovery_timedout) session->transport->session_recovery_timedout(session); @@ -373,44 +269,16 @@ static void session_recovery_timedout(struct work_struct *work) scsi_target_unblock(&session->dev); } -void __iscsi_unblock_session(struct iscsi_cls_session *session) +void iscsi_unblock_session(struct iscsi_cls_session *session) { if (!cancel_delayed_work(&session->recovery_work)) flush_workqueue(iscsi_eh_timer_workq); scsi_target_unblock(&session->dev); } - -void iscsi_unblock_session(struct iscsi_cls_session *session) -{ - struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_host *ihost = shost->shost_data; - unsigned long flags; - - spin_lock_irqsave(&session->lock, flags); - session->state = ISCSI_SESSION_LOGGED_IN; - spin_unlock_irqrestore(&session->lock, flags); - - __iscsi_unblock_session(session); - /* - * Only do kernel scanning if the driver is properly hooked into - * the async scanning code (drivers like iscsi_tcp do login and - * scanning from userspace). - */ - if (shost->hostt->scan_finished) { - if (queue_work(ihost->scan_workq, &session->scan_work)) - atomic_inc(&ihost->nr_scans); - } -} EXPORT_SYMBOL_GPL(iscsi_unblock_session); void iscsi_block_session(struct iscsi_cls_session *session) { - unsigned long flags; - - spin_lock_irqsave(&session->lock, flags); - session->state = ISCSI_SESSION_FAILED; - spin_unlock_irqrestore(&session->lock, flags); - scsi_target_block(&session->dev); queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work, session->recovery_tmo * HZ); @@ -443,7 +311,7 @@ static int iscsi_unbind_session(struct iscsi_cls_session *session) struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_host *ihost = shost->shost_data; - return queue_work(ihost->scan_workq, &session->unbind_work); + return queue_work(ihost->unbind_workq, &session->unbind_work); } struct iscsi_cls_session * @@ -459,13 +327,10 @@ iscsi_alloc_session(struct Scsi_Host *shost, session->transport = transport; session->recovery_tmo = 120; - session->state = ISCSI_SESSION_FREE; INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); INIT_WORK(&session->unbind_work, __iscsi_unbind_session); - INIT_WORK(&session->scan_work, iscsi_scan_session); - spin_lock_init(&session->lock); /* this is released in the dev's release function */ scsi_host_get(shost); @@ -493,8 +358,8 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) session->sid); err = device_add(&session->dev); if (err) { - iscsi_cls_session_printk(KERN_ERR, session, - "could not register session's dev\n"); + dev_printk(KERN_ERR, &session->dev, "iscsi: could not " + "register session's dev\n"); goto release_host; } transport_register_device(&session->dev); @@ -579,28 +444,22 @@ void iscsi_remove_session(struct iscsi_cls_session *session) * If we are blocked let commands flow again. The lld or iscsi * layer should set up the queuecommand to fail commands. */ - spin_lock_irqsave(&session->lock, flags); - session->state = ISCSI_SESSION_FREE; - spin_unlock_irqrestore(&session->lock, flags); - __iscsi_unblock_session(session); - __iscsi_unbind_session(&session->unbind_work); - - /* flush running scans */ - flush_workqueue(ihost->scan_workq); + iscsi_unblock_session(session); + iscsi_unbind_session(session); /* * If the session dropped while removing devices then we need to make * sure it is not blocked */ if (!cancel_delayed_work(&session->recovery_work)) flush_workqueue(iscsi_eh_timer_workq); + flush_workqueue(ihost->unbind_workq); /* hw iscsi may not have removed all connections from session */ err = device_for_each_child(&session->dev, NULL, iscsi_iter_destroy_conn_fn); if (err) - iscsi_cls_session_printk(KERN_ERR, session, - "Could not delete all connections " - "for session. Error %d.\n", err); + dev_printk(KERN_ERR, &session->dev, "iscsi: Could not delete " + "all connections for session. Error %d.\n", err); transport_unregister_device(&session->dev); device_del(&session->dev); @@ -672,8 +531,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) conn->dev.release = iscsi_conn_release; err = device_register(&conn->dev); if (err) { - iscsi_cls_session_printk(KERN_ERR, session, "could not " - "register connection's dev\n"); + dev_printk(KERN_ERR, &conn->dev, "iscsi: could not register " + "connection's dev\n"); goto release_parent_ref; } transport_register_device(&conn->dev); @@ -780,8 +639,8 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { iscsi_conn_error(conn, ISCSI_ERR_CONN_FAILED); - iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver " - "control PDU: OOM\n"); + dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver " + "control PDU: OOM\n"); return -ENOMEM; } @@ -802,27 +661,20 @@ EXPORT_SYMBOL_GPL(iscsi_recv_pdu); void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) { - struct iscsi_cls_session *session = iscsi_conn_to_session(conn); struct nlmsghdr *nlh; struct sk_buff *skb; struct iscsi_uevent *ev; struct iscsi_internal *priv; int len = NLMSG_SPACE(sizeof(*ev)); - unsigned long flags; priv = iscsi_if_transport_lookup(conn->transport); if (!priv) return; - spin_lock_irqsave(&session->lock, flags); - if (session->state == ISCSI_SESSION_LOGGED_IN) - session->state = ISCSI_SESSION_FAILED; - spin_unlock_irqrestore(&session->lock, flags); - skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { - iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored " - "conn error (%d)\n", error); + dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored " + "conn error (%d)\n", error); return; } @@ -836,8 +688,8 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) iscsi_broadcast_skb(skb, GFP_ATOMIC); - iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n", - error); + dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", + error); } EXPORT_SYMBOL_GPL(iscsi_conn_error); @@ -892,8 +744,8 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) skbstat = alloc_skb(len, GFP_ATOMIC); if (!skbstat) { - iscsi_cls_conn_printk(KERN_ERR, conn, "can not " - "deliver stats: OOM\n"); + dev_printk(KERN_ERR, &conn->dev, "iscsi: can not " + "deliver stats: OOM\n"); return -ENOMEM; } @@ -949,9 +801,8 @@ int iscsi_session_event(struct iscsi_cls_session *session, skb = alloc_skb(len, GFP_KERNEL); if (!skb) { - iscsi_cls_session_printk(KERN_ERR, session, - "Cannot notify userspace of session " - "event %u\n", event); + dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace " + "of session event %u\n", event); return -ENOMEM; } @@ -974,8 +825,8 @@ int iscsi_session_event(struct iscsi_cls_session *session, ev->r.unbind_session.sid = session->sid; break; default: - iscsi_cls_session_printk(KERN_ERR, session, "Invalid event " - "%u.\n", event); + dev_printk(KERN_ERR, &session->dev, "Invalid event %u.\n", + event); kfree_skb(skb); return -EINVAL; } @@ -986,10 +837,8 @@ int iscsi_session_event(struct iscsi_cls_session *session, */ rc = iscsi_broadcast_skb(skb, GFP_KERNEL); if (rc < 0) - iscsi_cls_session_printk(KERN_ERR, session, - "Cannot notify userspace of session " - "event %u. Check iscsi daemon\n", - event); + dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace " + "of session event %u. Check iscsi daemon\n", event); return rc; } EXPORT_SYMBOL_GPL(iscsi_session_event); @@ -1022,15 +871,16 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) session = iscsi_session_lookup(ev->u.c_conn.sid); if (!session) { - printk(KERN_ERR "iscsi: invalid session %d.\n", + printk(KERN_ERR "iscsi: invalid session %d\n", ev->u.c_conn.sid); return -EINVAL; } conn = transport->create_conn(session, ev->u.c_conn.cid); if (!conn) { - iscsi_cls_session_printk(KERN_ERR, session, - "couldn't create a new connection."); + printk(KERN_ERR "iscsi: couldn't create a new " + "connection for session %d\n", + session->sid); return -ENOMEM; } @@ -1396,15 +1246,6 @@ iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0); iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); -static ssize_t -show_priv_session_state(struct class_device *cdev, char *buf) -{ - struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); - return sprintf(buf, "%s\n", iscsi_session_state_name(session->state)); -} -static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state, - NULL); - #define iscsi_priv_session_attr_show(field, format) \ static ssize_t \ show_priv_session_##field(struct class_device *cdev, char *buf) \ @@ -1631,7 +1472,6 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO); SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO); SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); - SETUP_PRIV_SESSION_RD_ATTR(state); BUG_ON(count > ISCSI_SESSION_ATTRS); priv->session_attrs[count] = NULL; diff --git a/trunk/drivers/scsi/sd.c b/trunk/drivers/scsi/sd.c index 37df8bbe7f46..51a5557f42dd 100644 --- a/trunk/drivers/scsi/sd.c +++ b/trunk/drivers/scsi/sd.c @@ -929,7 +929,6 @@ static int sd_done(struct scsi_cmnd *SCpnt) unsigned int xfer_size = scsi_bufflen(SCpnt); unsigned int good_bytes = result ? 0 : xfer_size; u64 start_lba = SCpnt->request->sector; - u64 end_lba = SCpnt->request->sector + (xfer_size / 512); u64 bad_lba; struct scsi_sense_hdr sshdr; int sense_valid = 0; @@ -968,23 +967,26 @@ static int sd_done(struct scsi_cmnd *SCpnt) goto out; if (xfer_size <= SCpnt->device->sector_size) goto out; - if (SCpnt->device->sector_size < 512) { - /* only legitimate sector_size here is 256 */ + switch (SCpnt->device->sector_size) { + case 256: start_lba <<= 1; - end_lba <<= 1; - } else { - /* be careful ... don't want any overflows */ - u64 factor = SCpnt->device->sector_size / 512; - do_div(start_lba, factor); - do_div(end_lba, factor); - } - - if (bad_lba < start_lba || bad_lba >= end_lba) - /* the bad lba was reported incorrectly, we have - * no idea where the error is - */ + break; + case 512: + break; + case 1024: + start_lba >>= 1; + break; + case 2048: + start_lba >>= 2; + break; + case 4096: + start_lba >>= 3; + break; + default: + /* Print something here with limiting frequency. */ goto out; - + break; + } /* This computation should always be done in terms of * the resolution of the device's medium. */ diff --git a/trunk/drivers/scsi/ses.c b/trunk/drivers/scsi/ses.c deleted file mode 100644 index 2a6e4f472eaa..000000000000 --- a/trunk/drivers/scsi/ses.c +++ /dev/null @@ -1,689 +0,0 @@ -/* - * SCSI Enclosure Services - * - * Copyright (C) 2008 James Bottomley - * -**----------------------------------------------------------------------------- -** -** This program is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License -** version 2 as published by the Free Software Foundation. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -**----------------------------------------------------------------------------- -*/ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -struct ses_device { - char *page1; - char *page2; - char *page10; - short page1_len; - short page2_len; - short page10_len; -}; - -struct ses_component { - u64 addr; - unsigned char *desc; -}; - -static int ses_probe(struct device *dev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - int err = -ENODEV; - - if (sdev->type != TYPE_ENCLOSURE) - goto out; - - err = 0; - sdev_printk(KERN_NOTICE, sdev, "Attached Enclosure device\n"); - - out: - return err; -} - -#define SES_TIMEOUT 30 -#define SES_RETRIES 3 - -static int ses_recv_diag(struct scsi_device *sdev, int page_code, - void *buf, int bufflen) -{ - char cmd[] = { - RECEIVE_DIAGNOSTIC, - 1, /* Set PCV bit */ - page_code, - bufflen >> 8, - bufflen & 0xff, - 0 - }; - - return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen, - NULL, SES_TIMEOUT, SES_RETRIES); -} - -static int ses_send_diag(struct scsi_device *sdev, int page_code, - void *buf, int bufflen) -{ - u32 result; - - char cmd[] = { - SEND_DIAGNOSTIC, - 0x10, /* Set PF bit */ - 0, - bufflen >> 8, - bufflen & 0xff, - 0 - }; - - result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, buf, bufflen, - NULL, SES_TIMEOUT, SES_RETRIES); - if (result) - sdev_printk(KERN_ERR, sdev, "SEND DIAGNOSTIC result: %8x\n", - result); - return result; -} - -static int ses_set_page2_descriptor(struct enclosure_device *edev, - struct enclosure_component *ecomp, - char *desc) -{ - int i, j, count = 0, descriptor = ecomp->number; - struct scsi_device *sdev = to_scsi_device(edev->cdev.dev); - struct ses_device *ses_dev = edev->scratch; - char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; - char *desc_ptr = ses_dev->page2 + 8; - - /* Clear everything */ - memset(desc_ptr, 0, ses_dev->page2_len - 8); - for (i = 0; i < ses_dev->page1[10]; i++, type_ptr += 4) { - for (j = 0; j < type_ptr[1]; j++) { - desc_ptr += 4; - if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && - type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) - continue; - if (count++ == descriptor) { - memcpy(desc_ptr, desc, 4); - /* set select */ - desc_ptr[0] |= 0x80; - /* clear reserved, just in case */ - desc_ptr[0] &= 0xf0; - } - } - } - - return ses_send_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); -} - -static char *ses_get_page2_descriptor(struct enclosure_device *edev, - struct enclosure_component *ecomp) -{ - int i, j, count = 0, descriptor = ecomp->number; - struct scsi_device *sdev = to_scsi_device(edev->cdev.dev); - struct ses_device *ses_dev = edev->scratch; - char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; - char *desc_ptr = ses_dev->page2 + 8; - - ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); - - for (i = 0; i < ses_dev->page1[10]; i++, type_ptr += 4) { - for (j = 0; j < type_ptr[1]; j++) { - desc_ptr += 4; - if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && - type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) - continue; - if (count++ == descriptor) - return desc_ptr; - } - } - return NULL; -} - -static void ses_get_fault(struct enclosure_device *edev, - struct enclosure_component *ecomp) -{ - char *desc; - - desc = ses_get_page2_descriptor(edev, ecomp); - ecomp->fault = (desc[3] & 0x60) >> 4; -} - -static int ses_set_fault(struct enclosure_device *edev, - struct enclosure_component *ecomp, - enum enclosure_component_setting val) -{ - char desc[4] = {0 }; - - switch (val) { - case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ - break; - case ENCLOSURE_SETTING_ENABLED: - desc[2] = 0x02; - break; - default: - /* SES doesn't do the SGPIO blink settings */ - return -EINVAL; - } - - return ses_set_page2_descriptor(edev, ecomp, desc); -} - -static void ses_get_status(struct enclosure_device *edev, - struct enclosure_component *ecomp) -{ - char *desc; - - desc = ses_get_page2_descriptor(edev, ecomp); - ecomp->status = (desc[0] & 0x0f); -} - -static void ses_get_locate(struct enclosure_device *edev, - struct enclosure_component *ecomp) -{ - char *desc; - - desc = ses_get_page2_descriptor(edev, ecomp); - ecomp->locate = (desc[2] & 0x02) ? 1 : 0; -} - -static int ses_set_locate(struct enclosure_device *edev, - struct enclosure_component *ecomp, - enum enclosure_component_setting val) -{ - char desc[4] = {0 }; - - switch (val) { - case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ - break; - case ENCLOSURE_SETTING_ENABLED: - desc[2] = 0x02; - break; - default: - /* SES doesn't do the SGPIO blink settings */ - return -EINVAL; - } - return ses_set_page2_descriptor(edev, ecomp, desc); -} - -static int ses_set_active(struct enclosure_device *edev, - struct enclosure_component *ecomp, - enum enclosure_component_setting val) -{ - char desc[4] = {0 }; - - switch (val) { - case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ - ecomp->active = 0; - break; - case ENCLOSURE_SETTING_ENABLED: - desc[2] = 0x80; - ecomp->active = 1; - break; - default: - /* SES doesn't do the SGPIO blink settings */ - return -EINVAL; - } - return ses_set_page2_descriptor(edev, ecomp, desc); -} - -static struct enclosure_component_callbacks ses_enclosure_callbacks = { - .get_fault = ses_get_fault, - .set_fault = ses_set_fault, - .get_status = ses_get_status, - .get_locate = ses_get_locate, - .set_locate = ses_set_locate, - .set_active = ses_set_active, -}; - -struct ses_host_edev { - struct Scsi_Host *shost; - struct enclosure_device *edev; -}; - -int ses_match_host(struct enclosure_device *edev, void *data) -{ - struct ses_host_edev *sed = data; - struct scsi_device *sdev; - - if (!scsi_is_sdev_device(edev->cdev.dev)) - return 0; - - sdev = to_scsi_device(edev->cdev.dev); - - if (sdev->host != sed->shost) - return 0; - - sed->edev = edev; - return 1; -} - -static void ses_process_descriptor(struct enclosure_component *ecomp, - unsigned char *desc) -{ - int eip = desc[0] & 0x10; - int invalid = desc[0] & 0x80; - enum scsi_protocol proto = desc[0] & 0x0f; - u64 addr = 0; - struct ses_component *scomp = ecomp->scratch; - unsigned char *d; - - scomp->desc = desc; - - if (invalid) - return; - - switch (proto) { - case SCSI_PROTOCOL_SAS: - if (eip) - d = desc + 8; - else - d = desc + 4; - /* only take the phy0 addr */ - addr = (u64)d[12] << 56 | - (u64)d[13] << 48 | - (u64)d[14] << 40 | - (u64)d[15] << 32 | - (u64)d[16] << 24 | - (u64)d[17] << 16 | - (u64)d[18] << 8 | - (u64)d[19]; - break; - default: - /* FIXME: Need to add more protocols than just SAS */ - break; - } - scomp->addr = addr; -} - -struct efd { - u64 addr; - struct device *dev; -}; - -static int ses_enclosure_find_by_addr(struct enclosure_device *edev, - void *data) -{ - struct efd *efd = data; - int i; - struct ses_component *scomp; - - if (!edev->component[0].scratch) - return 0; - - for (i = 0; i < edev->components; i++) { - scomp = edev->component[i].scratch; - if (scomp->addr != efd->addr) - continue; - - enclosure_add_device(edev, i, efd->dev); - return 1; - } - return 0; -} - -#define VPD_INQUIRY_SIZE 512 - -static void ses_match_to_enclosure(struct enclosure_device *edev, - struct scsi_device *sdev) -{ - unsigned char *buf = kmalloc(VPD_INQUIRY_SIZE, GFP_KERNEL); - unsigned char *desc; - int len; - struct efd efd = { - .addr = 0, - }; - unsigned char cmd[] = { - INQUIRY, - 1, - 0x83, - VPD_INQUIRY_SIZE >> 8, - VPD_INQUIRY_SIZE & 0xff, - 0 - }; - - if (!buf) - return; - - if (scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, - VPD_INQUIRY_SIZE, NULL, SES_TIMEOUT, SES_RETRIES)) - goto free; - - len = (buf[2] << 8) + buf[3]; - desc = buf + 4; - while (desc < buf + len) { - enum scsi_protocol proto = desc[0] >> 4; - u8 code_set = desc[0] & 0x0f; - u8 piv = desc[1] & 0x80; - u8 assoc = (desc[1] & 0x30) >> 4; - u8 type = desc[1] & 0x0f; - u8 len = desc[3]; - - if (piv && code_set == 1 && assoc == 1 && code_set == 1 - && proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8) - efd.addr = (u64)desc[4] << 56 | - (u64)desc[5] << 48 | - (u64)desc[6] << 40 | - (u64)desc[7] << 32 | - (u64)desc[8] << 24 | - (u64)desc[9] << 16 | - (u64)desc[10] << 8 | - (u64)desc[11]; - - desc += len + 4; - } - if (!efd.addr) - goto free; - - efd.dev = &sdev->sdev_gendev; - - enclosure_for_each_device(ses_enclosure_find_by_addr, &efd); - free: - kfree(buf); -} - -#define INIT_ALLOC_SIZE 32 - -static int ses_intf_add(struct class_device *cdev, - struct class_interface *intf) -{ - struct scsi_device *sdev = to_scsi_device(cdev->dev); - struct scsi_device *tmp_sdev; - unsigned char *buf = NULL, *hdr_buf, *type_ptr, *desc_ptr, - *addl_desc_ptr; - struct ses_device *ses_dev; - u32 result; - int i, j, types, len, components = 0; - int err = -ENOMEM; - struct enclosure_device *edev; - struct ses_component *scomp; - - if (!scsi_device_enclosure(sdev)) { - /* not an enclosure, but might be in one */ - edev = enclosure_find(&sdev->host->shost_gendev); - if (edev) { - ses_match_to_enclosure(edev, sdev); - class_device_put(&edev->cdev); - } - return -ENODEV; - } - - /* TYPE_ENCLOSURE prints a message in probe */ - if (sdev->type != TYPE_ENCLOSURE) - sdev_printk(KERN_NOTICE, sdev, "Embedded Enclosure Device\n"); - - ses_dev = kzalloc(sizeof(*ses_dev), GFP_KERNEL); - hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); - if (!hdr_buf || !ses_dev) - goto err_init_free; - - result = ses_recv_diag(sdev, 1, hdr_buf, INIT_ALLOC_SIZE); - if (result) - goto recv_failed; - - if (hdr_buf[1] != 0) { - /* FIXME: need subenclosure support; I've just never - * seen a device with subenclosures and it makes the - * traversal routines more complex */ - sdev_printk(KERN_ERR, sdev, - "FIXME driver has no support for subenclosures (%d)\n", - buf[1]); - goto err_free; - } - - len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; - buf = kzalloc(len, GFP_KERNEL); - if (!buf) - goto err_free; - - ses_dev->page1 = buf; - ses_dev->page1_len = len; - - result = ses_recv_diag(sdev, 1, buf, len); - if (result) - goto recv_failed; - - types = buf[10]; - len = buf[11]; - - type_ptr = buf + 12 + len; - - for (i = 0; i < types; i++, type_ptr += 4) { - if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || - type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) - components += type_ptr[1]; - } - - result = ses_recv_diag(sdev, 2, hdr_buf, INIT_ALLOC_SIZE); - if (result) - goto recv_failed; - - len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; - buf = kzalloc(len, GFP_KERNEL); - if (!buf) - goto err_free; - - /* make sure getting page 2 actually works */ - result = ses_recv_diag(sdev, 2, buf, len); - if (result) - goto recv_failed; - ses_dev->page2 = buf; - ses_dev->page2_len = len; - - /* The additional information page --- allows us - * to match up the devices */ - result = ses_recv_diag(sdev, 10, hdr_buf, INIT_ALLOC_SIZE); - if (result) - goto no_page10; - - len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; - buf = kzalloc(len, GFP_KERNEL); - if (!buf) - goto err_free; - - result = ses_recv_diag(sdev, 10, buf, len); - if (result) - goto recv_failed; - ses_dev->page10 = buf; - ses_dev->page10_len = len; - - no_page10: - scomp = kmalloc(sizeof(struct ses_component) * components, GFP_KERNEL); - if (!scomp) - goto err_free; - - edev = enclosure_register(cdev->dev, sdev->sdev_gendev.bus_id, - components, &ses_enclosure_callbacks); - if (IS_ERR(edev)) { - err = PTR_ERR(edev); - goto err_free; - } - - edev->scratch = ses_dev; - for (i = 0; i < components; i++) - edev->component[i].scratch = scomp++; - - /* Page 7 for the descriptors is optional */ - buf = NULL; - result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE); - if (result) - goto simple_populate; - - len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; - /* add 1 for trailing '\0' we'll use */ - buf = kzalloc(len + 1, GFP_KERNEL); - result = ses_recv_diag(sdev, 7, buf, len); - if (result) { - simple_populate: - kfree(buf); - buf = NULL; - desc_ptr = NULL; - addl_desc_ptr = NULL; - } else { - desc_ptr = buf + 8; - len = (desc_ptr[2] << 8) + desc_ptr[3]; - /* skip past overall descriptor */ - desc_ptr += len + 4; - addl_desc_ptr = ses_dev->page10 + 8; - } - type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; - components = 0; - for (i = 0; i < types; i++, type_ptr += 4) { - for (j = 0; j < type_ptr[1]; j++) { - char *name = NULL; - struct enclosure_component *ecomp; - - if (desc_ptr) { - len = (desc_ptr[2] << 8) + desc_ptr[3]; - desc_ptr += 4; - /* Add trailing zero - pushes into - * reserved space */ - desc_ptr[len] = '\0'; - name = desc_ptr; - } - if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && - type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) - continue; - ecomp = enclosure_component_register(edev, - components++, - type_ptr[0], - name); - if (desc_ptr) { - desc_ptr += len; - if (!IS_ERR(ecomp)) - ses_process_descriptor(ecomp, - addl_desc_ptr); - - if (addl_desc_ptr) - addl_desc_ptr += addl_desc_ptr[1] + 2; - } - } - } - kfree(buf); - kfree(hdr_buf); - - /* see if there are any devices matching before - * we found the enclosure */ - shost_for_each_device(tmp_sdev, sdev->host) { - if (tmp_sdev->lun != 0 || scsi_device_enclosure(tmp_sdev)) - continue; - ses_match_to_enclosure(edev, tmp_sdev); - } - - return 0; - - recv_failed: - sdev_printk(KERN_ERR, sdev, "Failed to get diagnostic page 0x%x\n", - result); - err = -ENODEV; - err_free: - kfree(buf); - kfree(ses_dev->page10); - kfree(ses_dev->page2); - kfree(ses_dev->page1); - err_init_free: - kfree(ses_dev); - kfree(hdr_buf); - sdev_printk(KERN_ERR, sdev, "Failed to bind enclosure %d\n", err); - return err; -} - -static int ses_remove(struct device *dev) -{ - return 0; -} - -static void ses_intf_remove(struct class_device *cdev, - struct class_interface *intf) -{ - struct scsi_device *sdev = to_scsi_device(cdev->dev); - struct enclosure_device *edev; - struct ses_device *ses_dev; - - if (!scsi_device_enclosure(sdev)) - return; - - edev = enclosure_find(cdev->dev); - if (!edev) - return; - - ses_dev = edev->scratch; - edev->scratch = NULL; - - kfree(ses_dev->page1); - kfree(ses_dev->page2); - kfree(ses_dev); - - kfree(edev->component[0].scratch); - - class_device_put(&edev->cdev); - enclosure_unregister(edev); -} - -static struct class_interface ses_interface = { - .add = ses_intf_add, - .remove = ses_intf_remove, -}; - -static struct scsi_driver ses_template = { - .owner = THIS_MODULE, - .gendrv = { - .name = "ses", - .probe = ses_probe, - .remove = ses_remove, - }, -}; - -static int __init ses_init(void) -{ - int err; - - err = scsi_register_interface(&ses_interface); - if (err) - return err; - - err = scsi_register_driver(&ses_template.gendrv); - if (err) - goto out_unreg; - - return 0; - - out_unreg: - scsi_unregister_interface(&ses_interface); - return err; -} - -static void __exit ses_exit(void) -{ - scsi_unregister_driver(&ses_template.gendrv); - scsi_unregister_interface(&ses_interface); -} - -module_init(ses_init); -module_exit(ses_exit); - -MODULE_ALIAS_SCSI_DEVICE(TYPE_ENCLOSURE); - -MODULE_AUTHOR("James Bottomley"); -MODULE_DESCRIPTION("SCSI Enclosure Services (ses) driver"); -MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/scsi/sr.c b/trunk/drivers/scsi/sr.c index 208565bdbe8e..50ba49250203 100644 --- a/trunk/drivers/scsi/sr.c +++ b/trunk/drivers/scsi/sr.c @@ -163,29 +163,6 @@ static void scsi_cd_put(struct scsi_cd *cd) mutex_unlock(&sr_ref_mutex); } -/* identical to scsi_test_unit_ready except that it doesn't - * eat the NOT_READY returns for removable media */ -int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr) -{ - int retries = MAX_RETRIES; - int the_result; - u8 cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0 }; - - /* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION - * conditions are gone, or a timeout happens - */ - do { - the_result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, - 0, sshdr, SR_TIMEOUT, - retries--); - - } while (retries > 0 && - (!scsi_status_is_good(the_result) || - (scsi_sense_valid(sshdr) && - sshdr->sense_key == UNIT_ATTENTION))); - return the_result; -} - /* * This function checks to see if the media has been changed in the * CDROM drive. It is possible that we have already sensed a change, @@ -208,7 +185,8 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot) } sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); - retval = sr_test_unit_ready(cd->device, sshdr); + retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, + sshdr); if (retval || (scsi_sense_valid(sshdr) && /* 0x3a is medium not present */ sshdr->asc == 0x3a)) { @@ -755,8 +733,10 @@ static void get_capabilities(struct scsi_cd *cd) { unsigned char *buffer; struct scsi_mode_data data; + unsigned char cmd[MAX_COMMAND_SIZE]; struct scsi_sense_hdr sshdr; - int rc, n; + unsigned int the_result; + int retries, rc, n; static const char *loadmech[] = { @@ -778,8 +758,23 @@ static void get_capabilities(struct scsi_cd *cd) return; } - /* eat unit attentions */ - sr_test_unit_ready(cd->device, &sshdr); + /* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION + * conditions are gone, or a timeout happens + */ + retries = 0; + do { + memset((void *)cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + the_result = scsi_execute_req (cd->device, cmd, DMA_NONE, NULL, + 0, &sshdr, SR_TIMEOUT, + MAX_RETRIES); + + retries++; + } while (retries < 5 && + (!scsi_status_is_good(the_result) || + (scsi_sense_valid(&sshdr) && + sshdr.sense_key == UNIT_ATTENTION))); /* ask for mode page 0x2a */ rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, diff --git a/trunk/drivers/scsi/sr.h b/trunk/drivers/scsi/sr.h index 1e144dfdbd4b..81fbc0b78a52 100644 --- a/trunk/drivers/scsi/sr.h +++ b/trunk/drivers/scsi/sr.h @@ -61,7 +61,6 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed); int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); int sr_is_xa(Scsi_CD *); -int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr); /* sr_vendor.c */ void sr_vendor_init(Scsi_CD *); diff --git a/trunk/drivers/scsi/sr_ioctl.c b/trunk/drivers/scsi/sr_ioctl.c index ae87d08df588..d5cebff1d646 100644 --- a/trunk/drivers/scsi/sr_ioctl.c +++ b/trunk/drivers/scsi/sr_ioctl.c @@ -306,7 +306,8 @@ int sr_drive_status(struct cdrom_device_info *cdi, int slot) /* we have no changer support */ return -EINVAL; } - if (0 == sr_test_unit_ready(cd->device, &sshdr)) + if (0 == scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, + &sshdr)) return CDS_DISC_OK; if (!cdrom_get_media_event(cdi, &med)) { diff --git a/trunk/drivers/scsi/sun3x_esp.c b/trunk/drivers/scsi/sun3x_esp.c index 06152c7fa689..1bc41907a038 100644 --- a/trunk/drivers/scsi/sun3x_esp.c +++ b/trunk/drivers/scsi/sun3x_esp.c @@ -1,316 +1,392 @@ -/* sun3x_esp.c: ESP front-end for Sun3x systems. +/* sun3x_esp.c: EnhancedScsiProcessor Sun3x SCSI driver code. * - * Copyright (C) 2007,2008 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * + * Based on David S. Miller's esp driver */ #include #include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include #include +#include "scsi.h" +#include +#include "NCR53C9x.h" + #include -#include -#include #include +#include + +static void dma_barrier(struct NCR_ESP *esp); +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_drain(struct NCR_ESP *esp); +static void dma_invalidate(struct NCR_ESP *esp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static void dma_poll(struct NCR_ESP *esp, unsigned char *vaddr); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_reset(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); +static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_advance_sg (Scsi_Cmnd *sp); + +/* Detecting ESP chips on the machine. This is the simple and easy + * version. + */ +int sun3x_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct ConfigDev *esp_dev; + + esp_dev = 0; + esp = esp_allocate(tpnt, esp_dev, 0); + + /* Do command transfer with DMA */ + esp->do_pio_cmds = 0; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = &dma_barrier; + esp->dma_invalidate = &dma_invalidate; + esp->dma_drain = &dma_drain; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_led_on = 0; + esp->dma_led_off = 0; + esp->dma_poll = &dma_poll; + esp->dma_reset = &dma_reset; + + /* virtual DMA functions */ + esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; + esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one; + esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl; + esp->dma_advance_sg = &dma_advance_sg; + + /* SCSI chip speed */ + esp->cfreq = 20000000; + esp->eregs = (struct ESP_regs *)(SUN3X_ESP_BASE); + esp->dregs = (void *)SUN3X_ESP_DMA; -/* DMA controller reg offsets */ -#define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */ -#define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */ -#define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */ -#define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */ + esp->esp_command = (volatile unsigned char *)dvma_malloc(DVMA_PAGE_SIZE); + esp->esp_command_dvma = dvma_vtob((unsigned long)esp->esp_command); -#include + esp->irq = 2; + if (request_irq(esp->irq, esp_intr, IRQF_DISABLED, + "SUN3X SCSI", esp->ehost)) { + esp_deallocate(esp); + return 0; + } -#include "esp_scsi.h" + esp->scsi_id = 7; + esp->diff = 0; -#define DRV_MODULE_NAME "sun3x_esp" -#define PFX DRV_MODULE_NAME ": " -#define DRV_VERSION "1.000" -#define DRV_MODULE_RELDATE "Nov 1, 2007" + esp_initialize(esp); -/* - * m68k always assumes readl/writel operate on little endian - * mmio space; this is wrong at least for Sun3x, so we - * need to workaround this until a proper way is found - */ -#if 0 -#define dma_read32(REG) \ - readl(esp->dma_regs + (REG)) -#define dma_write32(VAL, REG) \ - writel((VAL), esp->dma_regs + (REG)) -#else -#define dma_read32(REG) \ - *(volatile u32 *)(esp->dma_regs + (REG)) -#define dma_write32(VAL, REG) \ - do { *(volatile u32 *)(esp->dma_regs + (REG)) = (VAL); } while (0) -#endif - -static void sun3x_esp_write8(struct esp *esp, u8 val, unsigned long reg) -{ - writeb(val, esp->regs + (reg * 4UL)); -} + /* for reasons beyond my knowledge (and which should likely be fixed) + sync mode doesn't work on a 3/80 at 5mhz. but it does at 4. */ + esp->sync_defp = 0x3f; -static u8 sun3x_esp_read8(struct esp *esp, unsigned long reg) -{ - return readb(esp->regs + (reg * 4UL)); + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, + esps_in_use); + esps_running = esps_in_use; + return esps_in_use; } -static dma_addr_t sun3x_esp_map_single(struct esp *esp, void *buf, - size_t sz, int dir) +static void dma_do_drain(struct NCR_ESP *esp) { - return dma_map_single(esp->dev, buf, sz, dir); + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + + int count = 500000; + + while((dregs->cond_reg & DMA_PEND_READ) && (--count > 0)) + udelay(1); + + if(!count) { + printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); + } + + dregs->cond_reg |= DMA_FIFO_STDRAIN; + + count = 500000; + + while((dregs->cond_reg & DMA_FIFO_ISDRAIN) && (--count > 0)) + udelay(1); + + if(!count) { + printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); + } + } - -static int sun3x_esp_map_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) + +static void dma_barrier(struct NCR_ESP *esp) { - return dma_map_sg(esp->dev, sg, num_sg, dir); + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + int count = 500000; + + while((dregs->cond_reg & DMA_PEND_READ) && (--count > 0)) + udelay(1); + + if(!count) { + printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); + } + + dregs->cond_reg &= ~(DMA_ENABLE); } -static void sun3x_esp_unmap_single(struct esp *esp, dma_addr_t addr, - size_t sz, int dir) +/* This uses various DMA csr fields and the fifo flags count value to + * determine how many bytes were successfully sent/received by the ESP. + */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) { - dma_unmap_single(esp->dev, addr, sz, dir); -} + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; -static void sun3x_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - dma_unmap_sg(esp->dev, sg, num_sg, dir); + int rval = dregs->st_addr - esp->esp_command_dvma; + + return rval - fifo_count; } -static int sun3x_esp_irq_pending(struct esp *esp) +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) { - if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) - return 1; - return 0; + return sp->SCp.this_residual; } -static void sun3x_esp_reset_dma(struct esp *esp) +static void dma_drain(struct NCR_ESP *esp) { - u32 val; - - val = dma_read32(DMA_CSR); - dma_write32(val | DMA_RST_SCSI, DMA_CSR); - dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + int count = 500000; + + if(dregs->cond_reg & DMA_FIFO_ISDRAIN) { + dregs->cond_reg |= DMA_FIFO_STDRAIN; + while((dregs->cond_reg & DMA_FIFO_ISDRAIN) && (--count > 0)) + udelay(1); + if(!count) { + printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); + } - /* Enable interrupts. */ - val = dma_read32(DMA_CSR); - dma_write32(val | DMA_INT_ENAB, DMA_CSR); + } } -static void sun3x_esp_dma_drain(struct esp *esp) +static void dma_invalidate(struct NCR_ESP *esp) { - u32 csr; - int lim; - - csr = dma_read32(DMA_CSR); - if (!(csr & DMA_FIFO_ISDRAIN)) - return; + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; - dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR); + __u32 tmp; + int count = 500000; - lim = 1000; - while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n", - esp->host->unique_id); - break; - } + while(((tmp = dregs->cond_reg) & DMA_PEND_READ) && (--count > 0)) udelay(1); + + if(!count) { + printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); } + + dregs->cond_reg = tmp | DMA_FIFO_INV; + dregs->cond_reg &= ~DMA_FIFO_INV; + } -static void sun3x_esp_dma_invalidate(struct esp *esp) +static void dma_dump_state(struct NCR_ESP *esp) { - u32 val; - int lim; - - lim = 1000; - while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: DMA will not " - "invalidate!\n", esp->host->unique_id); - break; - } - udelay(1); - } + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; - val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); - val |= DMA_FIFO_INV; - dma_write32(val, DMA_CSR); - val &= ~DMA_FIFO_INV; - dma_write32(val, DMA_CSR); + ESPLOG(("esp%d: dma -- cond_reg<%08lx> addr<%08lx>\n", + esp->esp_id, dregs->cond_reg, dregs->st_addr)); } -static void sun3x_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, - u32 dma_count, int write, u8 cmd) +static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) { - u32 csr; - - BUG_ON(!(cmd & ESP_CMD_DMA)); - - sun3x_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); - sun3x_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); - csr = dma_read32(DMA_CSR); - csr |= DMA_ENABLE; - if (write) - csr |= DMA_ST_WRITE; - else - csr &= ~DMA_ST_WRITE; - dma_write32(csr, DMA_CSR); - dma_write32(addr, DMA_ADDR); - - scsi_esp_cmd(esp, cmd); + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + + dregs->st_addr = vaddress; + dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE); } -static int sun3x_esp_dma_error(struct esp *esp) +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length) { - u32 csr = dma_read32(DMA_CSR); + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; - if (csr & DMA_HNDL_ERROR) - return 1; + /* Set up the DMA counters */ - return 0; + dregs->st_addr = vaddress; + dregs->cond_reg = ((dregs->cond_reg & ~(DMA_ST_WRITE)) | DMA_ENABLE); } -static const struct esp_driver_ops sun3x_esp_ops = { - .esp_write8 = sun3x_esp_write8, - .esp_read8 = sun3x_esp_read8, - .map_single = sun3x_esp_map_single, - .map_sg = sun3x_esp_map_sg, - .unmap_single = sun3x_esp_unmap_single, - .unmap_sg = sun3x_esp_unmap_sg, - .irq_pending = sun3x_esp_irq_pending, - .reset_dma = sun3x_esp_reset_dma, - .dma_drain = sun3x_esp_dma_drain, - .dma_invalidate = sun3x_esp_dma_invalidate, - .send_dma_cmd = sun3x_esp_send_dma_cmd, - .dma_error = sun3x_esp_dma_error, -}; - -static int __devinit esp_sun3x_probe(struct platform_device *dev) +static void dma_ints_off(struct NCR_ESP *esp) { - struct scsi_host_template *tpnt = &scsi_esp_template; - struct Scsi_Host *host; - struct esp *esp; - struct resource *res; - int err = -ENOMEM; - - host = scsi_host_alloc(tpnt, sizeof(struct esp)); - if (!host) - goto fail; - - host->max_id = 8; - esp = shost_priv(host); + DMA_INTSOFF((struct sparc_dma_registers *) esp->dregs); +} - esp->host = host; - esp->dev = dev; - esp->ops = &sun3x_esp_ops; +static void dma_ints_on(struct NCR_ESP *esp) +{ + DMA_INTSON((struct sparc_dma_registers *) esp->dregs); +} - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res && !res->start) - goto fail_unlink; +static int dma_irq_p(struct NCR_ESP *esp) +{ + return DMA_IRQ_P((struct sparc_dma_registers *) esp->dregs); +} - esp->regs = ioremap_nocache(res->start, 0x20); - if (!esp->regs) - goto fail_unmap_regs; +static void dma_poll(struct NCR_ESP *esp, unsigned char *vaddr) +{ + int count = 50; + dma_do_drain(esp); - res = platform_get_resource(dev, IORESOURCE_MEM, 1); - if (!res && !res->start) - goto fail_unmap_regs; + /* Wait till the first bits settle. */ + while((*(volatile unsigned char *)vaddr == 0xff) && (--count > 0)) + udelay(1); - esp->dma_regs = ioremap_nocache(res->start, 0x10); + if(!count) { +// printk("%s:%d timeout expire (data %02x)\n", __FILE__, __LINE__, +// esp_read(esp->eregs->esp_fdata)); + //mach_halt(); + vaddr[0] = esp_read(esp->eregs->esp_fdata); + vaddr[1] = esp_read(esp->eregs->esp_fdata); + } - esp->command_block = dma_alloc_coherent(esp->dev, 16, - &esp->command_block_dma, - GFP_KERNEL); - if (!esp->command_block) - goto fail_unmap_regs_dma; +} - host->irq = platform_get_irq(dev, 0); - err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, - "SUN3X ESP", esp); - if (err < 0) - goto fail_unmap_command_block; +static int dma_ports_p(struct NCR_ESP *esp) +{ + return (((struct sparc_dma_registers *) esp->dregs)->cond_reg + & DMA_INT_ENAB); +} - esp->scsi_id = 7; - esp->host->this_id = esp->scsi_id; - esp->scsi_id_mask = (1 << esp->scsi_id); - esp->cfreq = 20000000; +/* Resetting various pieces of the ESP scsi driver chipset/buses. */ +static void dma_reset(struct NCR_ESP *esp) +{ + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *)esp->dregs; - dev_set_drvdata(&dev->dev, esp); - - err = scsi_esp_register(esp, &dev->dev); - if (err) - goto fail_free_irq; - - return 0; - -fail_free_irq: - free_irq(host->irq, esp); -fail_unmap_command_block: - dma_free_coherent(esp->dev, 16, - esp->command_block, - esp->command_block_dma); -fail_unmap_regs_dma: - iounmap(esp->dma_regs); -fail_unmap_regs: - iounmap(esp->regs); -fail_unlink: - scsi_host_put(host); -fail: - return err; + /* Punt the DVMA into a known state. */ + dregs->cond_reg |= DMA_RST_SCSI; + dregs->cond_reg &= ~(DMA_RST_SCSI); + DMA_INTSON(dregs); } -static int __devexit esp_sun3x_remove(struct platform_device *dev) +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) { - struct esp *esp = dev_get_drvdata(&dev->dev); - unsigned int irq = esp->host->irq; - u32 val; + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + unsigned long nreg = dregs->cond_reg; + +// printk("dma_setup %c addr %08x cnt %08x\n", +// write ? 'W' : 'R', addr, count); - scsi_esp_unregister(esp); + dma_do_drain(esp); - /* Disable interrupts. */ - val = dma_read32(DMA_CSR); - dma_write32(val & ~DMA_INT_ENAB, DMA_CSR); + if(write) + nreg |= DMA_ST_WRITE; + else { + nreg &= ~(DMA_ST_WRITE); + } + + nreg |= DMA_ENABLE; + dregs->cond_reg = nreg; + dregs->st_addr = addr; +} - free_irq(irq, esp); - dma_free_coherent(esp->dev, 16, - esp->command_block, - esp->command_block_dma); +static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + sp->SCp.have_data_in = dvma_map((unsigned long)sp->SCp.buffer, + sp->SCp.this_residual); + sp->SCp.ptr = (char *)((unsigned long)sp->SCp.have_data_in); +} - scsi_host_put(esp->host); +static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + int sz = sp->SCp.buffers_residual; + struct scatterlist *sg = sp->SCp.buffer; + + while (sz >= 0) { + sg[sz].dma_address = dvma_map((unsigned long)sg_virt(&sg[sz]), + sg[sz].length); + sz--; + } + sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dma_address); +} - return 0; +static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + dvma_unmap((char *)sp->SCp.have_data_in); } -static struct platform_driver esp_sun3x_driver = { - .probe = esp_sun3x_probe, - .remove = __devexit_p(esp_sun3x_remove), - .driver = { - .name = "sun3x_esp", - }, -}; +static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + int sz = sp->use_sg - 1; + struct scatterlist *sg = (struct scatterlist *)sp->request_buffer; + + while(sz >= 0) { + dvma_unmap((char *)sg[sz].dma_address); + sz--; + } +} -static int __init sun3x_esp_init(void) +static void dma_advance_sg (Scsi_Cmnd *sp) { - return platform_driver_register(&esp_sun3x_driver); + sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dma_address); } -static void __exit sun3x_esp_exit(void) +static int sun3x_esp_release(struct Scsi_Host *instance) { - platform_driver_unregister(&esp_sun3x_driver); + /* this code does not support being compiled as a module */ + return 1; + } -MODULE_DESCRIPTION("Sun3x ESP SCSI driver"); -MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); +static struct scsi_host_template driver_template = { + .proc_name = "sun3x_esp", + .proc_info = &esp_proc_info, + .name = "Sun ESP 100/100a/200", + .detect = sun3x_esp_detect, + .release = sun3x_esp_release, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .info = esp_info, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING, +}; + -module_init(sun3x_esp_init); -module_exit(sun3x_esp_exit); +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/sym53c8xx_2/sym_hipd.c b/trunk/drivers/scsi/sym53c8xx_2/sym_hipd.c index 35142b5341b5..254bdaeb35ff 100644 --- a/trunk/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/trunk/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -3842,7 +3842,7 @@ int sym_compute_residual(struct sym_hcb *np, struct sym_ccb *cp) if (cp->startp == cp->phys.head.lastp || sym_evaluate_dp(np, cp, scr_to_cpu(cp->phys.head.lastp), &dp_ofs) < 0) { - return cp->data_len - cp->odd_byte_adjustment; + return cp->data_len; } /* diff --git a/trunk/drivers/scsi/u14-34f.c b/trunk/drivers/scsi/u14-34f.c index 58d7eee4fe81..662c00451be4 100644 --- a/trunk/drivers/scsi/u14-34f.c +++ b/trunk/drivers/scsi/u14-34f.c @@ -1216,7 +1216,7 @@ static void scsi_to_dev_dir(unsigned int i, unsigned int j) { cpp->xdir = DTD_IN; return; } - else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) { + else if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) { cpp->xdir = DTD_OUT; return; } diff --git a/trunk/fs/Kconfig b/trunk/fs/Kconfig index d7312825592b..3bf6ace1720c 100644 --- a/trunk/fs/Kconfig +++ b/trunk/fs/Kconfig @@ -1778,9 +1778,12 @@ config SUNRPC_GSS tristate config SUNRPC_XPRT_RDMA - tristate + tristate "RDMA transport for sunrpc (EXPERIMENTAL)" depends on SUNRPC && INFINIBAND && EXPERIMENTAL - default SUNRPC && INFINIBAND + default m + help + Adds a client RPC transport for supporting kernel NFS over RDMA + mounts, including Infiniband and iWARP. Experimental. config SUNRPC_BIND34 bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)" diff --git a/trunk/fs/jfs/file.c b/trunk/fs/jfs/file.c index 7f6063acaa3b..87eb93694af7 100644 --- a/trunk/fs/jfs/file.c +++ b/trunk/fs/jfs/file.c @@ -112,8 +112,5 @@ const struct file_operations jfs_file_operations = { .splice_write = generic_file_splice_write, .fsync = jfs_fsync, .release = jfs_release, - .unlocked_ioctl = jfs_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = jfs_compat_ioctl, -#endif + .ioctl = jfs_ioctl, }; diff --git a/trunk/fs/jfs/ioctl.c b/trunk/fs/jfs/ioctl.c index a1f8e375ad21..dfda12a073e1 100644 --- a/trunk/fs/jfs/ioctl.c +++ b/trunk/fs/jfs/ioctl.c @@ -51,9 +51,9 @@ static long jfs_map_ext2(unsigned long flags, int from) } -long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +int jfs_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, + unsigned long arg) { - struct inode *inode = filp->f_dentry->d_inode; struct jfs_inode_info *jfs_inode = JFS_IP(inode); unsigned int flags; @@ -82,10 +82,6 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* Is it quota file? Do not allow user to mess with it */ if (IS_NOQUOTA(inode)) return -EPERM; - - /* Lock against other parallel changes of flags */ - mutex_lock(&inode->i_mutex); - jfs_get_inode_flags(jfs_inode); oldflags = jfs_inode->mode2; @@ -96,10 +92,8 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if ((oldflags & JFS_IMMUTABLE_FL) || ((flags ^ oldflags) & (JFS_APPEND_FL | JFS_IMMUTABLE_FL))) { - if (!capable(CAP_LINUX_IMMUTABLE)) { - mutex_unlock(&inode->i_mutex); + if (!capable(CAP_LINUX_IMMUTABLE)) return -EPERM; - } } flags = flags & JFS_FL_USER_MODIFIABLE; @@ -107,7 +101,6 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) jfs_inode->mode2 = flags; jfs_set_inode_flags(inode); - mutex_unlock(&inode->i_mutex); inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); return 0; @@ -117,21 +110,3 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } -#ifdef CONFIG_COMPAT -long jfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - /* While these ioctl numbers defined with 'long' and have different - * numbers than the 64bit ABI, - * the actual implementation only deals with ints and is compatible. - */ - switch (cmd) { - case JFS_IOC_GETFLAGS32: - cmd = JFS_IOC_GETFLAGS; - break; - case JFS_IOC_SETFLAGS32: - cmd = JFS_IOC_SETFLAGS; - break; - } - return jfs_ioctl(filp, cmd, arg); -} -#endif diff --git a/trunk/fs/jfs/jfs_dinode.h b/trunk/fs/jfs/jfs_dinode.h index 395c4c0d0f06..c387540d3425 100644 --- a/trunk/fs/jfs/jfs_dinode.h +++ b/trunk/fs/jfs/jfs_dinode.h @@ -170,7 +170,5 @@ struct dinode { #define JFS_IOC_GETFLAGS _IOR('f', 1, long) #define JFS_IOC_SETFLAGS _IOW('f', 2, long) -#define JFS_IOC_GETFLAGS32 _IOR('f', 1, int) -#define JFS_IOC_SETFLAGS32 _IOW('f', 2, int) #endif /*_H_JFS_DINODE */ diff --git a/trunk/fs/jfs/jfs_inode.h b/trunk/fs/jfs/jfs_inode.h index adb2fafcc544..95a6a11425e5 100644 --- a/trunk/fs/jfs/jfs_inode.h +++ b/trunk/fs/jfs/jfs_inode.h @@ -22,8 +22,8 @@ struct fid; extern struct inode *ialloc(struct inode *, umode_t); extern int jfs_fsync(struct file *, struct dentry *, int); -extern long jfs_ioctl(struct file *, unsigned int, unsigned long); -extern long jfs_compat_ioctl(struct file *, unsigned int, unsigned long); +extern int jfs_ioctl(struct inode *, struct file *, + unsigned int, unsigned long); extern struct inode *jfs_iget(struct super_block *, unsigned long); extern int jfs_commit_inode(struct inode *, int); extern int jfs_write_inode(struct inode*, int); diff --git a/trunk/fs/jfs/namei.c b/trunk/fs/jfs/namei.c index 0ba6778edaa2..403cfc24c6fe 100644 --- a/trunk/fs/jfs/namei.c +++ b/trunk/fs/jfs/namei.c @@ -1556,10 +1556,7 @@ const struct file_operations jfs_dir_operations = { .read = generic_read_dir, .readdir = jfs_readdir, .fsync = jfs_fsync, - .unlocked_ioctl = jfs_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = jfs_compat_ioctl, -#endif + .ioctl = jfs_ioctl, }; static int jfs_ci_hash(struct dentry *dir, struct qstr *this) diff --git a/trunk/fs/nfs/write.c b/trunk/fs/nfs/write.c index f55c437124a2..b144b1957dd9 100644 --- a/trunk/fs/nfs/write.c +++ b/trunk/fs/nfs/write.c @@ -696,17 +696,6 @@ int nfs_flush_incompatible(struct file *file, struct page *page) return status; } -/* - * If the page cache is marked as unsafe or invalid, then we can't rely on - * the PageUptodate() flag. In this case, we will need to turn off - * write optimisations that depend on the page contents being correct. - */ -static int nfs_write_pageuptodate(struct page *page, struct inode *inode) -{ - return PageUptodate(page) && - !(NFS_I(inode)->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA)); -} - /* * Update and possibly write a cached page of an NFS file. * @@ -728,13 +717,10 @@ int nfs_updatepage(struct file *file, struct page *page, (long long)(page_offset(page) +offset)); /* If we're not using byte range locks, and we know the page - * is up to date, it may be more efficient to extend the write - * to cover the entire page in order to avoid fragmentation - * inefficiencies. + * is entirely in cache, it may be more efficient to avoid + * fragmenting write requests. */ - if (nfs_write_pageuptodate(page, inode) && - inode->i_flock == NULL && - !(file->f_mode & O_SYNC)) { + if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { count = max(count + offset, nfs_page_length(page)); offset = 0; } diff --git a/trunk/fs/ocfs2/cluster/tcp_internal.h b/trunk/fs/ocfs2/cluster/tcp_internal.h index d25b9af28500..b2e832aca567 100644 --- a/trunk/fs/ocfs2/cluster/tcp_internal.h +++ b/trunk/fs/ocfs2/cluster/tcp_internal.h @@ -38,15 +38,6 @@ * locking semantics of the file system using the protocol. It should * be somewhere else, I'm sure, but right now it isn't. * - * With version 11, we separate out the filesystem locking portion. The - * filesystem now has a major.minor version it negotiates. Version 11 - * introduces this negotiation to the o2dlm protocol, and as such the - * version here in tcp_internal.h should not need to be bumped for - * filesystem locking changes. - * - * New in version 11 - * - Negotiation of filesystem locking in the dlm join. - * * New in version 10: * - Meta/data locks combined * @@ -75,7 +66,7 @@ * - full 64 bit i_size in the metadata lock lvbs * - introduction of "rw" lock and pushing meta/data locking down */ -#define O2NET_PROTOCOL_VERSION 11ULL +#define O2NET_PROTOCOL_VERSION 10ULL struct o2net_handshake { __be64 protocol_version; __be64 connector_id; diff --git a/trunk/fs/ocfs2/dlm/dlmapi.h b/trunk/fs/ocfs2/dlm/dlmapi.h index b5786a787fab..cfd5cb65cab0 100644 --- a/trunk/fs/ocfs2/dlm/dlmapi.h +++ b/trunk/fs/ocfs2/dlm/dlmapi.h @@ -193,12 +193,7 @@ enum dlm_status dlmunlock(struct dlm_ctxt *dlm, dlm_astunlockfunc_t *unlockast, void *data); -struct dlm_protocol_version { - u8 pv_major; - u8 pv_minor; -}; -struct dlm_ctxt * dlm_register_domain(const char *domain, u32 key, - struct dlm_protocol_version *fs_proto); +struct dlm_ctxt * dlm_register_domain(const char *domain, u32 key); void dlm_unregister_domain(struct dlm_ctxt *dlm); diff --git a/trunk/fs/ocfs2/dlm/dlmcommon.h b/trunk/fs/ocfs2/dlm/dlmcommon.h index 9843ee17ea27..e90b92f9ece1 100644 --- a/trunk/fs/ocfs2/dlm/dlmcommon.h +++ b/trunk/fs/ocfs2/dlm/dlmcommon.h @@ -142,12 +142,6 @@ struct dlm_ctxt spinlock_t work_lock; struct list_head dlm_domain_handlers; struct list_head dlm_eviction_callbacks; - - /* The filesystem specifies this at domain registration. We - * cache it here to know what to tell other nodes. */ - struct dlm_protocol_version fs_locking_proto; - /* This is the inter-dlm communication version */ - struct dlm_protocol_version dlm_locking_proto; }; static inline struct hlist_head *dlm_lockres_hash(struct dlm_ctxt *dlm, unsigned i) @@ -595,24 +589,10 @@ struct dlm_proxy_ast #define DLM_PROXY_AST_MAX_LEN (sizeof(struct dlm_proxy_ast)+DLM_LVB_LEN) #define DLM_MOD_KEY (0x666c6172) -enum dlm_query_join_response_code { +enum dlm_query_join_response { JOIN_DISALLOW = 0, JOIN_OK, JOIN_OK_NO_MAP, - JOIN_PROTOCOL_MISMATCH, -}; - -union dlm_query_join_response { - u32 intval; - struct { - u8 code; /* Response code. dlm_minor and fs_minor - are only valid if this is JOIN_OK */ - u8 dlm_minor; /* The minor version of the protocol the - dlm is speaking. */ - u8 fs_minor; /* The minor version of the protocol the - filesystem is speaking. */ - u8 reserved; - } packet; }; struct dlm_lock_request @@ -653,8 +633,6 @@ struct dlm_query_join_request u8 node_idx; u8 pad1[2]; u8 name_len; - struct dlm_protocol_version dlm_proto; - struct dlm_protocol_version fs_proto; u8 domain[O2NM_MAX_NAME_LEN]; u8 node_map[BITS_TO_BYTES(O2NM_MAX_NODES)]; }; diff --git a/trunk/fs/ocfs2/dlm/dlmdomain.c b/trunk/fs/ocfs2/dlm/dlmdomain.c index 638d2ebb892b..6954565b8ccb 100644 --- a/trunk/fs/ocfs2/dlm/dlmdomain.c +++ b/trunk/fs/ocfs2/dlm/dlmdomain.c @@ -123,17 +123,6 @@ DEFINE_SPINLOCK(dlm_domain_lock); LIST_HEAD(dlm_domains); static DECLARE_WAIT_QUEUE_HEAD(dlm_domain_events); -/* - * The supported protocol version for DLM communication. Running domains - * will have a negotiated version with the same major number and a minor - * number equal or smaller. The dlm_ctxt->dlm_locking_proto field should - * be used to determine what a running domain is actually using. - */ -static const struct dlm_protocol_version dlm_protocol = { - .pv_major = 1, - .pv_minor = 0, -}; - #define DLM_DOMAIN_BACKOFF_MS 200 static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, @@ -144,8 +133,6 @@ static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data, void **ret_data); static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data, void **ret_data); -static int dlm_protocol_compare(struct dlm_protocol_version *existing, - struct dlm_protocol_version *request); static void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm); @@ -681,45 +668,11 @@ void dlm_unregister_domain(struct dlm_ctxt *dlm) } EXPORT_SYMBOL_GPL(dlm_unregister_domain); -static int dlm_query_join_proto_check(char *proto_type, int node, - struct dlm_protocol_version *ours, - struct dlm_protocol_version *request) -{ - int rc; - struct dlm_protocol_version proto = *request; - - if (!dlm_protocol_compare(ours, &proto)) { - mlog(0, - "node %u wanted to join with %s locking protocol " - "%u.%u, we respond with %u.%u\n", - node, proto_type, - request->pv_major, - request->pv_minor, - proto.pv_major, proto.pv_minor); - request->pv_minor = proto.pv_minor; - rc = 0; - } else { - mlog(ML_NOTICE, - "Node %u wanted to join with %s locking " - "protocol %u.%u, but we have %u.%u, disallowing\n", - node, proto_type, - request->pv_major, - request->pv_minor, - ours->pv_major, - ours->pv_minor); - rc = 1; - } - - return rc; -} - static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, void **ret_data) { struct dlm_query_join_request *query; - union dlm_query_join_response response = { - .packet.code = JOIN_DISALLOW, - }; + enum dlm_query_join_response response; struct dlm_ctxt *dlm = NULL; u8 nodenum; @@ -737,11 +690,11 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, mlog(0, "node %u is not in our live map yet\n", query->node_idx); - response.packet.code = JOIN_DISALLOW; + response = JOIN_DISALLOW; goto respond; } - response.packet.code = JOIN_OK_NO_MAP; + response = JOIN_OK_NO_MAP; spin_lock(&dlm_domain_lock); dlm = __dlm_lookup_domain_full(query->domain, query->name_len); @@ -760,7 +713,7 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, mlog(0, "disallow join as node %u does not " "have node %u in its nodemap\n", query->node_idx, nodenum); - response.packet.code = JOIN_DISALLOW; + response = JOIN_DISALLOW; goto unlock_respond; } } @@ -780,48 +733,30 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, /*If this is a brand new context and we * haven't started our join process yet, then * the other node won the race. */ - response.packet.code = JOIN_OK_NO_MAP; + response = JOIN_OK_NO_MAP; } else if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) { /* Disallow parallel joins. */ - response.packet.code = JOIN_DISALLOW; + response = JOIN_DISALLOW; } else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) { mlog(0, "node %u trying to join, but recovery " "is ongoing.\n", bit); - response.packet.code = JOIN_DISALLOW; + response = JOIN_DISALLOW; } else if (test_bit(bit, dlm->recovery_map)) { mlog(0, "node %u trying to join, but it " "still needs recovery.\n", bit); - response.packet.code = JOIN_DISALLOW; + response = JOIN_DISALLOW; } else if (test_bit(bit, dlm->domain_map)) { mlog(0, "node %u trying to join, but it " "is still in the domain! needs recovery?\n", bit); - response.packet.code = JOIN_DISALLOW; + response = JOIN_DISALLOW; } else { /* Alright we're fully a part of this domain * so we keep some state as to who's joining * and indicate to him that needs to be fixed * up. */ - - /* Make sure we speak compatible locking protocols. */ - if (dlm_query_join_proto_check("DLM", bit, - &dlm->dlm_locking_proto, - &query->dlm_proto)) { - response.packet.code = - JOIN_PROTOCOL_MISMATCH; - } else if (dlm_query_join_proto_check("fs", bit, - &dlm->fs_locking_proto, - &query->fs_proto)) { - response.packet.code = - JOIN_PROTOCOL_MISMATCH; - } else { - response.packet.dlm_minor = - query->dlm_proto.pv_minor; - response.packet.fs_minor = - query->fs_proto.pv_minor; - response.packet.code = JOIN_OK; - __dlm_set_joining_node(dlm, query->node_idx); - } + response = JOIN_OK; + __dlm_set_joining_node(dlm, query->node_idx); } spin_unlock(&dlm->spinlock); @@ -830,9 +765,9 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, spin_unlock(&dlm_domain_lock); respond: - mlog(0, "We respond with %u\n", response.packet.code); + mlog(0, "We respond with %u\n", response); - return response.intval; + return response; } static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, @@ -964,11 +899,10 @@ static int dlm_send_join_cancels(struct dlm_ctxt *dlm, static int dlm_request_join(struct dlm_ctxt *dlm, int node, - enum dlm_query_join_response_code *response) + enum dlm_query_join_response *response) { - int status; + int status, retval; struct dlm_query_join_request join_msg; - union dlm_query_join_response join_resp; mlog(0, "querying node %d\n", node); @@ -976,15 +910,12 @@ static int dlm_request_join(struct dlm_ctxt *dlm, join_msg.node_idx = dlm->node_num; join_msg.name_len = strlen(dlm->name); memcpy(join_msg.domain, dlm->name, join_msg.name_len); - join_msg.dlm_proto = dlm->dlm_locking_proto; - join_msg.fs_proto = dlm->fs_locking_proto; /* copy live node map to join message */ byte_copymap(join_msg.node_map, dlm->live_nodes_map, O2NM_MAX_NODES); status = o2net_send_message(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, &join_msg, - sizeof(join_msg), node, - &join_resp.intval); + sizeof(join_msg), node, &retval); if (status < 0 && status != -ENOPROTOOPT) { mlog_errno(status); goto bail; @@ -997,41 +928,14 @@ static int dlm_request_join(struct dlm_ctxt *dlm, if (status == -ENOPROTOOPT) { status = 0; *response = JOIN_OK_NO_MAP; - } else if (join_resp.packet.code == JOIN_DISALLOW || - join_resp.packet.code == JOIN_OK_NO_MAP) { - *response = join_resp.packet.code; - } else if (join_resp.packet.code == JOIN_PROTOCOL_MISMATCH) { - mlog(ML_NOTICE, - "This node requested DLM locking protocol %u.%u and " - "filesystem locking protocol %u.%u. At least one of " - "the protocol versions on node %d is not compatible, " - "disconnecting\n", - dlm->dlm_locking_proto.pv_major, - dlm->dlm_locking_proto.pv_minor, - dlm->fs_locking_proto.pv_major, - dlm->fs_locking_proto.pv_minor, - node); - status = -EPROTO; - *response = join_resp.packet.code; - } else if (join_resp.packet.code == JOIN_OK) { - *response = join_resp.packet.code; - /* Use the same locking protocol as the remote node */ - dlm->dlm_locking_proto.pv_minor = - join_resp.packet.dlm_minor; - dlm->fs_locking_proto.pv_minor = - join_resp.packet.fs_minor; - mlog(0, - "Node %d responds JOIN_OK with DLM locking protocol " - "%u.%u and fs locking protocol %u.%u\n", - node, - dlm->dlm_locking_proto.pv_major, - dlm->dlm_locking_proto.pv_minor, - dlm->fs_locking_proto.pv_major, - dlm->fs_locking_proto.pv_minor); + } else if (retval == JOIN_DISALLOW || + retval == JOIN_OK || + retval == JOIN_OK_NO_MAP) { + *response = retval; } else { status = -EINVAL; - mlog(ML_ERROR, "invalid response %d from node %u\n", - join_resp.packet.code, node); + mlog(ML_ERROR, "invalid response %d from node %u\n", retval, + node); } mlog(0, "status %d, node %d response is %d\n", status, node, @@ -1104,7 +1008,7 @@ struct domain_join_ctxt { static int dlm_should_restart_join(struct dlm_ctxt *dlm, struct domain_join_ctxt *ctxt, - enum dlm_query_join_response_code response) + enum dlm_query_join_response response) { int ret; @@ -1130,7 +1034,7 @@ static int dlm_try_to_join_domain(struct dlm_ctxt *dlm) { int status = 0, tmpstat, node; struct domain_join_ctxt *ctxt; - enum dlm_query_join_response_code response = JOIN_DISALLOW; + enum dlm_query_join_response response = JOIN_DISALLOW; mlog_entry("%p", dlm); @@ -1546,38 +1450,10 @@ static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain, } /* - * Compare a requested locking protocol version against the current one. - * - * If the major numbers are different, they are incompatible. - * If the current minor is greater than the request, they are incompatible. - * If the current minor is less than or equal to the request, they are - * compatible, and the requester should run at the current minor version. - */ -static int dlm_protocol_compare(struct dlm_protocol_version *existing, - struct dlm_protocol_version *request) -{ - if (existing->pv_major != request->pv_major) - return 1; - - if (existing->pv_minor > request->pv_minor) - return 1; - - if (existing->pv_minor < request->pv_minor) - request->pv_minor = existing->pv_minor; - - return 0; -} - -/* - * dlm_register_domain: one-time setup per "domain". - * - * The filesystem passes in the requested locking version via proto. - * If registration was successful, proto will contain the negotiated - * locking protocol. + * dlm_register_domain: one-time setup per "domain" */ struct dlm_ctxt * dlm_register_domain(const char *domain, - u32 key, - struct dlm_protocol_version *fs_proto) + u32 key) { int ret; struct dlm_ctxt *dlm = NULL; @@ -1620,15 +1496,6 @@ struct dlm_ctxt * dlm_register_domain(const char *domain, goto retry; } - if (dlm_protocol_compare(&dlm->fs_locking_proto, fs_proto)) { - mlog(ML_ERROR, - "Requested locking protocol version is not " - "compatible with already registered domain " - "\"%s\"\n", domain); - ret = -EPROTO; - goto leave; - } - __dlm_get(dlm); dlm->num_joins++; @@ -1659,13 +1526,6 @@ struct dlm_ctxt * dlm_register_domain(const char *domain, list_add_tail(&dlm->list, &dlm_domains); spin_unlock(&dlm_domain_lock); - /* - * Pass the locking protocol version into the join. If the join - * succeeds, it will have the negotiated protocol set. - */ - dlm->dlm_locking_proto = dlm_protocol; - dlm->fs_locking_proto = *fs_proto; - ret = dlm_join_domain(dlm); if (ret) { mlog_errno(ret); @@ -1673,9 +1533,6 @@ struct dlm_ctxt * dlm_register_domain(const char *domain, goto leave; } - /* Tell the caller what locking protocol we negotiated */ - *fs_proto = dlm->fs_locking_proto; - ret = 0; leave: if (new_ctxt) diff --git a/trunk/fs/ocfs2/dlm/dlmfs.c b/trunk/fs/ocfs2/dlm/dlmfs.c index 61a000f8524c..6639baab0798 100644 --- a/trunk/fs/ocfs2/dlm/dlmfs.c +++ b/trunk/fs/ocfs2/dlm/dlmfs.c @@ -60,8 +60,6 @@ #define MLOG_MASK_PREFIX ML_DLMFS #include "cluster/masklog.h" -#include "ocfs2_lockingver.h" - static const struct super_operations dlmfs_ops; static const struct file_operations dlmfs_file_operations; static const struct inode_operations dlmfs_dir_inode_operations; @@ -71,16 +69,6 @@ static struct kmem_cache *dlmfs_inode_cache; struct workqueue_struct *user_dlm_worker; -/* - * This is the userdlmfs locking protocol version. - * - * See fs/ocfs2/dlmglue.c for more details on locking versions. - */ -static const struct dlm_protocol_version user_locking_protocol = { - .pv_major = OCFS2_LOCKING_PROTOCOL_MAJOR, - .pv_minor = OCFS2_LOCKING_PROTOCOL_MINOR, -}; - /* * decodes a set of open flags into a valid lock level and a set of flags. * returns < 0 if we have invalid flags @@ -428,7 +416,6 @@ static int dlmfs_mkdir(struct inode * dir, struct qstr *domain = &dentry->d_name; struct dlmfs_inode_private *ip; struct dlm_ctxt *dlm; - struct dlm_protocol_version proto = user_locking_protocol; mlog(0, "mkdir %.*s\n", domain->len, domain->name); @@ -448,7 +435,7 @@ static int dlmfs_mkdir(struct inode * dir, ip = DLMFS_I(inode); - dlm = user_dlm_register_context(domain, &proto); + dlm = user_dlm_register_context(domain); if (IS_ERR(dlm)) { status = PTR_ERR(dlm); mlog(ML_ERROR, "Error %d could not register domain \"%.*s\"\n", diff --git a/trunk/fs/ocfs2/dlm/userdlm.c b/trunk/fs/ocfs2/dlm/userdlm.c index 4cb1d3dae250..7d2f578b267d 100644 --- a/trunk/fs/ocfs2/dlm/userdlm.c +++ b/trunk/fs/ocfs2/dlm/userdlm.c @@ -645,8 +645,7 @@ int user_dlm_destroy_lock(struct user_lock_res *lockres) return status; } -struct dlm_ctxt *user_dlm_register_context(struct qstr *name, - struct dlm_protocol_version *proto) +struct dlm_ctxt *user_dlm_register_context(struct qstr *name) { struct dlm_ctxt *dlm; u32 dlm_key; @@ -662,7 +661,7 @@ struct dlm_ctxt *user_dlm_register_context(struct qstr *name, snprintf(domain, name->len + 1, "%.*s", name->len, name->name); - dlm = dlm_register_domain(domain, dlm_key, proto); + dlm = dlm_register_domain(domain, dlm_key); if (IS_ERR(dlm)) mlog_errno(PTR_ERR(dlm)); diff --git a/trunk/fs/ocfs2/dlm/userdlm.h b/trunk/fs/ocfs2/dlm/userdlm.h index 39ec27738499..c400e93bbf79 100644 --- a/trunk/fs/ocfs2/dlm/userdlm.h +++ b/trunk/fs/ocfs2/dlm/userdlm.h @@ -83,8 +83,7 @@ void user_dlm_write_lvb(struct inode *inode, void user_dlm_read_lvb(struct inode *inode, char *val, unsigned int len); -struct dlm_ctxt *user_dlm_register_context(struct qstr *name, - struct dlm_protocol_version *proto); +struct dlm_ctxt *user_dlm_register_context(struct qstr *name); void user_dlm_unregister_context(struct dlm_ctxt *dlm); struct dlmfs_inode_private { diff --git a/trunk/fs/ocfs2/dlmglue.c b/trunk/fs/ocfs2/dlmglue.c index 351130c9b734..3867244fb144 100644 --- a/trunk/fs/ocfs2/dlmglue.c +++ b/trunk/fs/ocfs2/dlmglue.c @@ -43,7 +43,6 @@ #include #include "ocfs2.h" -#include "ocfs2_lockingver.h" #include "alloc.h" #include "dcache.h" @@ -259,31 +258,6 @@ static struct ocfs2_lock_res_ops ocfs2_flock_lops = { .flags = 0, }; -/* - * This is the filesystem locking protocol version. - * - * Whenever the filesystem does new things with locks (adds or removes a - * lock, orders them differently, does different things underneath a lock), - * the version must be changed. The protocol is negotiated when joining - * the dlm domain. A node may join the domain if its major version is - * identical to all other nodes and its minor version is greater than - * or equal to all other nodes. When its minor version is greater than - * the other nodes, it will run at the minor version specified by the - * other nodes. - * - * If a locking change is made that will not be compatible with older - * versions, the major number must be increased and the minor version set - * to zero. If a change merely adds a behavior that can be disabled when - * speaking to older versions, the minor version must be increased. If a - * change adds a fully backwards compatible change (eg, LVB changes that - * are just ignored by older versions), the version does not need to be - * updated. - */ -const struct dlm_protocol_version ocfs2_locking_protocol = { - .pv_major = OCFS2_LOCKING_PROTOCOL_MAJOR, - .pv_minor = OCFS2_LOCKING_PROTOCOL_MINOR, -}; - static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres) { return lockres->l_type == OCFS2_LOCK_TYPE_META || @@ -2532,8 +2506,7 @@ int ocfs2_dlm_init(struct ocfs2_super *osb) dlm_key = crc32_le(0, osb->uuid_str, strlen(osb->uuid_str)); /* for now, uuid == domain */ - dlm = dlm_register_domain(osb->uuid_str, dlm_key, - &osb->osb_locking_proto); + dlm = dlm_register_domain(osb->uuid_str, dlm_key); if (IS_ERR(dlm)) { status = PTR_ERR(dlm); mlog_errno(status); diff --git a/trunk/fs/ocfs2/dlmglue.h b/trunk/fs/ocfs2/dlmglue.h index 1d5b0699d0a9..5f17243ba501 100644 --- a/trunk/fs/ocfs2/dlmglue.h +++ b/trunk/fs/ocfs2/dlmglue.h @@ -116,5 +116,4 @@ void ocfs2_wake_downconvert_thread(struct ocfs2_super *osb); struct ocfs2_dlm_debug *ocfs2_new_dlm_debug(void); void ocfs2_put_dlm_debug(struct ocfs2_dlm_debug *dlm_debug); -extern const struct dlm_protocol_version ocfs2_locking_protocol; #endif /* DLMGLUE_H */ diff --git a/trunk/fs/ocfs2/ocfs2.h b/trunk/fs/ocfs2/ocfs2.h index e8b7292e0152..d08480580470 100644 --- a/trunk/fs/ocfs2/ocfs2.h +++ b/trunk/fs/ocfs2/ocfs2.h @@ -251,7 +251,6 @@ struct ocfs2_super struct ocfs2_lock_res osb_rename_lockres; struct dlm_eviction_cb osb_eviction_cb; struct ocfs2_dlm_debug *osb_dlm_debug; - struct dlm_protocol_version osb_locking_proto; struct dentry *osb_debug_root; diff --git a/trunk/fs/ocfs2/ocfs2_lockingver.h b/trunk/fs/ocfs2/ocfs2_lockingver.h deleted file mode 100644 index 82d5eeac0fff..000000000000 --- a/trunk/fs/ocfs2/ocfs2_lockingver.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; -*- - * vim: noexpandtab sw=8 ts=8 sts=0: - * - * ocfs2_lockingver.h - * - * Defines OCFS2 Locking version values. - * - * Copyright (C) 2008 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License, version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef OCFS2_LOCKINGVER_H -#define OCFS2_LOCKINGVER_H - -/* - * The protocol version for ocfs2 cluster locking. See dlmglue.c for - * more details. - */ -#define OCFS2_LOCKING_PROTOCOL_MAJOR 1 -#define OCFS2_LOCKING_PROTOCOL_MINOR 0 - -#endif /* OCFS2_LOCKINGVER_H */ diff --git a/trunk/fs/ocfs2/super.c b/trunk/fs/ocfs2/super.c index bec75aff3d9f..01fe40ee5ea9 100644 --- a/trunk/fs/ocfs2/super.c +++ b/trunk/fs/ocfs2/super.c @@ -1355,7 +1355,6 @@ static int ocfs2_initialize_super(struct super_block *sb, sb->s_fs_info = osb; sb->s_op = &ocfs2_sops; sb->s_export_op = &ocfs2_export_ops; - osb->osb_locking_proto = ocfs2_locking_protocol; sb->s_time_gran = 1; sb->s_flags |= MS_NOATIME; /* this is needed to support O_LARGEFILE */ diff --git a/trunk/fs/partitions/check.c b/trunk/fs/partitions/check.c index 9a64045ff845..739da701ae7b 100644 --- a/trunk/fs/partitions/check.c +++ b/trunk/fs/partitions/check.c @@ -319,14 +319,6 @@ void delete_partition(struct gendisk *disk, int part) put_device(&p->dev); } -static ssize_t whole_disk_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return 0; -} -static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH, - whole_disk_show, NULL); - void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags) { struct hd_struct *p; @@ -360,8 +352,13 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, device_add(&p->dev); partition_sysfs_add_subdir(p); p->dev.uevent_suppress = 0; - if (flags & ADDPART_FLAG_WHOLEDISK) - err = device_create_file(&p->dev, &dev_attr_whole_disk); + if (flags & ADDPART_FLAG_WHOLEDISK) { + static struct attribute addpartattr = { + .name = "whole_disk", + .mode = S_IRUSR | S_IRGRP | S_IROTH, + }; + err = sysfs_create_file(&p->dev.kobj, &addpartattr); + } /* suppress uevent if the disk supresses it */ if (!disk->dev.uevent_suppress) diff --git a/trunk/fs/sysfs/group.c b/trunk/fs/sysfs/group.c index 477904915032..0871c3dadce1 100644 --- a/trunk/fs/sysfs/group.c +++ b/trunk/fs/sysfs/group.c @@ -77,12 +77,7 @@ void sysfs_remove_group(struct kobject * kobj, if (grp->name) { sd = sysfs_get_dirent(dir_sd, grp->name); - if (!sd) { - printk(KERN_WARNING "sysfs group %p not found for " - "kobject '%s'\n", grp, kobject_name(kobj)); - WARN_ON(!sd); - return; - } + BUG_ON(!sd); } else sd = sysfs_get(dir_sd); diff --git a/trunk/include/asm-arm/arch-pxa/pxa27x_keyboard.h b/trunk/include/asm-arm/arch-pxa/pxa27x_keyboard.h new file mode 100644 index 000000000000..3aaff923b2ca --- /dev/null +++ b/trunk/include/asm-arm/arch-pxa/pxa27x_keyboard.h @@ -0,0 +1,13 @@ +#define PXAKBD_MAXROW 8 +#define PXAKBD_MAXCOL 8 + +struct pxa27x_keyboard_platform_data { + int nr_rows, nr_cols; + int keycodes[PXAKBD_MAXROW][PXAKBD_MAXCOL]; + int gpio_modes[PXAKBD_MAXROW + PXAKBD_MAXCOL]; + +#ifdef CONFIG_PM + u32 reg_kpc; + u32 reg_kprec; +#endif +}; diff --git a/trunk/include/asm-arm/arch-pxa/pxa27x_keypad.h b/trunk/include/asm-arm/arch-pxa/pxa27x_keypad.h deleted file mode 100644 index 644f7609b523..000000000000 --- a/trunk/include/asm-arm/arch-pxa/pxa27x_keypad.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __ASM_ARCH_PXA27x_KEYPAD_H -#define __ASM_ARCH_PXA27x_KEYPAD_H - -#include - -#define MAX_MATRIX_KEY_ROWS (8) -#define MAX_MATRIX_KEY_COLS (8) - -/* pxa3xx keypad platform specific parameters - * - * NOTE: - * 1. direct_key_num indicates the number of keys in the direct keypad - * _plus_ the number of rotary-encoder sensor inputs, this can be - * left as 0 if only rotary encoders are enabled, the driver will - * automatically calculate this - * - * 2. direct_key_map is the key code map for the direct keys, if rotary - * encoder(s) are enabled, direct key 0/1(2/3) will be ignored - * - * 3. rotary can be either interpreted as a relative input event (e.g. - * REL_WHEEL/REL_HWHEEL) or specific keys (e.g. UP/DOWN/LEFT/RIGHT) - * - * 4. matrix key and direct key will use the same debounce_interval by - * default, which should be sufficient in most cases - */ -struct pxa27x_keypad_platform_data { - - /* code map for the matrix keys */ - unsigned int matrix_key_rows; - unsigned int matrix_key_cols; - unsigned int *matrix_key_map; - int matrix_key_map_size; - - /* direct keys */ - int direct_key_num; - unsigned int direct_key_map[8]; - - /* rotary encoders 0 */ - int enable_rotary0; - int rotary0_rel_code; - int rotary0_up_key; - int rotary0_down_key; - - /* rotary encoders 1 */ - int enable_rotary1; - int rotary1_rel_code; - int rotary1_up_key; - int rotary1_down_key; - - /* key debounce interval */ - unsigned int debounce_interval; -}; - -#define KEY(row, col, val) (((row) << 28) | ((col) << 24) | (val)) - -#endif /* __ASM_ARCH_PXA27x_KEYPAD_H */ diff --git a/trunk/include/asm-arm/arch-pxa/tosa.h b/trunk/include/asm-arm/arch-pxa/tosa.h index c05e4faf85a6..c3364a2c4758 100644 --- a/trunk/include/asm-arm/arch-pxa/tosa.h +++ b/trunk/include/asm-arm/arch-pxa/tosa.h @@ -163,34 +163,4 @@ extern struct platform_device tosascoop_jc_device; extern struct platform_device tosascoop_device; - -#define TOSA_KEY_SYNC KEY_102ND /* ??? */ - - -#ifndef CONFIG_KEYBOARD_TOSA_USE_EXT_KEYCODES -#define TOSA_KEY_RECORD KEY_YEN -#define TOSA_KEY_ADDRESSBOOK KEY_KATAKANA -#define TOSA_KEY_CANCEL KEY_ESC -#define TOSA_KEY_CENTER KEY_HIRAGANA -#define TOSA_KEY_OK KEY_HENKAN -#define TOSA_KEY_CALENDAR KEY_KATAKANAHIRAGANA -#define TOSA_KEY_HOMEPAGE KEY_HANGEUL -#define TOSA_KEY_LIGHT KEY_MUHENKAN -#define TOSA_KEY_MENU KEY_HANJA -#define TOSA_KEY_FN KEY_RIGHTALT -#define TOSA_KEY_MAIL KEY_ZENKAKUHANKAKU -#else -#define TOSA_KEY_RECORD KEY_RECORD -#define TOSA_KEY_ADDRESSBOOK KEY_ADDRESSBOOK -#define TOSA_KEY_CANCEL KEY_CANCEL -#define TOSA_KEY_CENTER KEY_SELECT /* ??? */ -#define TOSA_KEY_OK KEY_OK -#define TOSA_KEY_CALENDAR KEY_CALENDAR -#define TOSA_KEY_HOMEPAGE KEY_HOMEPAGE -#define TOSA_KEY_LIGHT KEY_KBDILLUMTOGGLE -#define TOSA_KEY_MENU KEY_MENU -#define TOSA_KEY_FN KEY_FN -#define TOSA_KEY_MAIL KEY_MAIL -#endif - #endif /* _ASM_ARCH_TOSA_H_ */ diff --git a/trunk/include/linux/enclosure.h b/trunk/include/linux/enclosure.h deleted file mode 100644 index a5978f18ca40..000000000000 --- a/trunk/include/linux/enclosure.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Enclosure Services - * - * Copyright (C) 2008 James Bottomley - * -**----------------------------------------------------------------------------- -** -** This program is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License -** version 2 as published by the Free Software Foundation. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -**----------------------------------------------------------------------------- -*/ -#ifndef _LINUX_ENCLOSURE_H_ -#define _LINUX_ENCLOSURE_H_ - -#include -#include - -/* A few generic types ... taken from ses-2 */ -enum enclosure_component_type { - ENCLOSURE_COMPONENT_DEVICE = 0x01, - ENCLOSURE_COMPONENT_ARRAY_DEVICE = 0x17, -}; - -/* ses-2 common element status */ -enum enclosure_status { - ENCLOSURE_STATUS_UNSUPPORTED = 0, - ENCLOSURE_STATUS_OK, - ENCLOSURE_STATUS_CRITICAL, - ENCLOSURE_STATUS_NON_CRITICAL, - ENCLOSURE_STATUS_UNRECOVERABLE, - ENCLOSURE_STATUS_NOT_INSTALLED, - ENCLOSURE_STATUS_UNKNOWN, - ENCLOSURE_STATUS_UNAVAILABLE, -}; - -/* SFF-8485 activity light settings */ -enum enclosure_component_setting { - ENCLOSURE_SETTING_DISABLED = 0, - ENCLOSURE_SETTING_ENABLED = 1, - ENCLOSURE_SETTING_BLINK_A_ON_OFF = 2, - ENCLOSURE_SETTING_BLINK_A_OFF_ON = 3, - ENCLOSURE_SETTING_BLINK_B_ON_OFF = 6, - ENCLOSURE_SETTING_BLINK_B_OFF_ON = 7, -}; - -struct enclosure_device; -struct enclosure_component; -struct enclosure_component_callbacks { - void (*get_status)(struct enclosure_device *, - struct enclosure_component *); - int (*set_status)(struct enclosure_device *, - struct enclosure_component *, - enum enclosure_status); - void (*get_fault)(struct enclosure_device *, - struct enclosure_component *); - int (*set_fault)(struct enclosure_device *, - struct enclosure_component *, - enum enclosure_component_setting); - void (*get_active)(struct enclosure_device *, - struct enclosure_component *); - int (*set_active)(struct enclosure_device *, - struct enclosure_component *, - enum enclosure_component_setting); - void (*get_locate)(struct enclosure_device *, - struct enclosure_component *); - int (*set_locate)(struct enclosure_device *, - struct enclosure_component *, - enum enclosure_component_setting); -}; - - -struct enclosure_component { - void *scratch; - struct class_device cdev; - enum enclosure_component_type type; - int number; - int fault; - int active; - int locate; - enum enclosure_status status; -}; - -struct enclosure_device { - void *scratch; - struct list_head node; - struct class_device cdev; - struct enclosure_component_callbacks *cb; - int components; - struct enclosure_component component[0]; -}; - -static inline struct enclosure_device * -to_enclosure_device(struct class_device *dev) -{ - return container_of(dev, struct enclosure_device, cdev); -} - -static inline struct enclosure_component * -to_enclosure_component(struct class_device *dev) -{ - return container_of(dev, struct enclosure_component, cdev); -} - -struct enclosure_device * -enclosure_register(struct device *, const char *, int, - struct enclosure_component_callbacks *); -void enclosure_unregister(struct enclosure_device *); -struct enclosure_component * -enclosure_component_register(struct enclosure_device *, unsigned int, - enum enclosure_component_type, const char *); -int enclosure_add_device(struct enclosure_device *enclosure, int component, - struct device *dev); -int enclosure_remove_device(struct enclosure_device *enclosure, int component); -struct enclosure_device *enclosure_find(struct device *dev); -int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *), - void *data); - -#endif /* _LINUX_ENCLOSURE_H_ */ diff --git a/trunk/include/linux/hrtimer.h b/trunk/include/linux/hrtimer.h index 203591e23210..8371b664b41f 100644 --- a/trunk/include/linux/hrtimer.h +++ b/trunk/include/linux/hrtimer.h @@ -225,14 +225,11 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer) * idea of the (in)accuracy of timers. Timer values are rounded up to * this resolution values. */ -# define HIGH_RES_NSEC 1 -# define KTIME_HIGH_RES (ktime_t) { .tv64 = HIGH_RES_NSEC } -# define MONOTONIC_RES_NSEC HIGH_RES_NSEC +# define KTIME_HIGH_RES (ktime_t) { .tv64 = 1 } # define KTIME_MONOTONIC_RES KTIME_HIGH_RES #else -# define MONOTONIC_RES_NSEC LOW_RES_NSEC # define KTIME_MONOTONIC_RES KTIME_LOW_RES /* diff --git a/trunk/include/linux/input.h b/trunk/include/linux/input.h index 1bdc39a8c76c..056a17a4f34f 100644 --- a/trunk/include/linux/input.h +++ b/trunk/include/linux/input.h @@ -1020,6 +1020,7 @@ struct ff_effect { * @going_away: marks devices that are in a middle of unregistering and * causes input_open_device*() fail with -ENODEV. * @dev: driver model's view of this device + * @cdev: union for struct device pointer * @h_list: list of input handles associated with the device. When * accessing the list dev->mutex must be held * @node: used to place the device onto input_dev_list @@ -1084,6 +1085,9 @@ struct input_dev { int going_away; struct device dev; + union { /* temporarily so while we switching to struct device */ + struct device *dev; + } cdev; struct list_head h_list; struct list_head node; @@ -1307,9 +1311,6 @@ static inline void input_set_abs_params(struct input_dev *dev, int axis, int min dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis); } -int input_get_keycode(struct input_dev *dev, int scancode, int *keycode); -int input_set_keycode(struct input_dev *dev, int scancode, int keycode); - extern struct class input_class; /** diff --git a/trunk/include/linux/ktime.h b/trunk/include/linux/ktime.h index 36c542b70c6d..a6ddec141f96 100644 --- a/trunk/include/linux/ktime.h +++ b/trunk/include/linux/ktime.h @@ -316,8 +316,7 @@ static inline ktime_t ktime_sub_us(const ktime_t kt, const u64 usec) * idea of the (in)accuracy of timers. Timer values are rounded up to * this resolution values. */ -#define LOW_RES_NSEC TICK_NSEC -#define KTIME_LOW_RES (ktime_t){ .tv64 = LOW_RES_NSEC } +#define KTIME_LOW_RES (ktime_t){ .tv64 = TICK_NSEC } /* Get the monotonic time in timespec format: */ extern void ktime_get_ts(struct timespec *ts); diff --git a/trunk/include/scsi/iscsi_proto.h b/trunk/include/scsi/iscsi_proto.h index 5ffec8ad6964..318a909e7ae1 100644 --- a/trunk/include/scsi/iscsi_proto.h +++ b/trunk/include/scsi/iscsi_proto.h @@ -45,8 +45,8 @@ /* initiator tags; opaque for target */ typedef uint32_t __bitwise__ itt_t; /* below makes sense only for initiator that created this tag */ -#define build_itt(itt, age) ((__force itt_t)\ - ((itt) | ((age) << ISCSI_AGE_SHIFT))) +#define build_itt(itt, id, age) ((__force itt_t)\ + ((itt) | ((id) << ISCSI_CID_SHIFT) | ((age) << ISCSI_AGE_SHIFT))) #define get_itt(itt) ((__force uint32_t)(itt_t)(itt) & ISCSI_ITT_MASK) #define RESERVED_ITT ((__force itt_t)0xffffffff) diff --git a/trunk/include/scsi/libiscsi.h b/trunk/include/scsi/libiscsi.h index 7b90b63fb5c7..889f51fabab9 100644 --- a/trunk/include/scsi/libiscsi.h +++ b/trunk/include/scsi/libiscsi.h @@ -70,6 +70,8 @@ enum { #define ISCSI_SUSPEND_BIT 1 #define ISCSI_ITT_MASK (0xfff) +#define ISCSI_CID_SHIFT 12 +#define ISCSI_CID_MASK (0xffff << ISCSI_CID_SHIFT) #define ISCSI_AGE_SHIFT 28 #define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT) @@ -133,14 +135,6 @@ static inline void* iscsi_next_hdr(struct iscsi_cmd_task *ctask) return (void*)ctask->hdr + ctask->hdr_len; } -/* Connection's states */ -enum { - ISCSI_CONN_INITIAL_STAGE, - ISCSI_CONN_STARTED, - ISCSI_CONN_STOPPED, - ISCSI_CONN_CLEANUP_WAIT, -}; - struct iscsi_conn { struct iscsi_cls_conn *cls_conn; /* ptr to class connection */ void *dd_data; /* iscsi_transport data */ @@ -233,17 +227,6 @@ struct iscsi_pool { int max; /* Max number of elements */ }; -/* Session's states */ -enum { - ISCSI_STATE_FREE = 1, - ISCSI_STATE_LOGGED_IN, - ISCSI_STATE_FAILED, - ISCSI_STATE_TERMINATE, - ISCSI_STATE_IN_RECOVERY, - ISCSI_STATE_RECOVERY_FAILED, - ISCSI_STATE_LOGGING_OUT, -}; - struct iscsi_session { /* * Syncs up the scsi eh thread with the iscsi eh thread when sending @@ -342,10 +325,6 @@ extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session, #define session_to_cls(_sess) \ hostdata_session(_sess->host->hostdata) -#define iscsi_session_printk(prefix, _sess, fmt, a...) \ - iscsi_cls_session_printk(prefix, \ - (struct iscsi_cls_session *)session_to_cls(_sess), fmt, ##a) - /* * connection management */ @@ -360,9 +339,6 @@ extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err); extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, char *buf); -#define iscsi_conn_printk(prefix, _c, fmt, a...) \ - iscsi_cls_conn_printk(prefix, _c->cls_conn, fmt, ##a) - /* * pdu and task processing */ @@ -373,6 +349,8 @@ extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *, char *, uint32_t); extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, char *, int); +extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, + char *, int); extern int iscsi_verify_itt(struct iscsi_conn *, struct iscsi_hdr *, uint32_t *); extern void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask); diff --git a/trunk/include/scsi/scsi.h b/trunk/include/scsi/scsi.h index 1f74bcd603fe..82251575a9b4 100644 --- a/trunk/include/scsi/scsi.h +++ b/trunk/include/scsi/scsi.h @@ -235,20 +235,6 @@ static inline int scsi_status_is_good(int status) #define TYPE_RBC 0x0e #define TYPE_NO_LUN 0x7f -/* SCSI protocols; these are taken from SPC-3 section 7.5 */ -enum scsi_protocol { - SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */ - SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */ - SCSI_PROTOCOL_SSA = 2, /* Serial Storage Architecture - Obsolete */ - SCSI_PROTOCOL_SBP = 3, /* firewire */ - SCSI_PROTOCOL_SRP = 4, /* Infiniband RDMA */ - SCSI_PROTOCOL_ISCSI = 5, - SCSI_PROTOCOL_SAS = 6, - SCSI_PROTOCOL_ADT = 7, /* Media Changers */ - SCSI_PROTOCOL_ATA = 8, - SCSI_PROTOCOL_UNSPEC = 0xf, /* No specific protocol */ -}; - /* Returns a human-readable name for the device */ extern const char * scsi_device_type(unsigned type); diff --git a/trunk/include/scsi/scsi_host.h b/trunk/include/scsi/scsi_host.h index d1299e999723..5c58d594126a 100644 --- a/trunk/include/scsi/scsi_host.h +++ b/trunk/include/scsi/scsi_host.h @@ -280,45 +280,39 @@ struct scsi_host_template { * If the host wants to be called before the scan starts, but * after the midlayer has set up ready for the scan, it can fill * in this function. - * - * Status: OPTIONAL */ void (* scan_start)(struct Scsi_Host *); /* - * Fill in this function to allow the queue depth of this host - * to be changeable (on a per device basis). Returns either + * fill in this function to allow the queue depth of this host + * to be changeable (on a per device basis). returns either * the current queue depth setting (may be different from what * was passed in) or an error. An error should only be * returned if the requested depth is legal but the driver was * unable to set it. If the requested depth is illegal, the * driver should set and return the closest legal queue depth. * - * Status: OPTIONAL */ int (* change_queue_depth)(struct scsi_device *, int); /* - * Fill in this function to allow the changing of tag types + * fill in this function to allow the changing of tag types * (this also allows the enabling/disabling of tag command * queueing). An error should only be returned if something * went wrong in the driver while trying to set the tag type. * If the driver doesn't support the requested tag type, then * it should set the closest type it does support without * returning an error. Returns the actual tag type set. - * - * Status: OPTIONAL */ int (* change_queue_type)(struct scsi_device *, int); /* - * This function determines the BIOS parameters for a given + * 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) * - * Status: OPTIONAL - */ + * Status: OPTIONAL */ int (* bios_param)(struct scsi_device *, struct block_device *, sector_t, int []); @@ -357,7 +351,7 @@ struct scsi_host_template { /* * This determines if we will use a non-interrupt driven - * or an interrupt driven scheme. It is set to the maximum number + * or an interrupt driven scheme, It is set to the maximum number * of simultaneous commands a given host adapter will accept. */ int can_queue; @@ -378,12 +372,12 @@ struct scsi_host_template { unsigned short sg_tablesize; /* - * Set this if the host adapter has limitations beside segment count. + * If the host adapter has limitations beside segment count */ unsigned short max_sectors; /* - * DMA scatter gather segment boundary limit. A segment crossing this + * dma scatter gather segment boundary limit. a segment crossing this * boundary will be split in two. */ unsigned long dma_boundary; @@ -392,7 +386,7 @@ struct scsi_host_template { * 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). + * individual devices (e.g. 256 for SCSI-1) */ #define SCSI_DEFAULT_MAX_SECTORS 1024 @@ -419,12 +413,12 @@ struct scsi_host_template { unsigned supported_mode:2; /* - * True if this host adapter uses unchecked DMA onto an ISA bus. + * 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. + * 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 @@ -434,7 +428,7 @@ struct scsi_host_template { unsigned use_clustering:1; /* - * True for emulated SCSI host adapters (e.g. ATAPI). + * True for emulated SCSI host adapters (e.g. ATAPI) */ unsigned emulated:1; @@ -444,12 +438,12 @@ struct scsi_host_template { unsigned skip_settle_delay:1; /* - * True if we are using ordered write support. + * ordered write support */ unsigned ordered_tag:1; /* - * Countdown for host blocking with no commands outstanding. + * Countdown for host blocking with no commands outstanding */ unsigned int max_host_blocked; @@ -528,8 +522,8 @@ struct Scsi_Host { struct scsi_transport_template *transportt; /* - * Area to keep a shared tag map (if needed, will be - * NULL if not). + * area to keep a shared tag map (if needed, will be + * NULL if not) */ struct blk_queue_tag *bqt; @@ -602,16 +596,16 @@ struct Scsi_Host { /* * Host uses correct SCSI ordering not PC ordering. The bit is * set for the minority of drivers whose authors actually read - * the spec ;). + * the spec ;) */ unsigned reverse_ordering:1; /* - * Ordered write support + * ordered write support */ unsigned ordered_tag:1; - /* Task mgmt function in progress */ + /* task mgmt function in progress */ unsigned tmf_in_progress:1; /* Asynchronous scan in progress */ diff --git a/trunk/include/scsi/scsi_transport_iscsi.h b/trunk/include/scsi/scsi_transport_iscsi.h index dbc96ef4cc72..404f11d331d6 100644 --- a/trunk/include/scsi/scsi_transport_iscsi.h +++ b/trunk/include/scsi/scsi_transport_iscsi.h @@ -149,6 +149,13 @@ extern void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error); extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, char *data, uint32_t data_size); + +/* Connection's states */ +#define ISCSI_CONN_INITIAL_STAGE 0 +#define ISCSI_CONN_STARTED 1 +#define ISCSI_CONN_STOPPED 2 +#define ISCSI_CONN_CLEANUP_WAIT 3 + struct iscsi_cls_conn { struct list_head conn_list; /* item in connlist */ void *dd_data; /* LLD private data */ @@ -162,31 +169,27 @@ struct iscsi_cls_conn { #define iscsi_dev_to_conn(_dev) \ container_of(_dev, struct iscsi_cls_conn, dev) -#define iscsi_conn_to_session(_conn) \ - iscsi_dev_to_session(_conn->dev.parent) - -/* iscsi class session state */ -enum { - ISCSI_SESSION_LOGGED_IN, - ISCSI_SESSION_FAILED, - ISCSI_SESSION_FREE, -}; +/* Session's states */ +#define ISCSI_STATE_FREE 1 +#define ISCSI_STATE_LOGGED_IN 2 +#define ISCSI_STATE_FAILED 3 +#define ISCSI_STATE_TERMINATE 4 +#define ISCSI_STATE_IN_RECOVERY 5 +#define ISCSI_STATE_RECOVERY_FAILED 6 +#define ISCSI_STATE_LOGGING_OUT 7 struct iscsi_cls_session { struct list_head sess_list; /* item in session_list */ struct list_head host_list; struct iscsi_transport *transport; - spinlock_t lock; - struct work_struct scan_work; - struct work_struct unbind_work; /* recovery fields */ int recovery_tmo; struct delayed_work recovery_work; + struct work_struct unbind_work; int target_id; - int state; int sid; /* session id */ void *dd_data; /* LLD private data */ struct device dev; /* sysfs transport/container device */ @@ -203,22 +206,14 @@ struct iscsi_cls_session { struct iscsi_host { struct list_head sessions; - atomic_t nr_scans; struct mutex mutex; - struct workqueue_struct *scan_workq; - char scan_workq_name[KOBJ_NAME_LEN]; + struct workqueue_struct *unbind_workq; + char unbind_workq_name[KOBJ_NAME_LEN]; }; /* * session and connection functions that can be used by HW iSCSI LLDs */ -#define iscsi_cls_session_printk(prefix, _cls_session, fmt, a...) \ - dev_printk(prefix, &(_cls_session)->dev, fmt, ##a) - -#define iscsi_cls_conn_printk(prefix, _cls_conn, fmt, a...) \ - dev_printk(prefix, &(_cls_conn)->dev, fmt, ##a) - -extern int iscsi_session_chkready(struct iscsi_cls_session *session); extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport); extern int iscsi_add_session(struct iscsi_cls_session *session, @@ -236,6 +231,6 @@ extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess, extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); extern void iscsi_unblock_session(struct iscsi_cls_session *session); extern void iscsi_block_session(struct iscsi_cls_session *session); -extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time); + #endif diff --git a/trunk/mm/slub.c b/trunk/mm/slub.c index 3f056677fa8f..2dacaf519c4d 100644 --- a/trunk/mm/slub.c +++ b/trunk/mm/slub.c @@ -2601,6 +2601,7 @@ EXPORT_SYMBOL(ksize); void kfree(const void *x) { struct page *page; + void *object = (void *)x; if (unlikely(ZERO_OR_NULL_PTR(x))) return; @@ -2610,7 +2611,7 @@ void kfree(const void *x) put_page(page); return; } - slab_free(page->slab, page, (void *)x, __builtin_return_address(0)); + slab_free(page->slab, page, object, __builtin_return_address(0)); } EXPORT_SYMBOL(kfree);