aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/pcmcia/Kconfig9
-rw-r--r--drivers/char/pcmcia/Makefile2
-rw-r--r--drivers/char/pcmcia/ipwireless/Makefile10
-rw-r--r--drivers/char/pcmcia/ipwireless/hardware.c1787
-rw-r--r--drivers/char/pcmcia/ipwireless/hardware.h64
-rw-r--r--drivers/char/pcmcia/ipwireless/main.c501
-rw-r--r--drivers/char/pcmcia/ipwireless/main.h70
-rw-r--r--drivers/char/pcmcia/ipwireless/network.c512
-rw-r--r--drivers/char/pcmcia/ipwireless/network.h55
-rw-r--r--drivers/char/pcmcia/ipwireless/setup_protocol.h108
-rw-r--r--drivers/char/pcmcia/ipwireless/tty.c688
-rw-r--r--drivers/char/pcmcia/ipwireless/tty.h48
-rw-r--r--drivers/firmware/dmi_scan.c62
-rw-r--r--drivers/hwmon/Kconfig30
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/abituguru3.c1
-rw-r--r--drivers/hwmon/adm1021.c1
-rw-r--r--drivers/hwmon/adm1025.c393
-rw-r--r--drivers/hwmon/adm1026.c632
-rw-r--r--drivers/hwmon/adm1031.c501
-rw-r--r--drivers/hwmon/adm9240.c27
-rw-r--r--drivers/hwmon/ads7828.c297
-rw-r--r--drivers/hwmon/adt7470.c100
-rw-r--r--drivers/hwmon/asb100.c395
-rw-r--r--drivers/hwmon/dme1737.c23
-rw-r--r--drivers/hwmon/ds1621.c1
-rw-r--r--drivers/hwmon/f71805f.c6
-rw-r--r--drivers/hwmon/f71882fg.c6
-rw-r--r--drivers/hwmon/fscher.c1
-rw-r--r--drivers/hwmon/fschmd.c94
-rw-r--r--drivers/hwmon/fscpos.c1
-rw-r--r--drivers/hwmon/gl518sm.c269
-rw-r--r--drivers/hwmon/gl520sm.c648
-rw-r--r--drivers/hwmon/it87.c88
-rw-r--r--drivers/hwmon/lm75.c1
-rw-r--r--drivers/hwmon/lm77.c20
-rw-r--r--drivers/hwmon/lm78.c7
-rw-r--r--drivers/hwmon/lm80.c328
-rw-r--r--drivers/hwmon/lm83.c1
-rw-r--r--drivers/hwmon/lm85.c64
-rw-r--r--drivers/hwmon/lm87.c29
-rw-r--r--drivers/hwmon/lm90.c27
-rw-r--r--drivers/hwmon/lm92.c1
-rw-r--r--drivers/hwmon/pc87360.c6
-rw-r--r--drivers/hwmon/pc87427.c6
-rw-r--r--drivers/hwmon/smsc47b397.c6
-rw-r--r--drivers/hwmon/smsc47m1.c6
-rw-r--r--drivers/hwmon/smsc47m192.c3
-rw-r--r--drivers/hwmon/vt1211.c8
-rw-r--r--drivers/hwmon/vt8231.c2
-rw-r--r--drivers/hwmon/w83627ehf.c29
-rw-r--r--drivers/hwmon/w83627hf.c225
-rw-r--r--drivers/hwmon/w83781d.c49
-rw-r--r--drivers/hwmon/w83791d.c6
-rw-r--r--drivers/hwmon/w83793.c13
-rw-r--r--drivers/hwmon/w83l785ts.c1
-rw-r--r--drivers/hwmon/w83l786ng.c821
-rw-r--r--drivers/i2c/chips/eeprom.c1
-rw-r--r--drivers/i2c/chips/pcf8574.c1
-rw-r--r--drivers/i2c/chips/pcf8591.c1
-rw-r--r--drivers/misc/Kconfig9
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/enclosure.c484
-rw-r--r--drivers/scsi/Kconfig93
-rw-r--r--drivers/scsi/Makefile12
-rw-r--r--drivers/scsi/NCR53C9x.c3654
-rw-r--r--drivers/scsi/NCR53C9x.h668
-rw-r--r--drivers/scsi/aacraid/aachba.c81
-rw-r--r--drivers/scsi/aacraid/commctrl.c26
-rw-r--r--drivers/scsi/aacraid/linit.c28
-rw-r--r--drivers/scsi/advansys.c6
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h4
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c87
-rw-r--r--drivers/scsi/arm/acornscsi.c14
-rw-r--r--drivers/scsi/arm/scsi.h87
-rw-r--r--drivers/scsi/blz1230.c353
-rw-r--r--drivers/scsi/blz2060.c306
-rw-r--r--drivers/scsi/cyberstorm.c377
-rw-r--r--drivers/scsi/cyberstormII.c314
-rw-r--r--drivers/scsi/dc395x.c2
-rw-r--r--drivers/scsi/dec_esp.c687
-rw-r--r--drivers/scsi/fastlane.c421
-rw-r--r--drivers/scsi/iscsi_tcp.c57
-rw-r--r--drivers/scsi/libiscsi.c137
-rw-r--r--drivers/scsi/mac_esp.c751
-rw-r--r--drivers/scsi/mca_53c9x.c520
-rw-r--r--drivers/scsi/oktagon_esp.c606
-rw-r--r--drivers/scsi/oktagon_io.S194
-rw-r--r--drivers/scsi/ps3rom.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c24
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c87
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h7
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c27
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c404
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c36
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c1
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c75
-rw-r--r--drivers/scsi/scsi.c5
-rw-r--r--drivers/scsi/scsi_lib.c1
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c238
-rw-r--r--drivers/scsi/sd.c34
-rw-r--r--drivers/scsi/ses.c689
-rw-r--r--drivers/scsi/sg.c23
-rw-r--r--drivers/scsi/sr.c49
-rw-r--r--drivers/scsi/sr.h1
-rw-r--r--drivers/scsi/sr_ioctl.c3
-rw-r--r--drivers/scsi/sun3x_esp.c546
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_hipd.c2
-rw-r--r--drivers/scsi/u14-34f.c2
113 files changed, 9667 insertions, 11669 deletions
diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig
index f25facd97bb..00b8a84b031 100644
--- a/drivers/char/pcmcia/Kconfig
+++ b/drivers/char/pcmcia/Kconfig
@@ -43,5 +43,14 @@ 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/drivers/char/pcmcia/Makefile b/drivers/char/pcmcia/Makefile
index 0aae20985d5..be8f287aa39 100644
--- a/drivers/char/pcmcia/Makefile
+++ b/drivers/char/pcmcia/Makefile
@@ -4,6 +4,8 @@
# 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/drivers/char/pcmcia/ipwireless/Makefile b/drivers/char/pcmcia/ipwireless/Makefile
new file mode 100644
index 00000000000..b71eb593643
--- /dev/null
+++ b/drivers/char/pcmcia/ipwireless/Makefile
@@ -0,0 +1,10 @@
+#
+# 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/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c
new file mode 100644
index 00000000000..1f978ff87fa
--- /dev/null
+++ b/drivers/char/pcmcia/ipwireless/hardware.c
@@ -0,0 +1,1787 @@
+/*
+ * IPWireless 3G PCMCIA Network Driver
+ *
+ * Original code
+ * by Stephen Blackheath <stephen@blacksapphire.com>,
+ * Ben Martel <benm@symmetric.co.nz>
+ *
+ * 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 <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#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/drivers/char/pcmcia/ipwireless/hardware.h b/drivers/char/pcmcia/ipwireless/hardware.h
new file mode 100644
index 00000000000..c83190ffb0e
--- /dev/null
+++ b/drivers/char/pcmcia/ipwireless/hardware.h
@@ -0,0 +1,64 @@
+/*
+ * IPWireless 3G PCMCIA Network Driver
+ *
+ * Original code
+ * by Stephen Blackheath <stephen@blacksapphire.com>,
+ * Ben Martel <benm@symmetric.co.nz>
+ *
+ * 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 <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#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/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c
new file mode 100644
index 00000000000..00c7f8407e3
--- /dev/null
+++ b/drivers/char/pcmcia/ipwireless/main.c
@@ -0,0 +1,501 @@
+/*
+ * IPWireless 3G PCMCIA Network Driver
+ *
+ * Original code
+ * by Stephen Blackheath <stephen@blacksapphire.com>,
+ * Ben Martel <benm@symmetric.co.nz>
+ *
+ * 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 <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/device_id.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cs.h>
+
+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/drivers/char/pcmcia/ipwireless/main.h b/drivers/char/pcmcia/ipwireless/main.h
new file mode 100644
index 00000000000..1bfdcc8d47d
--- /dev/null
+++ b/drivers/char/pcmcia/ipwireless/main.h
@@ -0,0 +1,70 @@
+/*
+ * IPWireless 3G PCMCIA Network Driver
+ *
+ * Original code
+ * by Stephen Blackheath <stephen@blacksapphire.com>,
+ * Ben Martel <benm@symmetric.co.nz>
+ *
+ * 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 <linux/sched.h>
+#include <linux/types.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#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/drivers/char/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c
new file mode 100644
index 00000000000..ff35230058d
--- /dev/null
+++ b/drivers/char/pcmcia/ipwireless/network.c
@@ -0,0 +1,512 @@
+/*
+ * IPWireless 3G PCMCIA Network Driver
+ *
+ * Original code
+ * by Stephen Blackheath <stephen@blacksapphire.com>,
+ * Ben Martel <benm@symmetric.co.nz>
+ *
+ * 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 <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/ppp_channel.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/skbuff.h>
+
+#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/drivers/char/pcmcia/ipwireless/network.h b/drivers/char/pcmcia/ipwireless/network.h
new file mode 100644
index 00000000000..b0e1e952fd1
--- /dev/null
+++ b/drivers/char/pcmcia/ipwireless/network.h
@@ -0,0 +1,55 @@
+/*
+ * IPWireless 3G PCMCIA Network Driver
+ *
+ * Original code
+ * by Stephen Blackheath <stephen@blacksapphire.com>,
+ * Ben Martel <benm@symmetric.co.nz>
+ *
+ * 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 <linux/types.h>
+
+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/drivers/char/pcmcia/ipwireless/setup_protocol.h b/drivers/char/pcmcia/ipwireless/setup_protocol.h
new file mode 100644
index 00000000000..9d6bcc77c73
--- /dev/null
+++ b/drivers/char/pcmcia/ipwireless/setup_protocol.h
@@ -0,0 +1,108 @@
+/*
+ * IPWireless 3G PCMCIA Network Driver
+ *
+ * Original code
+ * by Stephen Blackheath <stephen@blacksapphire.com>,
+ * Ben Martel <benm@symmetric.co.nz>
+ *
+ * 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/drivers/char/pcmcia/ipwireless/tty.c b/drivers/char/pcmcia/ipwireless/tty.c
new file mode 100644
index 00000000000..42f3815c5ce
--- /dev/null
+++ b/drivers/char/pcmcia/ipwireless/tty.c
@@ -0,0 +1,688 @@
+/*
+ * IPWireless 3G PCMCIA Network Driver
+ *
+ * Original code
+ * by Stephen Blackheath <stephen@blacksapphire.com>,
+ * Ben Martel <benm@symmetric.co.nz>
+ *
+ * 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 <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/ppp_defs.h>
+#include <linux/if.h>
+#include <linux/if_ppp.h>
+#include <linux/sched.h>
+#include <linux/serial.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+
+#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/drivers/char/pcmcia/ipwireless/tty.h b/drivers/char/pcmcia/ipwireless/tty.h
new file mode 100644
index 00000000000..b0deb9168b6
--- /dev/null
+++ b/drivers/char/pcmcia/ipwireless/tty.h
@@ -0,0 +1,48 @@
+/*
+ * IPWireless 3G PCMCIA Network Driver
+ *
+ * Original code
+ * by Stephen Blackheath <stephen@blacksapphire.com>,
+ * Ben Martel <benm@symmetric.co.nz>
+ *
+ * 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 <linux/types.h>
+#include <linux/sched.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+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/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index e0bade73237..1412d7bcdbd 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -43,18 +43,12 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s)
* We have to be cautious here. We have seen BIOSes with DMI pointers
* pointing to completely the wrong place for example
*/
-static int __init dmi_table(u32 base, int len, int num,
- void (*decode)(const struct dmi_header *))
+static void dmi_table(u8 *buf, int len, int num,
+ void (*decode)(const struct dmi_header *))
{
- u8 *buf, *data;
+ u8 *data = buf;
int i = 0;
- buf = dmi_ioremap(base, len);
- if (buf == NULL)
- return -1;
-
- data = buf;
-
/*
* Stop when we see all the items the table claimed to have
* OR we run off the end of the table (also happens)
@@ -75,7 +69,23 @@ static int __init dmi_table(u32 base, int len, int num,
data += 2;
i++;
}
- dmi_iounmap(buf, len);
+}
+
+static u32 dmi_base;
+static u16 dmi_len;
+static u16 dmi_num;
+
+static int __init dmi_walk_early(void (*decode)(const struct dmi_header *))
+{
+ u8 *buf;
+
+ buf = dmi_ioremap(dmi_base, dmi_len);
+ if (buf == NULL)
+ return -1;
+
+ dmi_table(buf, dmi_len, dmi_num, decode);
+
+ dmi_iounmap(buf, dmi_len);
return 0;
}
@@ -291,9 +301,9 @@ static int __init dmi_present(const char __iomem *p)
memcpy_fromio(buf, p, 15);
if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
- u16 num = (buf[13] << 8) | buf[12];
- u16 len = (buf[7] << 8) | buf[6];
- u32 base = (buf[11] << 24) | (buf[10] << 16) |
+ dmi_num = (buf[13] << 8) | buf[12];
+ dmi_len = (buf[7] << 8) | buf[6];
+ dmi_base = (buf[11] << 24) | (buf[10] << 16) |
(buf[9] << 8) | buf[8];
/*
@@ -305,7 +315,7 @@ static int __init dmi_present(const char __iomem *p)
buf[14] >> 4, buf[14] & 0xF);
else
printk(KERN_INFO "DMI present.\n");
- if (dmi_table(base,len, num, dmi_decode) == 0)
+ if (dmi_walk_early(dmi_decode) == 0)
return 0;
}
return 1;
@@ -489,3 +499,27 @@ int dmi_get_year(int field)
return year;
}
+
+/**
+ * dmi_walk - Walk the DMI table and get called back for every record
+ * @decode: Callback function
+ *
+ * Returns -1 when the DMI table can't be reached, 0 on success.
+ */
+int dmi_walk(void (*decode)(const struct dmi_header *))
+{
+ u8 *buf;
+
+ if (!dmi_available)
+ return -1;
+
+ buf = ioremap(dmi_base, dmi_len);
+ if (buf == NULL)
+ return -1;
+
+ dmi_table(buf, dmi_len, dmi_num, decode);
+
+ iounmap(buf);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dmi_walk);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index a0445bea9f7..410ffe4e9d8 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -433,12 +433,12 @@ config SENSORS_LM85
will be called lm85.
config SENSORS_LM87
- tristate "National Semiconductor LM87"
+ tristate "National Semiconductor LM87 and compatibles"
depends on I2C
select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM87
- sensor chips.
+ and Analog Devices ADM1024 sensor chips.
This driver can also be built as a module. If so, the module
will be called lm87.
@@ -588,6 +588,16 @@ config SENSORS_SMSC47B397
This driver can also be built as a module. If so, the module
will be called smsc47b397.
+config SENSORS_ADS7828
+ tristate "Texas Instruments ADS7828"
+ depends on I2C
+ help
+ If you say yes here you get support for Texas Instruments ADS7828
+ 12-bit 8-channel ADC device.
+
+ This driver can also be built as a module. If so, the module
+ will be called ads7828.
+
config SENSORS_THMC50
tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
depends on I2C && EXPERIMENTAL
@@ -631,13 +641,13 @@ config SENSORS_VT8231
will be called vt8231.
config SENSORS_W83781D
- tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F"
+ tristate "Winbond W83781D, W83782D, W83783S, Asus AS99127F"
depends on I2C
select HWMON_VID
help
If you say yes here you get support for the Winbond W8378x series
- of sensor chips: the W83781D, W83782D, W83783S and W83627HF,
- and the similar Asus AS99127F.
+ of sensor chips: the W83781D, W83782D and W83783S, and the similar
+ Asus AS99127F.
This driver can also be built as a module. If so, the module
will be called w83781d.
@@ -683,6 +693,16 @@ config SENSORS_W83L785TS
This driver can also be built as a module. If so, the module
will be called w83l785ts.
+config SENSORS_W83L786NG
+ tristate "Winbond W83L786NG, W83L786NR"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Winbond W83L786NG
+ and W83L786NR sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called w83l786ng.
+
config SENSORS_W83627HF
tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
select HWMON_VID
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 55595f6e1aa..824161337f1 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
+obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_AMS) += ams/
@@ -68,6 +69,7 @@ obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
+obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index d9f04ce9032..ed33fddc4de 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -528,6 +528,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
{ "AUX1 Fan", 33, 2, 60, 1, 0 },
{ "AUX2 Fan", 35, 2, 60, 1, 0 },
{ "AUX3 Fan", 36, 2, 60, 1, 0 },
+ { "AUX4 Fan", 37, 2, 60, 1, 0 },
{ NULL, 0, 0, 0, 0, 0 } }
},
{ 0x001B, "unknown", {
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index ebdc6d7db23..b96be772e49 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -115,7 +115,6 @@ static struct i2c_driver adm1021_driver = {
.driver = {
.name = "adm1021",
},
- .id = I2C_DRIVERID_ADM1021,
.attach_adapter = adm1021_attach_adapter,
.detach_client = adm1021_detach_client,
};
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
index 041ecb0bdf4..e96c3725203 100644
--- a/drivers/hwmon/adm1025.c
+++ b/drivers/hwmon/adm1025.c
@@ -51,6 +51,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
@@ -74,7 +75,7 @@ I2C_CLIENT_INSMOD_2(adm1025, ne1619);
*/
#define ADM1025_REG_MAN_ID 0x3E
-#define ADM1025_REG_CHIP_ID 0x3F
+#define ADM1025_REG_CHIP_ID 0x3F
#define ADM1025_REG_CONFIG 0x40
#define ADM1025_REG_STATUS1 0x41
#define ADM1025_REG_STATUS2 0x42
@@ -92,7 +93,7 @@ I2C_CLIENT_INSMOD_2(adm1025, ne1619);
* The ADM1025 uses signed 8-bit values for temperatures.
*/
-static int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 };
+static const int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 };
#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192)
#define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \
@@ -122,7 +123,6 @@ static struct i2c_driver adm1025_driver = {
.driver = {
.name = "adm1025",
},
- .id = I2C_DRIVERID_ADM1025,
.attach_adapter = adm1025_attach_adapter,
.detach_client = adm1025_detach_client,
};
@@ -153,86 +153,96 @@ struct adm1025_data {
* Sysfs stuff
*/
-#define show_in(offset) \
-static ssize_t show_in##offset(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct adm1025_data *data = adm1025_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \
- in_scale[offset])); \
-} \
-static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct adm1025_data *data = adm1025_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \
- in_scale[offset])); \
-} \
-static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct adm1025_data *data = adm1025_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \
- in_scale[offset])); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);
-show_in(0);
-show_in(1);
-show_in(2);
-show_in(3);
-show_in(4);
-show_in(5);
-
-#define show_temp(offset) \
-static ssize_t show_temp##offset(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct adm1025_data *data = adm1025_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \
-} \
-static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct adm1025_data *data = adm1025_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \
-} \
-static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct adm1025_data *data = adm1025_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \
-}\
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp##offset, NULL);
-show_temp(1);
-show_temp(2);
+static ssize_t
+show_in(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct adm1025_data *data = adm1025_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in[index],
+ in_scale[index]));
+}
+
+static ssize_t
+show_in_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct adm1025_data *data = adm1025_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[index],
+ in_scale[index]));
+}
+
+static ssize_t
+show_in_max(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct adm1025_data *data = adm1025_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[index],
+ in_scale[index]));
+}
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct adm1025_data *data = adm1025_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[index]));
+}
+
+static ssize_t
+show_temp_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct adm1025_data *data = adm1025_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[index]));
+}
+
+static ssize_t
+show_temp_max(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct adm1025_data *data = adm1025_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index]));
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm1025_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->in_min[index] = IN_TO_REG(val, in_scale[index]);
+ i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(index),
+ data->in_min[index]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm1025_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->in_max[index] = IN_TO_REG(val, in_scale[index]);
+ i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(index),
+ data->in_max[index]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
#define set_in(offset) \
-static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct adm1025_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- data->in_min[offset] = IN_TO_REG(val, in_scale[offset]); \
- i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(offset), \
- data->in_min[offset]); \
- mutex_unlock(&data->update_lock); \
- return count; \
-} \
-static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct adm1025_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- data->in_max[offset] = IN_TO_REG(val, in_scale[offset]); \
- i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(offset), \
- data->in_max[offset]); \
- mutex_unlock(&data->update_lock); \
- return count; \
-} \
-static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
- show_in##offset##_min, set_in##offset##_min); \
-static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \
- show_in##offset##_max, set_in##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
+ show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \
+ show_in_max, set_in_max, offset)
set_in(0);
set_in(1);
set_in(2);
@@ -240,65 +250,91 @@ set_in(3);
set_in(4);
set_in(5);
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm1025_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->temp_min[index] = TEMP_TO_REG(val);
+ i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(index),
+ data->temp_min[index]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm1025_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->temp_max[index] = TEMP_TO_REG(val);
+ i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(index),
+ data->temp_max[index]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
#define set_temp(offset) \
-static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct adm1025_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- data->temp_min[offset-1] = TEMP_TO_REG(val); \
- i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(offset-1), \
- data->temp_min[offset-1]); \
- mutex_unlock(&data->update_lock); \
- return count; \
-} \
-static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct adm1025_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- data->temp_max[offset-1] = TEMP_TO_REG(val); \
- i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(offset-1), \
- data->temp_max[offset-1]); \
- mutex_unlock(&data->update_lock); \
- return count; \
-} \
-static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
- show_temp##offset##_min, set_temp##offset##_min); \
-static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
- show_temp##offset##_max, set_temp##offset##_max);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_temp, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
+ show_temp_min, set_temp_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
+ show_temp_max, set_temp_max, offset - 1)
set_temp(1);
set_temp(2);
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t
+show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1025_data *data = adm1025_update_device(dev);
return sprintf(buf, "%u\n", data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
-static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t
+show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct adm1025_data *data = adm1025_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_alarm, NULL, 14);
+
+static ssize_t
+show_vid(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1025_data *data = adm1025_update_device(dev);
return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
-static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t
+show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1025_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", data->vrm);
}
-static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct adm1025_data *data = i2c_get_clientdata(client);
+ struct adm1025_data *data = dev_get_drvdata(dev);
data->vrm = simple_strtoul(buf, NULL, 10);
return count;
}
@@ -316,27 +352,35 @@ static int adm1025_attach_adapter(struct i2c_adapter *adapter)
}
static struct attribute *adm1025_attributes[] = {
- &dev_attr_in0_input.attr,
- &dev_attr_in1_input.attr,
- &dev_attr_in2_input.attr,
- &dev_attr_in3_input.attr,
- &dev_attr_in5_input.attr,
- &dev_attr_in0_min.attr,
- &dev_attr_in1_min.attr,
- &dev_attr_in2_min.attr,
- &dev_attr_in3_min.attr,
- &dev_attr_in5_min.attr,
- &dev_attr_in0_max.attr,
- &dev_attr_in1_max.attr,
- &dev_attr_in2_max.attr,
- &dev_attr_in3_max.attr,
- &dev_attr_in5_max.attr,
- &dev_attr_temp1_input.attr,
- &dev_attr_temp2_input.attr,
- &dev_attr_temp1_min.attr,
- &dev_attr_temp2_min.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp2_max.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_fault.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_cpu0_vid.attr,
&dev_attr_vrm.attr,
@@ -347,15 +391,16 @@ static const struct attribute_group adm1025_group = {
.attrs = adm1025_attributes,
};
-static struct attribute *adm1025_attributes_opt[] = {
- &dev_attr_in4_input.attr,
- &dev_attr_in4_min.attr,
- &dev_attr_in4_max.attr,
+static struct attribute *adm1025_attributes_in4[] = {
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
NULL
};
-static const struct attribute_group adm1025_group_opt = {
- .attrs = adm1025_attributes_opt,
+static const struct attribute_group adm1025_group_in4 = {
+ .attrs = adm1025_attributes_in4,
};
/*
@@ -364,7 +409,7 @@ static const struct attribute_group adm1025_group_opt = {
*/
static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
{
- struct i2c_client *new_client;
+ struct i2c_client *client;
struct adm1025_data *data;
int err = 0;
const char *name = "";
@@ -378,14 +423,11 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit;
}
- /* The common I2C client data is placed right before the
- ADM1025-specific data. */
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &adm1025_driver;
- new_client->flags = 0;
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &adm1025_driver;
/*
* Now we do the remaining detection. A negative kind means that
@@ -397,12 +439,12 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
* requested, so both the detection and the identification steps
* are skipped.
*/
- config = i2c_smbus_read_byte_data(new_client, ADM1025_REG_CONFIG);
+ config = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
if (kind < 0) { /* detection */
if ((config & 0x80) != 0x00
- || (i2c_smbus_read_byte_data(new_client,
+ || (i2c_smbus_read_byte_data(client,
ADM1025_REG_STATUS1) & 0xC0) != 0x00
- || (i2c_smbus_read_byte_data(new_client,
+ || (i2c_smbus_read_byte_data(client,
ADM1025_REG_STATUS2) & 0xBC) != 0x00) {
dev_dbg(&adapter->dev,
"ADM1025 detection failed at 0x%02x.\n",
@@ -414,11 +456,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
if (kind <= 0) { /* identification */
u8 man_id, chip_id;
- man_id = i2c_smbus_read_byte_data(new_client,
- ADM1025_REG_MAN_ID);
- chip_id = i2c_smbus_read_byte_data(new_client,
- ADM1025_REG_CHIP_ID);
-
+ man_id = i2c_smbus_read_byte_data(client, ADM1025_REG_MAN_ID);
+ chip_id = i2c_smbus_read_byte_data(client, ADM1025_REG_CHIP_ID);
+
if (man_id == 0x41) { /* Analog Devices */
if ((chip_id & 0xF0) == 0x20) { /* ADM1025/ADM1025A */
kind = adm1025;
@@ -446,33 +486,28 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* We can fill in the remaining client fields */
- strlcpy(new_client->name, name, I2C_NAME_SIZE);
- data->valid = 0;
+ strlcpy(client->name, name, I2C_NAME_SIZE);
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
+ if ((err = i2c_attach_client(client)))
goto exit_free;
/* Initialize the ADM1025 chip */
- adm1025_init_client(new_client);
+ adm1025_init_client(client);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1025_group)))
+ if ((err = sysfs_create_group(&client->dev.kobj, &adm1025_group)))
goto exit_detach;
/* Pin 11 is either in4 (+12V) or VID4 */
if (!(config & 0x20)) {
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_in4_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in4_min))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in4_max)))
+ if ((err = sysfs_create_group(&client->dev.kobj,
+ &adm1025_group_in4)))
goto exit_remove;
}
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
@@ -481,10 +516,10 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
exit_remove:
- sysfs_remove_group(&new_client->dev.kobj, &adm1025_group);
- sysfs_remove_group(&new_client->dev.kobj, &adm1025_group_opt);
+ sysfs_remove_group(&client->dev.kobj, &adm1025_group);
+ sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4);
exit_detach:
- i2c_detach_client(new_client);
+ i2c_detach_client(client);
exit_free:
kfree(data);
exit:
@@ -540,7 +575,7 @@ static int adm1025_detach_client(struct i2c_client *client)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1025_group);
- sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt);
+ sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index 3e63c148677..8002f68240c 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -40,8 +40,8 @@ static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(adm1026);
-static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1 };
+static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 };
static int gpio_output[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 };
static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
@@ -49,46 +49,49 @@ static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
static int gpio_normal[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 };
static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
-module_param_array(gpio_input,int,NULL,0);
-MODULE_PARM_DESC(gpio_input,"List of GPIO pins (0-16) to program as inputs");
-module_param_array(gpio_output,int,NULL,0);
-MODULE_PARM_DESC(gpio_output,"List of GPIO pins (0-16) to program as "
+module_param_array(gpio_input, int, NULL, 0);
+MODULE_PARM_DESC(gpio_input, "List of GPIO pins (0-16) to program as inputs");
+module_param_array(gpio_output, int, NULL, 0);
+MODULE_PARM_DESC(gpio_output, "List of GPIO pins (0-16) to program as "
"outputs");
-module_param_array(gpio_inverted,int,NULL,0);
-MODULE_PARM_DESC(gpio_inverted,"List of GPIO pins (0-16) to program as "
+module_param_array(gpio_inverted, int, NULL, 0);
+MODULE_PARM_DESC(gpio_inverted, "List of GPIO pins (0-16) to program as "
"inverted");
-module_param_array(gpio_normal,int,NULL,0);
-MODULE_PARM_DESC(gpio_normal,"List of GPIO pins (0-16) to program as "
+module_param_array(gpio_normal, int, NULL, 0);
+MODULE_PARM_DESC(gpio_normal, "List of GPIO pins (0-16) to program as "
"normal/non-inverted");
-module_param_array(gpio_fan,int,NULL,0);
-MODULE_PARM_DESC(gpio_fan,"List of GPIO pins (0-7) to program as fan tachs");
+module_param_array(gpio_fan, int, NULL, 0);
+MODULE_PARM_DESC(gpio_fan, "List of GPIO pins (0-7) to program as fan tachs");
/* Many ADM1026 constants specified below */
/* The ADM1026 registers */
-#define ADM1026_REG_CONFIG1 0x00
-#define CFG1_MONITOR 0x01
-#define CFG1_INT_ENABLE 0x02
-#define CFG1_INT_CLEAR 0x04
-#define CFG1_AIN8_9 0x08
-#define CFG1_THERM_HOT 0x10
-#define CFG1_DAC_AFC 0x20
-#define CFG1_PWM_AFC 0x40
-#define CFG1_RESET 0x80
-#define ADM1026_REG_CONFIG2 0x01
+#define ADM1026_REG_CONFIG1 0x00
+#define CFG1_MONITOR 0x01
+#define CFG1_INT_ENABLE 0x02
+#define CFG1_INT_CLEAR 0x04
+#define CFG1_AIN8_9 0x08
+#define CFG1_THERM_HOT 0x10
+#define CFG1_DAC_AFC 0x20
+#define CFG1_PWM_AFC 0x40
+#define CFG1_RESET 0x80
+
+#define ADM1026_REG_CONFIG2 0x01
/* CONFIG2 controls FAN0/GPIO0 through FAN7/GPIO7 */
-#define ADM1026_REG_CONFIG3 0x07
-#define CFG3_GPIO16_ENABLE 0x01
-#define CFG3_CI_CLEAR 0x02
-#define CFG3_VREF_250 0x04
-#define CFG3_GPIO16_DIR 0x40
-#define CFG3_GPIO16_POL 0x80
-#define ADM1026_REG_E2CONFIG 0x13
-#define E2CFG_READ 0x01
-#define E2CFG_WRITE 0x02
-#define E2CFG_ERASE 0x04
-#define E2CFG_ROM 0x08
-#define E2CFG_CLK_EXT 0x80
+
+#define ADM1026_REG_CONFIG3 0x07
+#define CFG3_GPIO16_ENABLE 0x01
+#define CFG3_CI_CLEAR 0x02
+#define CFG3_VREF_250 0x04
+#define CFG3_GPIO16_DIR 0x40
+#define CFG3_GPIO16_POL 0x80
+
+#define ADM1026_REG_E2CONFIG 0x13
+#define E2CFG_READ 0x01
+#define E2CFG_WRITE 0x02
+#define E2CFG_ERASE 0x04
+#define E2CFG_ROM 0x08
+#define E2CFG_CLK_EXT 0x80
/* There are 10 general analog inputs and 7 dedicated inputs
* They are:
@@ -129,48 +132,48 @@ static u16 ADM1026_REG_TEMP_TMIN[] = { 0x10, 0x11, 0x12 };
static u16 ADM1026_REG_TEMP_THERM[] = { 0x0d, 0x0e, 0x0f };
static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f };
-#define ADM1026_REG_FAN(nr) (0x38 + (nr))
-#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr))
-#define ADM1026_REG_FAN_DIV_0_3 0x02
-#define ADM1026_REG_FAN_DIV_4_7 0x03
+#define ADM1026_REG_FAN(nr) (0x38 + (nr))
+#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr))
+#define ADM1026_REG_FAN_DIV_0_3 0x02
+#define ADM1026_REG_FAN_DIV_4_7 0x03
-#define ADM1026_REG_DAC 0x04
-#define ADM1026_REG_PWM 0x05
+#define ADM1026_REG_DAC 0x04
+#define ADM1026_REG_PWM 0x05
-#define ADM1026_REG_GPIO_CFG_0_3 0x08
-#define ADM1026_REG_GPIO_CFG_4_7 0x09
-#define ADM1026_REG_GPIO_CFG_8_11 0x0a
-#define ADM1026_REG_GPIO_CFG_12_15 0x0b
+#define ADM1026_REG_GPIO_CFG_0_3 0x08
+#define ADM1026_REG_GPIO_CFG_4_7 0x09
+#define ADM1026_REG_GPIO_CFG_8_11 0x0a
+#define ADM1026_REG_GPIO_CFG_12_15 0x0b
/* CFG_16 in REG_CFG3 */
-#define ADM1026_REG_GPIO_STATUS_0_7 0x24
-#define ADM1026_REG_GPIO_STATUS_8_15 0x25
+#define ADM1026_REG_GPIO_STATUS_0_7 0x24
+#define ADM1026_REG_GPIO_STATUS_8_15 0x25
/* STATUS_16 in REG_STATUS4 */
-#define ADM1026_REG_GPIO_MASK_0_7 0x1c
-#define ADM1026_REG_GPIO_MASK_8_15 0x1d
+#define ADM1026_REG_GPIO_MASK_0_7 0x1c
+#define ADM1026_REG_GPIO_MASK_8_15 0x1d
/* MASK_16 in REG_MASK4 */
-#define ADM1026_REG_COMPANY 0x16
-#define ADM1026_REG_VERSTEP 0x17
+#define ADM1026_REG_COMPANY 0x16
+#define ADM1026_REG_VERSTEP 0x17
/* These are the recognized values for the above regs */
-#define ADM1026_COMPANY_ANALOG_DEV 0x41
-#define ADM1026_VERSTEP_GENERIC 0x40
-#define ADM1026_VERSTEP_ADM1026 0x44
+#define ADM1026_COMPANY_ANALOG_DEV 0x41
+#define ADM1026_VERSTEP_GENERIC 0x40
+#define ADM1026_VERSTEP_ADM1026 0x44
-#define ADM1026_REG_MASK1 0x18
-#define ADM1026_REG_MASK2 0x19
-#define ADM1026_REG_MASK3 0x1a
-#define ADM1026_REG_MASK4 0x1b
+#define ADM1026_REG_MASK1 0x18
+#define ADM1026_REG_MASK2 0x19
+#define ADM1026_REG_MASK3 0x1a
+#define ADM1026_REG_MASK4 0x1b
-#define ADM1026_REG_STATUS1 0x20
-#define ADM1026_REG_STATUS2 0x21
-#define ADM1026_REG_STATUS3 0x22
-#define ADM1026_REG_STATUS4 0x23
+#define ADM1026_REG_STATUS1 0x20
+#define ADM1026_REG_STATUS2 0x21
+#define ADM1026_REG_STATUS3 0x22
+#define ADM1026_REG_STATUS4 0x23
#define ADM1026_FAN_ACTIVATION_TEMP_HYST -6
-#define ADM1026_FAN_CONTROL_TEMP_RANGE 20
-#define ADM1026_PWM_MAX 255
+#define ADM1026_FAN_CONTROL_TEMP_RANGE 20
+#define ADM1026_PWM_MAX 255
-/* Conversions. Rounding and limit checking is only done on the TO_REG
+/* Conversions. Rounding and limit checking is only done on the TO_REG
* variants. Note that you should be a bit careful with which arguments
* these macros are called: arguments may be evaluated more than once.
*/
@@ -186,52 +189,49 @@ static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f };
* The values in this table are based on Table II, page 15 of the
* datasheet.
*/
-static int adm1026_scaling[] = { /* .001 Volts */
- 2250, 2250, 2250, 2250, 2250, 2250,
- 1875, 1875, 1875, 1875, 3000, 3330,
+static int adm1026_scaling[] = { /* .001 Volts */
+ 2250, 2250, 2250, 2250, 2250, 2250,
+ 1875, 1875, 1875, 1875, 3000, 3330,
3330, 4995, 2250, 12000, 13875
};
#define NEG12_OFFSET 16000
-#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from))
-#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,adm1026_scaling[n],192),\
- 0,255))
-#define INS_FROM_REG(n,val) (SCALE(val,192,adm1026_scaling[n]))
+#define SCALE(val, from, to) (((val)*(to) + ((from)/2))/(from))
+#define INS_TO_REG(n, val) (SENSORS_LIMIT(SCALE(val, adm1026_scaling[n], 192),\
+ 0, 255))
+#define INS_FROM_REG(n, val) (SCALE(val, 192, adm1026_scaling[n]))
/* FAN speed is measured using 22.5kHz clock and counts for 2 pulses
* and we assume a 2 pulse-per-rev fan tach signal
* 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000
*/
-#define FAN_TO_REG(val,div) ((val)<=0 ? 0xff : SENSORS_LIMIT(1350000/((val)*\
- (div)),1,254))
-#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==0xff ? 0 : 1350000/((val)*\
- (div)))
+#define FAN_TO_REG(val, div) ((val) <= 0 ? 0xff : \
+ SENSORS_LIMIT(1350000/((val)*(div)), 1, 254))
+#define FAN_FROM_REG(val, div) ((val) == 0 ? -1:(val) == 0xff ? 0 : \
+ 1350000/((val)*(div)))
#define DIV_FROM_REG(val) (1<<(val))
-#define DIV_TO_REG(val) ((val)>=8 ? 3 : (val)>=4 ? 2 : (val)>=2 ? 1 : 0)
+#define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0)
/* Temperature is reported in 1 degC increments */
#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\
- -127,127))
+ -127, 127))
#define TEMP_FROM_REG(val) ((val) * 1000)
#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\
- -127,127))
+ -127, 127))
#define OFFSET_FROM_REG(val) ((val) * 1000)
-#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255))
+#define PWM_TO_REG(val) (SENSORS_LIMIT(val, 0, 255))
#define PWM_FROM_REG(val) (val)
#define PWM_MIN_TO_REG(val) ((val) & 0xf0)
#define PWM_MIN_FROM_REG(val) (((val) & 0xf0) + ((val) >> 4))
-/* Analog output is a voltage, and scaled to millivolts. The datasheet
- * indicates that the DAC could be used to drive the fans, but in our
+/* Analog output is a voltage, and scaled to millivolts. The datasheet
+ * indicates that the DAC could be used to drive the fans, but in our
* example board (Arima HDAMA) it isn't connected to the fans at all.
*/
-#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val)*255)+500)/2500),0,255))
+#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val)*255)+500)/2500), 0, 255))
#define DAC_FROM_REG(val) (((val)*2500)/255)
-/* Typically used with systems using a v9.1 VRM spec ? */
-#define ADM1026_INIT_VRM 91
-
/* Chip sampling rates
*
* Some sensors are not updated more frequently than once per second
@@ -243,8 +243,8 @@ static int adm1026_scaling[] = { /* .001 Volts */
* So, we keep the config data up to date in the cache
* when it is written and only sample it once every 5 *minutes*
*/
-#define ADM1026_DATA_INTERVAL (1 * HZ)
-#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ)
+#define ADM1026_DATA_INTERVAL (1 * HZ)
+#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ)
/* We allow for multiple chips in a single system.
*
@@ -261,37 +261,36 @@ struct pwm_data {
struct adm1026_data {
struct i2c_client client;
struct device *hwmon_dev;
- enum chips type;
struct mutex update_lock;
int valid; /* !=0 if following fields are valid */
unsigned long last_reading; /* In jiffies */
unsigned long last_config; /* In jiffies */
- u8 in[17]; /* Register value */
- u8 in_max[17]; /* Register value */
- u8 in_min[17]; /* Register value */
- s8 temp[3]; /* Register value */
- s8 temp_min[3]; /* Register value */
- s8 temp_max[3]; /* Register value */
- s8 temp_tmin[3]; /* Register value */
- s8 temp_crit[3]; /* Register value */
- s8 temp_offset[3]; /* Register value */
- u8 fan[8]; /* Register value */
- u8 fan_min[8]; /* Register value */
- u8 fan_div[8]; /* Decoded value */
- struct pwm_data pwm1; /* Pwm control values */
- int vid; /* Decoded value */
- u8 vrm; /* VRM version */
+ u8 in[17]; /* Register value */
+ u8 in_max[17]; /* Register value */
+ u8 in_min[17]; /* Register value */
+ s8 temp[3]; /* Register value */
+ s8 temp_min[3]; /* Register value */
+ s8 temp_max[3]; /* Register value */
+ s8 temp_tmin[3]; /* Register value */
+ s8 temp_crit[3]; /* Register value */
+ s8 temp_offset[3]; /* Register value */
+ u8 fan[8]; /* Register value */
+ u8 fan_min[8]; /* Register value */
+ u8 fan_div[8]; /* Decoded value */
+ struct pwm_data pwm1; /* Pwm control values */
+ int vid; /* Decoded value */
+ u8 vrm; /* VRM version */
u8 analog_out; /* Register value (DAC) */
- long alarms; /* Register encoding, combined */
- long alarm_mask; /* Register encoding, combined */
- long gpio; /* Register encoding, combined */
- long gpio_mask; /* Register encoding, combined */
- u8 gpio_config[17]; /* Decoded value */
- u8 config1; /* Register value */
- u8 config2; /* Register value */
- u8 config3; /* Register value */
+ long alarms; /* Register encoding, combined */
+ long alarm_mask; /* Register encoding, combined */
+ long gpio; /* Register encoding, combined */
+ long gpio_mask; /* Register encoding, combined */
+ u8 gpio_config[17]; /* Decoded value */
+ u8 config1; /* Register value */
+ u8 config2; /* Register value */
+ u8 config3; /* Register value */
};
static int adm1026_attach_adapter(struct i2c_adapter *adapter);
@@ -301,7 +300,7 @@ static int adm1026_detach_client(struct i2c_client *client);
static int adm1026_read_value(struct i2c_client *client, u8 reg);
static int adm1026_write_value(struct i2c_client *client, u8 reg, int value);
static void adm1026_print_gpio(struct i2c_client *client);
-static void adm1026_fixup_gpio(struct i2c_client *client);
+static void adm1026_fixup_gpio(struct i2c_client *client);
static struct adm1026_data *adm1026_update_device(struct device *dev);
static void adm1026_init_client(struct i2c_client *client);
@@ -311,7 +310,7 @@ static struct i2c_driver adm1026_driver = {
.name = "adm1026",
},
.attach_adapter = adm1026_attach_adapter,
- .detach_client = adm1026_detach_client,
+ .detach_client = adm1026_detach_client,
};
static int adm1026_attach_adapter(struct i2c_adapter *adapter)
@@ -355,7 +354,7 @@ static void adm1026_init_client(struct i2c_client *client)
int value, i;
struct adm1026_data *data = i2c_get_clientdata(client);
- dev_dbg(&client->dev, "Initializing device\n");
+ dev_dbg(&client->dev, "Initializing device\n");
/* Read chip config */
data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1);
data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2);
@@ -384,7 +383,6 @@ static void adm1026_init_client(struct i2c_client *client)
"and temp limits enabled.\n");
}
- value = data->config3;
if (data->config3 & CFG3_GPIO16_ENABLE) {
dev_dbg(&client->dev, "GPIO16 enabled. THERM "
"pin disabled.\n");
@@ -426,10 +424,10 @@ static void adm1026_init_client(struct i2c_client *client)
* configured, we don't want to mess with them.
* If they weren't, the default is 100% PWM, no
* control and will suffice until 'sensors -s'
- * can be run by the user. We DO set the default
+ * can be run by the user. We DO set the default
* value for pwm1.auto_pwm_min to its maximum
* so that enabling automatic pwm fan control
- * without first setting a value for pwm1.auto_pwm_min
+ * without first setting a value for pwm1.auto_pwm_min
* will not result in potentially dangerous fan speed decrease.
*/
data->pwm1.auto_pwm_min=255;
@@ -453,7 +451,7 @@ static void adm1026_init_client(struct i2c_client *client)
static void adm1026_print_gpio(struct i2c_client *client)
{
struct adm1026_data *data = i2c_get_clientdata(client);
- int i;
+ int i;
dev_dbg(&client->dev, "GPIO config is:");
for (i = 0;i <= 7;++i) {
@@ -477,7 +475,7 @@ static void adm1026_print_gpio(struct i2c_client *client)
data->gpio_config[16] & 0x02 ? "" : "!",
data->gpio_config[16] & 0x01 ? "OUT" : "IN");
} else {
- /* GPIO16 is THERM */
+ /* GPIO16 is THERM */
dev_dbg(&client->dev, "\tTHERM\n");
}
}
@@ -485,8 +483,8 @@ static void adm1026_print_gpio(struct i2c_client *client)
static void adm1026_fixup_gpio(struct i2c_client *client)
{
struct adm1026_data *data = i2c_get_clientdata(client);
- int i;
- int value;
+ int i;
+ int value;
/* Make the changes requested. */
/* We may need to unlock/stop monitoring or soft-reset the
@@ -516,14 +514,14 @@ static void adm1026_fixup_gpio(struct i2c_client *client)
}
}
- /* Inverted */
+ /* Inverted */
for (i = 0;i <= 16;++i) {
if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16) {
data->gpio_config[gpio_inverted[i]] &= ~ 0x02;
}
}
- /* Normal overrides inverted */
+ /* Normal overrides inverted */
for (i = 0;i <= 16;++i) {
if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16) {
data->gpio_config[gpio_normal[i]] |= 0x02;
@@ -569,7 +567,7 @@ static struct adm1026_data *adm1026_update_device(struct device *dev)
if (!data->valid
|| time_after(jiffies, data->last_reading + ADM1026_DATA_INTERVAL)) {
/* Things that change quickly */
- dev_dbg(&client->dev,"Reading sensor values\n");
+ dev_dbg(&client->dev, "Reading sensor values\n");
for (i = 0;i <= 16;++i) {
data->in[i] =
adm1026_read_value(client, ADM1026_REG_IN[i]);
@@ -582,18 +580,18 @@ static struct adm1026_data *adm1026_update_device(struct device *dev)
for (i = 0;i <= 2;++i) {
/* NOTE: temp[] is s8 and we assume 2's complement
- * "conversion" in the assignment */
+ * "conversion" in the assignment */
data->temp[i] =
adm1026_read_value(client, ADM1026_REG_TEMP[i]);
}
- data->pwm1.pwm = adm1026_read_value(client,
+ data->pwm1.pwm = adm1026_read_value(client,
ADM1026_REG_PWM);
- data->analog_out = adm1026_read_value(client,
+ data->analog_out = adm1026_read_value(client,
ADM1026_REG_DAC);
/* GPIO16 is MSbit of alarms, move it to gpio */
alarms = adm1026_read_value(client, ADM1026_REG_STATUS4);
- gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */
+ gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */
alarms &= 0x7f;
alarms <<= 8;
alarms |= adm1026_read_value(client, ADM1026_REG_STATUS3);
@@ -604,24 +602,24 @@ static struct adm1026_data *adm1026_update_device(struct device *dev)
data->alarms = alarms;
/* Read the GPIO values */
- gpio |= adm1026_read_value(client,
+ gpio |= adm1026_read_value(client,
ADM1026_REG_GPIO_STATUS_8_15);
gpio <<= 8;
- gpio |= adm1026_read_value(client,
+ gpio |= adm1026_read_value(client,
ADM1026_REG_GPIO_STATUS_0_7);
data->gpio = gpio;
data->last_reading = jiffies;
- }; /* last_reading */
+ }; /* last_reading */
if (!data->valid ||
time_after(jiffies, data->last_config + ADM1026_CONFIG_INTERVAL)) {
/* Things that don't change often */
dev_dbg(&client->dev, "Reading config values\n");
for (i = 0;i <= 16;++i) {
- data->in_min[i] = adm1026_read_value(client,
+ data->in_min[i] = adm1026_read_value(client,
ADM1026_REG_IN_MIN[i]);
- data->in_max[i] = adm1026_read_value(client,
+ data->in_max[i] = adm1026_read_value(client,
ADM1026_REG_IN_MAX[i]);
}
@@ -629,32 +627,32 @@ static struct adm1026_data *adm1026_update_device(struct device *dev)
| (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7)
<< 8);
for (i = 0;i <= 7;++i) {
- data->fan_min[i] = adm1026_read_value(client,
+ data->fan_min[i] = adm1026_read_value(client,
ADM1026_REG_FAN_MIN(i));
data->fan_div[i] = DIV_FROM_REG(value & 0x03);
value >>= 2;
}
for (i = 0; i <= 2; ++i) {
- /* NOTE: temp_xxx[] are s8 and we assume 2's
+ /* NOTE: temp_xxx[] are s8 and we assume 2's
* complement "conversion" in the assignment
*/
- data->temp_min[i] = adm1026_read_value(client,
+ data->temp_min[i] = adm1026_read_value(client,
ADM1026_REG_TEMP_MIN[i]);
- data->temp_max[i] = adm1026_read_value(client,
+ data->temp_max[i] = adm1026_read_value(client,
ADM1026_REG_TEMP_MAX[i]);
- data->temp_tmin[i] = adm1026_read_value(client,
+ data->temp_tmin[i] = adm1026_read_value(client,
ADM1026_REG_TEMP_TMIN[i]);
- data->temp_crit[i] = adm1026_read_value(client,
+ data->temp_crit[i] = adm1026_read_value(client,
ADM1026_REG_TEMP_THERM[i]);
- data->temp_offset[i] = adm1026_read_value(client,
+ data->temp_offset[i] = adm1026_read_value(client,
ADM1026_REG_TEMP_OFFSET[i]);
}
/* Read the STATUS/alarm masks */
- alarms = adm1026_read_value(client, ADM1026_REG_MASK4);
- gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */
- alarms = (alarms & 0x7f) << 8;
+ alarms = adm1026_read_value(client, ADM1026_REG_MASK4);
+ gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */
+ alarms = (alarms & 0x7f) << 8;
alarms |= adm1026_read_value(client, ADM1026_REG_MASK3);
alarms <<= 8;
alarms |= adm1026_read_value(client, ADM1026_REG_MASK2);
@@ -663,24 +661,24 @@ static struct adm1026_data *adm1026_update_device(struct device *dev)
data->alarm_mask = alarms;
/* Read the GPIO values */
- gpio |= adm1026_read_value(client,
+ gpio |= adm1026_read_value(client,
ADM1026_REG_GPIO_MASK_8_15);
gpio <<= 8;
gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_0_7);
data->gpio_mask = gpio;
/* Read various values from CONFIG1 */
- data->config1 = adm1026_read_value(client,
+ data->config1 = adm1026_read_value(client,
ADM1026_REG_CONFIG1);
if (data->config1 & CFG1_PWM_AFC) {
data->pwm1.enable = 2;
- data->pwm1.auto_pwm_min =
+ data->pwm1.auto_pwm_min =
PWM_MIN_FROM_REG(data->pwm1.pwm);
}
/* Read the GPIO config */
- data->config2 = adm1026_read_value(client,
+ data->config2 = adm1026_read_value(client,
ADM1026_REG_CONFIG2);
- data->config3 = adm1026_read_value(client,
+ data->config3 = adm1026_read_value(client,
ADM1026_REG_CONFIG3);
data->gpio_config[16] = (data->config3 >> 6) & 0x03;
@@ -695,7 +693,7 @@ static struct adm1026_data *adm1026_update_device(struct device *dev)
}
data->last_config = jiffies;
- }; /* last_config */
+ }; /* last_config */
dev_dbg(&client->dev, "Setting VID from GPIO11-15.\n");
data->vid = (data->gpio >> 11) & 0x1f;
@@ -710,15 +708,15 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in[nr]));
+ return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in[nr]));
}
static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]));
+ struct adm1026_data *data = adm1026_update_device(dev);
+ return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in_min[nr]));
}
static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -733,7 +731,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
data->in_min[nr] = INS_TO_REG(nr, val);
adm1026_write_value(client, ADM1026_REG_IN_MIN[nr], data->in_min[nr]);
mutex_unlock(&data->update_lock);
- return count;
+ return count;
}
static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -741,7 +739,7 @@ static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]));
+ return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in_max[nr]));
}
static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -788,13 +786,13 @@ in_reg(15);
static ssize_t show_in16(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in[16]) -
+ return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in[16]) -
NEG12_OFFSET);
}
static ssize_t show_in16_min(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_min[16])
+ struct adm1026_data *data = adm1026_update_device(dev);
+ return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in_min[16])
- NEG12_OFFSET);
}
static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
@@ -807,12 +805,12 @@ static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, c
data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET);
adm1026_write_value(client, ADM1026_REG_IN_MIN[16], data->in_min[16]);
mutex_unlock(&data->update_lock);
- return count;
+ return count;
}
static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_max[16])
+ return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in_max[16])
- NEG12_OFFSET);
}
static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
@@ -843,7 +841,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr],
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
data->fan_div[nr]));
}
static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
@@ -852,7 +850,7 @@ static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
data->fan_div[nr]));
}
static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
@@ -872,10 +870,10 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
return count;
}
-#define fan_offset(offset) \
-static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \
- offset - 1); \
-static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+#define fan_offset(offset) \
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \
+ offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
show_fan_min, set_fan_min, offset - 1);
fan_offset(1);
@@ -892,8 +890,8 @@ static void fixup_fan_min(struct device *dev, int fan, int old_div)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1026_data *data = i2c_get_clientdata(client);
- int new_min;
- int new_div = data->fan_div[fan];
+ int new_min;
+ int new_div = data->fan_div[fan];
/* 0 and 0xff are special. Don't adjust them */
if (data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff) {
@@ -913,7 +911,7 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", data->fan_div[nr]);
+ return sprintf(buf, "%d\n", data->fan_div[nr]);
}
static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -922,10 +920,10 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct adm1026_data *data = i2c_get_clientdata(client);
- int val,orig_div,new_div,shift;
+ int val, orig_div, new_div, shift;
val = simple_strtol(buf, NULL, 10);
- new_div = DIV_TO_REG(val);
+ new_div = DIV_TO_REG(val);
if (new_div == 0) {
return -EINVAL;
}
@@ -946,14 +944,14 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
}
if (data->fan_div[nr] != orig_div) {
- fixup_fan_min(dev,nr,orig_div);
+ fixup_fan_min(dev, nr, orig_div);
}
mutex_unlock(&data->update_lock);
return count;
}
-#define fan_offset_div(offset) \
-static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+#define fan_offset_div(offset) \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
show_fan_div, set_fan_div, offset - 1);
fan_offset_div(1);
@@ -972,7 +970,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp[nr]));
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
}
static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -980,7 +978,7 @@ static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]));
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));
}
static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -1004,7 +1002,7 @@ static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]));
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));
}
static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -1024,7 +1022,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
}
#define temp_reg(offset) \
-static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \
NULL, offset - 1); \
static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
show_temp_min, set_temp_min, offset - 1); \
@@ -1042,7 +1040,7 @@ static ssize_t show_temp_offset(struct device *dev,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_offset[nr]));
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_offset[nr]));
}
static ssize_t set_temp_offset(struct device *dev,
struct device_attribute *attr, const char *buf,
@@ -1076,7 +1074,7 @@ static ssize_t show_temp_auto_point1_temp_hyst(struct device *dev,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", TEMP_FROM_REG(
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(
ADM1026_FAN_ACTIVATION_TEMP_HYST + data->temp_tmin[nr]));
}
static ssize_t show_temp_auto_point2_temp(struct device *dev,
@@ -1085,7 +1083,7 @@ static ssize_t show_temp_auto_point2_temp(struct device *dev,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr] +
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_tmin[nr] +
ADM1026_FAN_CONTROL_TEMP_RANGE));
}
static ssize_t show_temp_auto_point1_temp(struct device *dev,
@@ -1094,7 +1092,7 @@ static ssize_t show_temp_auto_point1_temp(struct device *dev,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr]));
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_tmin[nr]));
}
static ssize_t set_temp_auto_point1_temp(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
@@ -1113,13 +1111,13 @@ static ssize_t set_temp_auto_point1_temp(struct device *dev,
return count;
}
-#define temp_auto_point(offset) \
-static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp, S_IRUGO | S_IWUSR, \
- show_temp_auto_point1_temp, set_temp_auto_point1_temp, \
- offset - 1); \
-static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp_hyst, S_IRUGO, \
- show_temp_auto_point1_temp_hyst, NULL, offset - 1); \
-static SENSOR_DEVICE_ATTR(temp##offset##_auto_point2_temp, S_IRUGO, \
+#define temp_auto_point(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp, \
+ S_IRUGO | S_IWUSR, show_temp_auto_point1_temp, \
+ set_temp_auto_point1_temp, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp_hyst, S_IRUGO,\
+ show_temp_auto_point1_temp_hyst, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_point2_temp, S_IRUGO, \
show_temp_auto_point2_temp, NULL, offset - 1);
temp_auto_point(1);
@@ -1130,7 +1128,7 @@ static ssize_t show_temp_crit_enable(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", (data->config1 & CFG1_THERM_HOT) >> 4);
+ return sprintf(buf, "%d\n", (data->config1 & CFG1_THERM_HOT) >> 4);
}
static ssize_t set_temp_crit_enable(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
@@ -1142,7 +1140,7 @@ static ssize_t set_temp_crit_enable(struct device *dev,
if ((val == 1) || (val==0)) {
mutex_lock(&data->update_lock);
data->config1 = (data->config1 & ~CFG1_THERM_HOT) | (val << 4);
- adm1026_write_value(client, ADM1026_REG_CONFIG1,
+ adm1026_write_value(client, ADM1026_REG_CONFIG1,
data->config1);
mutex_unlock(&data->update_lock);
}
@@ -1163,7 +1161,7 @@ static ssize_t show_temp_crit(struct device *dev,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_crit[nr]));
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr]));
}
static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -1193,7 +1191,7 @@ temp_crit_reg(3);
static ssize_t show_analog_out_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", DAC_FROM_REG(data->analog_out));
+ return sprintf(buf, "%d\n", DAC_FROM_REG(data->analog_out));
}
static ssize_t set_analog_out_reg(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
@@ -1209,26 +1207,25 @@ static ssize_t set_analog_out_reg(struct device *dev, struct device_attribute *a
return count;
}
-static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg,
+static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg,
set_analog_out_reg);
static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm));
+ return sprintf(buf, "%d\n", vid_from_reg(data->vid & 0x3f, data->vrm));
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1026_data *data = dev_get_drvdata(dev);
- return sprintf(buf,"%d\n", data->vrm);
+ return sprintf(buf, "%d\n", data->vrm);
}
static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct adm1026_data *data = i2c_get_clientdata(client);
+ struct adm1026_data *data = dev_get_drvdata(dev);
data->vrm = simple_strtol(buf, NULL, 10);
return count;
@@ -1239,15 +1236,52 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf, "%ld\n", (long) (data->alarms));
+ return sprintf(buf, "%ld\n", data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct adm1026_data *data = adm1026_update_device(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ return sprintf(buf, "%ld\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in11_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in14_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in15_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(in16_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 18);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 19);
+static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 20);
+static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 21);
+static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_alarm, NULL, 22);
+static SENSOR_DEVICE_ATTR(fan8_alarm, S_IRUGO, show_alarm, NULL, 23);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 24);
+static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 25);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 26);
+
static ssize_t show_alarm_mask(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%ld\n", data->alarm_mask);
+ return sprintf(buf, "%ld\n", data->alarm_mask);
}
static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
@@ -1283,7 +1317,7 @@ static DEVICE_ATTR(alarm_mask, S_IRUGO | S_IWUSR, show_alarm_mask,
static ssize_t show_gpio(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%ld\n", data->gpio);
+ return sprintf(buf, "%ld\n", data->gpio);
}
static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
@@ -1291,16 +1325,16 @@ static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, const
struct i2c_client *client = to_i2c_client(dev);
struct adm1026_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
- long gpio;
+ long gpio;
mutex_lock(&data->update_lock);
data->gpio = val & 0x1ffff;
gpio = data->gpio;
- adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_0_7,gpio & 0xff);
+ adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_0_7, gpio & 0xff);
gpio >>= 8;
- adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_8_15,gpio & 0xff);
+ adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_8_15, gpio & 0xff);
gpio = ((gpio >> 1) & 0x80) | (data->alarms >> 24 & 0x7f);
- adm1026_write_value(client, ADM1026_REG_STATUS4,gpio & 0xff);
+ adm1026_write_value(client, ADM1026_REG_STATUS4, gpio & 0xff);
mutex_unlock(&data->update_lock);
return count;
}
@@ -1311,7 +1345,7 @@ static DEVICE_ATTR(gpio, S_IRUGO | S_IWUSR, show_gpio, set_gpio);
static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%ld\n", data->gpio_mask);
+ return sprintf(buf, "%ld\n", data->gpio_mask);
}
static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
@@ -1319,16 +1353,16 @@ static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr,
struct i2c_client *client = to_i2c_client(dev);
struct adm1026_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
- long mask;
+ long mask;
mutex_lock(&data->update_lock);
data->gpio_mask = val & 0x1ffff;
mask = data->gpio_mask;
- adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7,mask & 0xff);
+ adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7, mask & 0xff);
mask >>= 8;
- adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15,mask & 0xff);
+ adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15, mask & 0xff);
mask = ((mask >> 1) & 0x80) | (data->alarm_mask >> 24 & 0x7f);
- adm1026_write_value(client, ADM1026_REG_MASK1,mask & 0xff);
+ adm1026_write_value(client, ADM1026_REG_MASK1, mask & 0xff);
mutex_unlock(&data->update_lock);
return count;
}
@@ -1338,7 +1372,7 @@ static DEVICE_ATTR(gpio_mask, S_IRUGO | S_IWUSR, show_gpio_mask, set_gpio_mask);
static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm1.pwm));
+ return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm1.pwm));
}
static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
@@ -1359,7 +1393,7 @@ static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, co
static ssize_t show_auto_pwm_min(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", data->pwm1.auto_pwm_min);
+ return sprintf(buf, "%d\n", data->pwm1.auto_pwm_min);
}
static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
@@ -1369,10 +1403,10 @@ static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *att
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
- data->pwm1.auto_pwm_min = SENSORS_LIMIT(val,0,255);
+ data->pwm1.auto_pwm_min = SENSORS_LIMIT(val, 0, 255);
if (data->pwm1.enable == 2) { /* apply immediately */
data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) |
- PWM_MIN_TO_REG(data->pwm1.auto_pwm_min));
+ PWM_MIN_TO_REG(data->pwm1.auto_pwm_min));
adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm);
}
mutex_unlock(&data->update_lock);
@@ -1380,12 +1414,12 @@ static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *att
}
static ssize_t show_auto_pwm_max(struct device *dev, struct device_attribute *attr, char *buf)
{
- return sprintf(buf,"%d\n", ADM1026_PWM_MAX);
+ return sprintf(buf, "%d\n", ADM1026_PWM_MAX);
}
static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1026_data *data = adm1026_update_device(dev);
- return sprintf(buf,"%d\n", data->pwm1.enable);
+ return sprintf(buf, "%d\n", data->pwm1.enable);
}
static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
@@ -1393,7 +1427,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
struct i2c_client *client = to_i2c_client(dev);
struct adm1026_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
- int old_enable;
+ int old_enable;
if ((val >= 0) && (val < 3)) {
mutex_lock(&data->update_lock);
@@ -1403,15 +1437,15 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
| ((val == 2) ? CFG1_PWM_AFC : 0);
adm1026_write_value(client, ADM1026_REG_CONFIG1,
data->config1);
- if (val == 2) { /* apply pwm1_auto_pwm_min to pwm1 */
+ if (val == 2) { /* apply pwm1_auto_pwm_min to pwm1 */
data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) |
- PWM_MIN_TO_REG(data->pwm1.auto_pwm_min));
- adm1026_write_value(client, ADM1026_REG_PWM,
+ PWM_MIN_TO_REG(data->pwm1.auto_pwm_min));
+ adm1026_write_value(client, ADM1026_REG_PWM,
data->pwm1.pwm);
} else if (!((old_enable == 1) && (val == 1))) {
/* set pwm to safe value */
data->pwm1.pwm = 255;
- adm1026_write_value(client, ADM1026_REG_PWM,
+ adm1026_write_value(client, ADM1026_REG_PWM,
data->pwm1.pwm);
}
mutex_unlock(&data->update_lock);
@@ -1420,20 +1454,20 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
}
/* enable PWM fan control */
-static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg);
-static DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg);
-static DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg);
-static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable,
+static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg);
+static DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg);
+static DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg);
+static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable,
set_pwm_enable);
-static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable,
+static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable,
set_pwm_enable);
-static DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable,
+static DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable,
set_pwm_enable);
-static DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO | S_IWUSR,
show_auto_pwm_min, set_auto_pwm_min);
-static DEVICE_ATTR(temp2_auto_point1_pwm, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(temp2_auto_point1_pwm, S_IRUGO | S_IWUSR,
show_auto_pwm_min, set_auto_pwm_min);
-static DEVICE_ATTR(temp3_auto_point1_pwm, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(temp3_auto_point1_pwm, S_IRUGO | S_IWUSR,
show_auto_pwm_min, set_auto_pwm_min);
static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
@@ -1444,105 +1478,115 @@ static struct attribute *adm1026_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_max.dev_attr.attr,
&sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in2_max.dev_attr.attr,
&sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in3_max.dev_attr.attr,
&sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in4_max.dev_attr.attr,
&sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
&sensor_dev_attr_in5_input.dev_attr.attr,
&sensor_dev_attr_in5_max.dev_attr.attr,
&sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
&sensor_dev_attr_in6_input.dev_attr.attr,
&sensor_dev_attr_in6_max.dev_attr.attr,
&sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
&sensor_dev_attr_in7_input.dev_attr.attr,
&sensor_dev_attr_in7_max.dev_attr.attr,
&sensor_dev_attr_in7_min.dev_attr.attr,
- &sensor_dev_attr_in8_input.dev_attr.attr,
- &sensor_dev_attr_in8_max.dev_attr.attr,
- &sensor_dev_attr_in8_min.dev_attr.attr,
- &sensor_dev_attr_in9_input.dev_attr.attr,
- &sensor_dev_attr_in9_max.dev_attr.attr,
- &sensor_dev_attr_in9_min.dev_attr.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
&sensor_dev_attr_in10_input.dev_attr.attr,
&sensor_dev_attr_in10_max.dev_attr.attr,
&sensor_dev_attr_in10_min.dev_attr.attr,
+ &sensor_dev_attr_in10_alarm.dev_attr.attr,
&sensor_dev_attr_in11_input.dev_attr.attr,
&sensor_dev_attr_in11_max.dev_attr.attr,
&sensor_dev_attr_in11_min.dev_attr.attr,
+ &sensor_dev_attr_in11_alarm.dev_attr.attr,
&sensor_dev_attr_in12_input.dev_attr.attr,
&sensor_dev_attr_in12_max.dev_attr.attr,
&sensor_dev_attr_in12_min.dev_attr.attr,
+ &sensor_dev_attr_in12_alarm.dev_attr.attr,
&sensor_dev_attr_in13_input.dev_attr.attr,
&sensor_dev_attr_in13_max.dev_attr.attr,
&sensor_dev_attr_in13_min.dev_attr.attr,
+ &sensor_dev_attr_in13_alarm.dev_attr.attr,
&sensor_dev_attr_in14_input.dev_attr.attr,
&sensor_dev_attr_in14_max.dev_attr.attr,
&sensor_dev_attr_in14_min.dev_attr.attr,
+ &sensor_dev_attr_in14_alarm.dev_attr.attr,
&sensor_dev_attr_in15_input.dev_attr.attr,
&sensor_dev_attr_in15_max.dev_attr.attr,
&sensor_dev_attr_in15_min.dev_attr.attr,
+ &sensor_dev_attr_in15_alarm.dev_attr.attr,
&sensor_dev_attr_in16_input.dev_attr.attr,
&sensor_dev_attr_in16_max.dev_attr.attr,
&sensor_dev_attr_in16_min.dev_attr.attr,
+ &sensor_dev_attr_in16_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan3_div.dev_attr.attr,
&sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
&sensor_dev_attr_fan4_input.dev_attr.attr,
&sensor_dev_attr_fan4_div.dev_attr.attr,
&sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_alarm.dev_attr.attr,
&sensor_dev_attr_fan5_input.dev_attr.attr,
&sensor_dev_attr_fan5_div.dev_attr.attr,
&sensor_dev_attr_fan5_min.dev_attr.attr,
+ &sensor_dev_attr_fan5_alarm.dev_attr.attr,
&sensor_dev_attr_fan6_input.dev_attr.attr,
&sensor_dev_attr_fan6_div.dev_attr.attr,
&sensor_dev_attr_fan6_min.dev_attr.attr,
+ &sensor_dev_attr_fan6_alarm.dev_attr.attr,
&sensor_dev_attr_fan7_input.dev_attr.attr,
&sensor_dev_attr_fan7_div.dev_attr.attr,
&sensor_dev_attr_fan7_min.dev_attr.attr,
+ &sensor_dev_attr_fan7_alarm.dev_attr.attr,
&sensor_dev_attr_fan8_input.dev_attr.attr,
&sensor_dev_attr_fan8_div.dev_attr.attr,
&sensor_dev_attr_fan8_min.dev_attr.attr,
+ &sensor_dev_attr_fan8_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_min.dev_attr.attr,
- &sensor_dev_attr_temp3_input.dev_attr.attr,
- &sensor_dev_attr_temp3_max.dev_attr.attr,
- &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_offset.dev_attr.attr,
&sensor_dev_attr_temp2_offset.dev_attr.attr,
- &sensor_dev_attr_temp3_offset.dev_attr.attr,
&sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
&sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
- &sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr,
&sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr,
&sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr.attr,
- &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
- &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp2_crit.dev_attr.attr,
- &sensor_dev_attr_temp3_crit.dev_attr.attr,
&dev_attr_temp1_crit_enable.attr,
&dev_attr_temp2_crit_enable.attr,
- &dev_attr_temp3_crit_enable.attr,
&dev_attr_cpu0_vid.attr,
&dev_attr_vrm.attr,
&dev_attr_alarms.attr,
@@ -1557,10 +1601,8 @@ static struct attribute *adm1026_attributes[] = {
&dev_attr_pwm3_enable.attr,
&dev_attr_temp1_auto_point1_pwm.attr,
&dev_attr_temp2_auto_point1_pwm.attr,
- &dev_attr_temp3_auto_point1_pwm.attr,
&dev_attr_temp1_auto_point2_pwm.attr,
&dev_attr_temp2_auto_point2_pwm.attr,
- &dev_attr_temp3_auto_point2_pwm.attr,
&dev_attr_analog_out.attr,
NULL
};
@@ -1569,11 +1611,45 @@ static const struct attribute_group adm1026_group = {
.attrs = adm1026_attributes,
};
+static struct attribute *adm1026_attributes_temp3[] = {
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_offset.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit.dev_attr.attr,
+ &dev_attr_temp3_crit_enable.attr,
+ &dev_attr_temp3_auto_point1_pwm.attr,
+ &dev_attr_temp3_auto_point2_pwm.attr,
+};
+
+static const struct attribute_group adm1026_group_temp3 = {
+ .attrs = adm1026_attributes_temp3,
+};
+
+static struct attribute *adm1026_attributes_in8_9[] = {
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in8_max.dev_attr.attr,
+ &sensor_dev_attr_in8_min.dev_attr.attr,
+ &sensor_dev_attr_in8_alarm.dev_attr.attr,
+ &sensor_dev_attr_in9_input.dev_attr.attr,
+ &sensor_dev_attr_in9_max.dev_attr.attr,
+ &sensor_dev_attr_in9_min.dev_attr.attr,
+ &sensor_dev_attr_in9_alarm.dev_attr.attr,
+};
+
+static const struct attribute_group adm1026_group_in8_9 = {
+ .attrs = adm1026_attributes_in8_9,
+};
+
static int adm1026_detect(struct i2c_adapter *adapter, int address,
int kind)
{
int company, verstep;
- struct i2c_client *new_client;
+ struct i2c_client *client;
struct adm1026_data *data;
int err = 0;
const char *type_name = "";
@@ -1592,26 +1668,25 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
goto exit;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &adm1026_driver;
- new_client->flags = 0;
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &adm1026_driver;
/* Now, we do the remaining detection. */
- company = adm1026_read_value(new_client, ADM1026_REG_COMPANY);
- verstep = adm1026_read_value(new_client, ADM1026_REG_VERSTEP);
+ company = adm1026_read_value(client, ADM1026_REG_COMPANY);
+ verstep = adm1026_read_value(client, ADM1026_REG_VERSTEP);
- dev_dbg(&new_client->dev, "Detecting device at %d,0x%02x with"
+ dev_dbg(&client->dev, "Detecting device at %d,0x%02x with"
" COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
- i2c_adapter_id(new_client->adapter), new_client->addr,
+ i2c_adapter_id(client->adapter), client->addr,
company, verstep);
/* If auto-detecting, Determine the chip type. */
if (kind <= 0) {
- dev_dbg(&new_client->dev, "Autodetecting device at %d,0x%02x "
+ dev_dbg(&client->dev, "Autodetecting device at %d,0x%02x "
"...\n", i2c_adapter_id(adapter), address);
if (company == ADM1026_COMPANY_ANALOG_DEV
&& verstep == ADM1026_VERSTEP_ADM1026) {
@@ -1627,16 +1702,15 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
verstep);
kind = any_chip;
} else {
- dev_dbg(&new_client->dev, ": Autodetection "
+ dev_dbg(&client->dev, ": Autodetection "
"failed\n");
/* Not an ADM1026 ... */
- if (kind == 0) { /* User used force=x,y */
+ if (kind == 0) { /* User used force=x,y */
dev_err(&adapter->dev, "Generic ADM1026 not "
"found at %d,0x%02x. Try "
"force_adm1026.\n",
i2c_adapter_id(adapter), address);
}
- err = 0;
goto exitfree;
}
}
@@ -1655,28 +1729,34 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
err = -EFAULT;
goto exitfree;
}
- strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
+ strlcpy(client->name, type_name, I2C_NAME_SIZE);
/* Fill in the remaining client fields */
- data->type = kind;
- data->valid = 0;
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
+ if ((err = i2c_attach_client(client)))
goto exitfree;
/* Set the VRM version */
data->vrm = vid_which_vrm();
/* Initialize the ADM1026 chip */
- adm1026_init_client(new_client);
+ adm1026_init_client(client);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1026_group)))
+ if ((err = sysfs_create_group(&client->dev.kobj, &adm1026_group)))
goto exitdetach;
+ if (data->config1 & CFG1_AIN8_9)
+ err = sysfs_create_group(&client->dev.kobj,
+ &adm1026_group_in8_9);
+ else
+ err = sysfs_create_group(&client->dev.kobj,
+ &adm1026_group_temp3);
+ if (err)
+ goto exitremove;
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exitremove;
@@ -1686,9 +1766,13 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
/* Error out and cleanup code */
exitremove:
- sysfs_remove_group(&new_client->dev.kobj, &adm1026_group);
+ sysfs_remove_group(&client->dev.kobj, &adm1026_group);
+ if (data->config1 & CFG1_AIN8_9)
+ sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9);
+ else
+ sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3);
exitdetach:
- i2c_detach_client(new_client);
+ i2c_detach_client(client);
exitfree:
kfree(data);
exit:
@@ -1700,6 +1784,10 @@ static int adm1026_detach_client(struct i2c_client *client)
struct adm1026_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1026_group);
+ if (data->config1 & CFG1_AIN8_9)
+ sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9);
+ else
+ sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3);
i2c_detach_client(client);
kfree(data);
return 0;
@@ -1710,14 +1798,14 @@ static int __init sm_adm1026_init(void)
return i2c_add_driver(&adm1026_driver);
}
-static void __exit sm_adm1026_exit(void)
+static void __exit sm_adm1026_exit(void)
{
i2c_del_driver(&adm1026_driver);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com>, "
- "Justin Thiessen <jthiessen@penguincomputing.com>");
+ "Justin Thiessen <jthiessen@penguincomputing.com>");
MODULE_DESCRIPTION("ADM1026 driver");
module_init(sm_adm1026_init);
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index 37cfc101da5..5aaad3636c9 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -5,7 +5,7 @@
Supports adm1030 / adm1031
Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org>
Reworked by Jean Delvare <khali@linux-fr.org>
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -27,27 +27,28 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
/* Following macros takes channel parameter starting from 0 to 2 */
#define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr))
-#define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr))
+#define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr))
#define ADM1031_REG_PWM (0x22)
#define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr))
-#define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4*(nr))
-#define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4*(nr))
-#define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4*(nr))
+#define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4 * (nr))
+#define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4 * (nr))
+#define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4 * (nr))
-#define ADM1031_REG_TEMP(nr) (0xa + (nr))
+#define ADM1031_REG_TEMP(nr) (0x0a + (nr))
#define ADM1031_REG_AUTO_TEMP(nr) (0x24 + (nr))
#define ADM1031_REG_STATUS(nr) (0x2 + (nr))
-#define ADM1031_REG_CONF1 0x0
-#define ADM1031_REG_CONF2 0x1
-#define ADM1031_REG_EXT_TEMP 0x6
+#define ADM1031_REG_CONF1 0x00
+#define ADM1031_REG_CONF2 0x01
+#define ADM1031_REG_EXT_TEMP 0x06
#define ADM1031_CONF1_MONITOR_ENABLE 0x01 /* Monitoring enable */
#define ADM1031_CONF1_PWM_INVERT 0x08 /* PWM Invert */
@@ -78,7 +79,7 @@ struct adm1031_data {
/* The chan_select_table contains the possible configurations for
* auto fan control.
*/
- auto_chan_table_t *chan_select_table;
+ const auto_chan_table_t *chan_select_table;
u16 alarm;
u8 conf1;
u8 conf2;
@@ -181,25 +182,25 @@ static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm)
#define GET_FAN_AUTO_BITFIELD(data, idx) \
(*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx%2]
-/* The tables below contains the possible values for the auto fan
+/* The tables below contains the possible values for the auto fan
* control bitfields. the index in the table is the register value.
* MSb is the auto fan control enable bit, so the four first entries
* in the table disables auto fan control when both bitfields are zero.
*/
-static auto_chan_table_t auto_channel_select_table_adm1031 = {
- {0, 0}, {0, 0}, {0, 0}, {0, 0},
- {2 /*0b010 */ , 4 /*0b100 */ },
- {2 /*0b010 */ , 2 /*0b010 */ },
- {4 /*0b100 */ , 4 /*0b100 */ },
- {7 /*0b111 */ , 7 /*0b111 */ },
+static const auto_chan_table_t auto_channel_select_table_adm1031 = {
+ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
+ { 2 /* 0b010 */ , 4 /* 0b100 */ },
+ { 2 /* 0b010 */ , 2 /* 0b010 */ },
+ { 4 /* 0b100 */ , 4 /* 0b100 */ },
+ { 7 /* 0b111 */ , 7 /* 0b111 */ },
};
-static auto_chan_table_t auto_channel_select_table_adm1030 = {
- {0, 0}, {0, 0}, {0, 0}, {0, 0},
- {2 /*0b10 */ , 0},
- {0xff /*invalid */ , 0},
- {0xff /*invalid */ , 0},
- {3 /*0b11 */ , 0},
+static const auto_chan_table_t auto_channel_select_table_adm1030 = {
+ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
+ { 2 /* 0b10 */ , 0 },
+ { 0xff /* invalid */ , 0 },
+ { 0xff /* invalid */ , 0 },
+ { 3 /* 0b11 */ , 0 },
};
/* That function checks if a bitfield is valid and returns the other bitfield
@@ -228,8 +229,8 @@ get_fan_auto_nearest(struct adm1031_data *data,
break;
} else if (val == (*data->chan_select_table)[i][chan] &&
first_match == -1) {
- /* Save the first match in case of an exact match has not been
- * found
+ /* Save the first match in case of an exact match has
+ * not been found
*/
first_match = i;
}
@@ -245,17 +246,21 @@ get_fan_auto_nearest(struct adm1031_data *data,
return 0;
}
-static ssize_t show_fan_auto_channel(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_auto_channel(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct adm1031_data *data = adm1031_update_device(dev);
return sprintf(buf, "%d\n", GET_FAN_AUTO_BITFIELD(data, nr));
}
static ssize_t
-set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr)
+set_fan_auto_channel(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client);
+ int nr = to_sensor_dev_attr(attr)->index;
int val = simple_strtol(buf, NULL, 10);
u8 reg;
int ret;
@@ -264,16 +269,17 @@ set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr)
old_fan_mode = data->conf1;
mutex_lock(&data->update_lock);
-
+
if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, &reg))) {
mutex_unlock(&data->update_lock);
return ret;
}
- if (((data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1)) & ADM1031_CONF1_AUTO_MODE) ^
+ data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
+ if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^
(old_fan_mode & ADM1031_CONF1_AUTO_MODE)) {
if (data->conf1 & ADM1031_CONF1_AUTO_MODE){
- /* Switch to Auto Fan Mode
- * Save PWM registers
+ /* Switch to Auto Fan Mode
+ * Save PWM registers
* Set PWM registers to 33% Both */
data->old_pwm[0] = data->pwm[0];
data->old_pwm[1] = data->pwm[1];
@@ -283,7 +289,7 @@ set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr)
data->pwm[0] = data->old_pwm[0];
data->pwm[1] = data->old_pwm[1];
/* Restore PWM registers */
- adm1031_write_value(client, ADM1031_REG_PWM,
+ adm1031_write_value(client, ADM1031_REG_PWM,
data->pwm[0] | (data->pwm[1] << 4));
}
}
@@ -293,41 +299,35 @@ set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr)
return count;
}
-#define fan_auto_channel_offset(offset) \
-static ssize_t show_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_auto_channel(dev, buf, offset - 1); \
-} \
-static ssize_t set_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_auto_channel(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(auto_fan##offset##_channel, S_IRUGO | S_IWUSR, \
- show_fan_auto_channel_##offset, \
- set_fan_auto_channel_##offset)
-
-fan_auto_channel_offset(1);
-fan_auto_channel_offset(2);
+static SENSOR_DEVICE_ATTR(auto_fan1_channel, S_IRUGO | S_IWUSR,
+ show_fan_auto_channel, set_fan_auto_channel, 0);
+static SENSOR_DEVICE_ATTR(auto_fan2_channel, S_IRUGO | S_IWUSR,
+ show_fan_auto_channel, set_fan_auto_channel, 1);
/* Auto Temps */
-static ssize_t show_auto_temp_off(struct device *dev, char *buf, int nr)
+static ssize_t show_auto_temp_off(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct adm1031_data *data = adm1031_update_device(dev);
- return sprintf(buf, "%d\n",
+ return sprintf(buf, "%d\n",
AUTO_TEMP_OFF_FROM_REG(data->auto_temp[nr]));
}
-static ssize_t show_auto_temp_min(struct device *dev, char *buf, int nr)
+static ssize_t show_auto_temp_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct adm1031_data *data = adm1031_update_device(dev);
return sprintf(buf, "%d\n",
AUTO_TEMP_MIN_FROM_REG(data->auto_temp[nr]));
}
static ssize_t
-set_auto_temp_min(struct device *dev, const char *buf, size_t count, int nr)
+set_auto_temp_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client);
+ int nr = to_sensor_dev_attr(attr)->index;
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -337,17 +337,21 @@ set_auto_temp_min(struct device *dev, const char *buf, size_t count, int nr)
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_auto_temp_max(struct device *dev, char *buf, int nr)
+static ssize_t show_auto_temp_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct adm1031_data *data = adm1031_update_device(dev);
return sprintf(buf, "%d\n",
AUTO_TEMP_MAX_FROM_REG(data->auto_temp[nr]));
}
static ssize_t
-set_auto_temp_max(struct device *dev, const char *buf, size_t count, int nr)
+set_auto_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client);
+ int nr = to_sensor_dev_attr(attr)->index;
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -358,56 +362,37 @@ set_auto_temp_max(struct device *dev, const char *buf, size_t count, int nr)
return count;
}
-#define auto_temp_reg(offset) \
-static ssize_t show_auto_temp_##offset##_off (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_auto_temp_off(dev, buf, offset - 1); \
-} \
-static ssize_t show_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_auto_temp_min(dev, buf, offset - 1); \
-} \
-static ssize_t show_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_auto_temp_max(dev, buf, offset - 1); \
-} \
-static ssize_t set_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_auto_temp_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_auto_temp_max(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(auto_temp##offset##_off, S_IRUGO, \
- show_auto_temp_##offset##_off, NULL); \
-static DEVICE_ATTR(auto_temp##offset##_min, S_IRUGO | S_IWUSR, \
- show_auto_temp_##offset##_min, set_auto_temp_##offset##_min);\
-static DEVICE_ATTR(auto_temp##offset##_max, S_IRUGO | S_IWUSR, \
- show_auto_temp_##offset##_max, set_auto_temp_##offset##_max)
+#define auto_temp_reg(offset) \
+static SENSOR_DEVICE_ATTR(auto_temp##offset##_off, S_IRUGO, \
+ show_auto_temp_off, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(auto_temp##offset##_min, S_IRUGO | S_IWUSR, \
+ show_auto_temp_min, set_auto_temp_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(auto_temp##offset##_max, S_IRUGO | S_IWUSR, \
+ show_auto_temp_max, set_auto_temp_max, offset - 1)
auto_temp_reg(1);
auto_temp_reg(2);
auto_temp_reg(3);
/* pwm */
-static ssize_t show_pwm(struct device *dev, char *buf, int nr)
+static ssize_t show_pwm(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct adm1031_data *data = adm1031_update_device(dev);
return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr]));
}
-static ssize_t
-set_pwm(struct device *dev, const char *buf, size_t count, int nr)
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client);
+ int nr = to_sensor_dev_attr(attr)->index;
int val = simple_strtol(buf, NULL, 10);
int reg;
mutex_lock(&data->update_lock);
- if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) &&
+ if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) &&
(((val>>4) & 0xf) != 5)) {
/* In automatic mode, the only PWM accepted is 33% */
mutex_unlock(&data->update_lock);
@@ -422,21 +407,12 @@ set_pwm(struct device *dev, const char *buf, size_t count, int nr)
return count;
}
-#define pwm_reg(offset) \
-static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_pwm(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
- show_pwm_##offset, set_pwm_##offset)
-
-pwm_reg(1);
-pwm_reg(2);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(auto_fan1_min_pwm, S_IRUGO | S_IWUSR,
+ show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(auto_fan2_min_pwm, S_IRUGO | S_IWUSR,
+ show_pwm, set_pwm, 1);
/* Fans */
@@ -471,7 +447,7 @@ static int trust_fan_readings(struct adm1031_data *data, int chan)
AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[0])
|| data->temp[1] >=
AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1])
- || (data->chip_type == adm1031
+ || (data->chip_type == adm1031
&& data->temp[2] >=
AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]));
break;
@@ -483,8 +459,10 @@ static int trust_fan_readings(struct adm1031_data *data, int chan)
}
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct adm1031_data *data = adm1031_update_device(dev);
int value;
@@ -493,28 +471,33 @@ static ssize_t show_fan(struct device *dev, char *buf, int nr)
return sprintf(buf, "%d\n", value);
}
-static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_div(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct adm1031_data *data = adm1031_update_device(dev);
return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[nr]));
}
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct adm1031_data *data = adm1031_update_device(dev);
return sprintf(buf, "%d\n",
FAN_FROM_REG(data->fan_min[nr],
FAN_DIV_FROM_REG(data->fan_div[nr])));
}
-static ssize_t
-set_fan_min(struct device *dev, const char *buf, size_t count, int nr)
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client);
+ int nr = to_sensor_dev_attr(attr)->index;
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
if (val) {
- data->fan_min[nr] =
+ data->fan_min[nr] =
FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr]));
} else {
data->fan_min[nr] = 0xff;
@@ -523,11 +506,12 @@ set_fan_min(struct device *dev, const char *buf, size_t count, int nr)
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t
-set_fan_div(struct device *dev, const char *buf, size_t count, int nr)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client);
+ int nr = to_sensor_dev_attr(attr)->index;
int val = simple_strtol(buf, NULL, 10);
u8 tmp;
int old_div;
@@ -535,68 +519,53 @@ set_fan_div(struct device *dev, const char *buf, size_t count, int nr)
tmp = val == 8 ? 0xc0 :
val == 4 ? 0x80 :
- val == 2 ? 0x40 :
- val == 1 ? 0x00 :
+ val == 2 ? 0x40 :
+ val == 1 ? 0x00 :
0xff;
if (tmp == 0xff)
return -EINVAL;
-
+
mutex_lock(&data->update_lock);
+ /* Get fresh readings */
+ data->fan_div[nr] = adm1031_read_value(client,
+ ADM1031_REG_FAN_DIV(nr));
+ data->fan_min[nr] = adm1031_read_value(client,
+ ADM1031_REG_FAN_MIN(nr));
+
+ /* Write the new clock divider and fan min */
old_div = FAN_DIV_FROM_REG(data->fan_div[nr]);
- data->fan_div[nr] = (tmp & 0xC0) | (0x3f & data->fan_div[nr]);
- new_min = data->fan_min[nr] * old_div /
- FAN_DIV_FROM_REG(data->fan_div[nr]);
+ data->fan_div[nr] = tmp | (0x3f & data->fan_div[nr]);
+ new_min = data->fan_min[nr] * old_div / val;
data->fan_min[nr] = new_min > 0xff ? 0xff : new_min;
- data->fan[nr] = data->fan[nr] * old_div /
- FAN_DIV_FROM_REG(data->fan_div[nr]);
- adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr),
+ adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr),
data->fan_div[nr]);
- adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr),
+ adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr),
data->fan_min[nr]);
+
+ /* Invalidate the cache: fan speed is no longer valid */
+ data->valid = 0;
mutex_unlock(&data->update_lock);
return count;
}
#define fan_offset(offset) \
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_min(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_div(dev, buf, offset - 1); \
-} \
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_div(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \
- NULL); \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
- show_fan_##offset##_min, set_fan_##offset##_min); \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
- show_fan_##offset##_div, set_fan_##offset##_div); \
-static DEVICE_ATTR(auto_fan##offset##_min_pwm, S_IRUGO | S_IWUSR, \
- show_pwm_##offset, set_pwm_##offset)
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, set_fan_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+ show_fan_div, set_fan_div, offset - 1)
fan_offset(1);
fan_offset(2);
/* Temps */
-static ssize_t show_temp(struct device *dev, char *buf, int nr)
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct adm1031_data *data = adm1031_update_device(dev);
int ext;
ext = nr == 0 ?
@@ -604,26 +573,33 @@ static ssize_t show_temp(struct device *dev, char *buf, int nr)
(((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7));
return sprintf(buf, "%d\n", TEMP_FROM_REG_EXT(data->temp[nr], ext));
}
-static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
+static ssize_t show_temp_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct adm1031_data *data = adm1031_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));
}
-static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct adm1031_data *data = adm1031_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));
}
-static ssize_t show_temp_crit(struct device *dev, char *buf, int nr)
+static ssize_t show_temp_crit(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct adm1031_data *data = adm1031_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr]));
}
-static ssize_t
-set_temp_min(struct device *dev, const char *buf, size_t count, int nr)
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client);
+ int nr = to_sensor_dev_attr(attr)->index;
int val;
val = simple_strtol(buf, NULL, 10);
@@ -635,11 +611,12 @@ set_temp_min(struct device *dev, const char *buf, size_t count, int nr)
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t
-set_temp_max(struct device *dev, const char *buf, size_t count, int nr)
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client);
+ int nr = to_sensor_dev_attr(attr)->index;
int val;
val = simple_strtol(buf, NULL, 10);
@@ -651,11 +628,12 @@ set_temp_max(struct device *dev, const char *buf, size_t count, int nr)
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t
-set_temp_crit(struct device *dev, const char *buf, size_t count, int nr)
+static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct adm1031_data *data = i2c_get_clientdata(client);
+ int nr = to_sensor_dev_attr(attr)->index;
int val;
val = simple_strtol(buf, NULL, 10);
@@ -668,46 +646,15 @@ set_temp_crit(struct device *dev, const char *buf, size_t count, int nr)
return count;
}
-#define temp_reg(offset) \
-static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp(dev, buf, offset - 1); \
-} \
-static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_min(dev, buf, offset - 1); \
-} \
-static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_max(dev, buf, offset - 1); \
-} \
-static ssize_t show_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_crit(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_max(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_crit(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \
- NULL); \
-static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_min, set_temp_##offset##_min); \
-static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_max, set_temp_##offset##_max); \
-static DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_crit, set_temp_##offset##_crit)
+#define temp_reg(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_temp, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
+ show_temp_min, set_temp_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
+ show_temp_max, set_temp_max, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \
+ show_temp_crit, set_temp_crit, offset - 1)
temp_reg(1);
temp_reg(2);
@@ -722,6 +669,29 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_alarm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct adm1031_data *data = adm1031_update_device(dev);
+ return sprintf(buf, "%d\n", (data->alarm >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
static int adm1031_attach_adapter(struct i2c_adapter *adapter)
{
@@ -731,29 +701,38 @@ static int adm1031_attach_adapter(struct i2c_adapter *adapter)
}
static struct attribute *adm1031_attributes[] = {
- &dev_attr_fan1_input.attr,
- &dev_attr_fan1_div.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_pwm1.attr,
- &dev_attr_auto_fan1_channel.attr,
- &dev_attr_temp1_input.attr,
- &dev_attr_temp1_min.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp1_crit.attr,
- &dev_attr_temp2_input.attr,
- &dev_attr_temp2_min.attr,
- &dev_attr_temp2_max.attr,
- &dev_attr_temp2_crit.attr,
-
- &dev_attr_auto_temp1_off.attr,
- &dev_attr_auto_temp1_min.attr,
- &dev_attr_auto_temp1_max.attr,
-
- &dev_attr_auto_temp2_off.attr,
- &dev_attr_auto_temp2_min.attr,
- &dev_attr_auto_temp2_max.attr,
-
- &dev_attr_auto_fan1_min_pwm.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan1_fault.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_auto_fan1_channel.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
+
+ &sensor_dev_attr_auto_temp1_off.dev_attr.attr,
+ &sensor_dev_attr_auto_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_auto_temp1_max.dev_attr.attr,
+
+ &sensor_dev_attr_auto_temp2_off.dev_attr.attr,
+ &sensor_dev_attr_auto_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_auto_temp2_max.dev_attr.attr,
+
+ &sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr,
&dev_attr_alarms.attr,
@@ -765,19 +744,25 @@ static const struct attribute_group adm1031_group = {
};
static struct attribute *adm1031_attributes_opt[] = {
- &dev_attr_fan2_input.attr,
- &dev_attr_fan2_div.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_pwm2.attr,
- &dev_attr_auto_fan2_channel.attr,
- &dev_attr_temp3_input.attr,
- &dev_attr_temp3_min.attr,
- &dev_attr_temp3_max.attr,
- &dev_attr_temp3_crit.attr,
- &dev_attr_auto_temp3_off.attr,
- &dev_attr_auto_temp3_min.attr,
- &dev_attr_auto_temp3_max.attr,
- &dev_attr_auto_fan2_min_pwm.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_fault.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_auto_fan2_channel.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
+ &sensor_dev_attr_auto_temp3_off.dev_attr.attr,
+ &sensor_dev_attr_auto_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_auto_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_auto_fan2_min_pwm.dev_attr.attr,
NULL
};
@@ -788,7 +773,7 @@ static const struct attribute_group adm1031_group_opt = {
/* This function is called by i2c_probe */
static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
{
- struct i2c_client *new_client;
+ struct i2c_client *client;
struct adm1031_data *data;
int err = 0;
const char *name = "";
@@ -801,17 +786,16 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &adm1031_driver;
- new_client->flags = 0;
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &adm1031_driver;
if (kind < 0) {
int id, co;
- id = i2c_smbus_read_byte_data(new_client, 0x3d);
- co = i2c_smbus_read_byte_data(new_client, 0x3e);
+ id = i2c_smbus_read_byte_data(client, 0x3d);
+ co = i2c_smbus_read_byte_data(client, 0x3e);
if (!((id == 0x31 || id == 0x30) && co == 0x41))
goto exit_free;
@@ -832,28 +816,27 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
}
data->chip_type = kind;
- strlcpy(new_client->name, name, I2C_NAME_SIZE);
- data->valid = 0;
+ strlcpy(client->name, name, I2C_NAME_SIZE);
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
+ if ((err = i2c_attach_client(client)))
goto exit_free;
/* Initialize the ADM1031 chip */
- adm1031_init_client(new_client);
+ adm1031_init_client(client);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1031_group)))
+ if ((err = sysfs_create_group(&client->dev.kobj, &adm1031_group)))
goto exit_detach;
if (kind == adm1031) {
- if ((err = sysfs_create_group(&new_client->dev.kobj,
+ if ((err = sysfs_create_group(&client->dev.kobj,
&adm1031_group_opt)))
goto exit_remove;
}
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
@@ -862,10 +845,10 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
exit_remove:
- sysfs_remove_group(&new_client->dev.kobj, &adm1031_group);
- sysfs_remove_group(&new_client->dev.kobj, &adm1031_group_opt);
+ sysfs_remove_group(&client->dev.kobj, &adm1031_group);
+ sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
exit_detach:
- i2c_detach_client(new_client);
+ i2c_detach_client(client);
exit_free:
kfree(data);
exit:
@@ -897,7 +880,7 @@ static void adm1031_init_client(struct i2c_client *client)
if (data->chip_type == adm1031) {
mask |= (ADM1031_CONF2_PWM2_ENABLE |
ADM1031_CONF2_TACH2_ENABLE);
- }
+ }
/* Initialize the ADM1031 chip (enables fan speed reading ) */
read_val = adm1031_read_value(client, ADM1031_REG_CONF2);
if ((read_val | mask) != read_val) {
@@ -976,7 +959,7 @@ static struct adm1031_data *adm1031_update_device(struct device *dev)
if (data->chip_type == adm1030) {
data->alarm &= 0xc0ff;
}
-
+
for (chan=0; chan<(data->chip_type == adm1030 ? 1 : 2); chan++) {
data->fan_div[chan] =
adm1031_read_value(client, ADM1031_REG_FAN_DIV(chan));
@@ -985,7 +968,7 @@ static struct adm1031_data *adm1031_update_device(struct device *dev)
data->fan[chan] =
adm1031_read_value(client, ADM1031_REG_FAN_SPEED(chan));
data->pwm[chan] =
- 0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >>
+ 0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >>
(4*chan));
}
data->last_updated = jiffies;
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index c17d0b6b328..7671d2bf780 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -141,7 +141,6 @@ static struct i2c_driver adm9240_driver = {
.driver = {
.name = "adm9240",
},
- .id = I2C_DRIVERID_ADM9240,
.attach_adapter = adm9240_attach_adapter,
.detach_client = adm9240_detach_client,
};
@@ -415,6 +414,23 @@ static ssize_t show_alarms(struct device *dev,
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_alarm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct adm9240_data *data = adm9240_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+
/* vid */
static ssize_t show_vid(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -469,30 +485,39 @@ static struct attribute *adm9240_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_min.dev_attr.attr,
&sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in2_min.dev_attr.attr,
&sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in3_min.dev_attr.attr,
&sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in4_min.dev_attr.attr,
&sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
&sensor_dev_attr_in5_input.dev_attr.attr,
&sensor_dev_attr_in5_min.dev_attr.attr,
&sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
&dev_attr_temp1_input.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_aout_output.attr,
&dev_attr_chassis_clear.attr,
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
new file mode 100644
index 00000000000..6b8a73ef404
--- /dev/null
+++ b/drivers/hwmon/ads7828.c
@@ -0,0 +1,297 @@
+/*
+ ads7828.c - lm_sensors driver for ads7828 12-bit 8-channel ADC
+ (C) 2007 EADS Astrium
+
+ This driver is based on the lm75 and other lm_sensors/hwmon drivers
+
+ Written by Steve Hardy <steve@linuxrealtime.co.uk>
+
+ Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/* The ADS7828 registers */
+#define ADS7828_NCH 8 /* 8 channels of 12-bit A-D supported */
+#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */
+#define ADS7828_CMD_SD_DIFF 0x00 /* Differential inputs */
+#define ADS7828_CMD_PD0 0x0 /* Power Down between A-D conversions */
+#define ADS7828_CMD_PD1 0x04 /* Internal ref OFF && A-D ON */
+#define ADS7828_CMD_PD2 0x08 /* Internal ref ON && A-D OFF */
+#define ADS7828_CMD_PD3 0x0C /* Internal ref ON && A-D ON */
+#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+ I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(ads7828);
+
+/* Other module parameters */
+static int se_input = 1; /* Default is SE, 0 == diff */
+static int int_vref = 1; /* Default is internal ref ON */
+static int vref_mv = ADS7828_INT_VREF_MV; /* set if vref != 2.5V */
+module_param(se_input, bool, S_IRUGO);
+module_param(int_vref, bool, S_IRUGO);
+module_param(vref_mv, int, S_IRUGO);
+
+/* Global Variables */
+static u8 ads7828_cmd_byte; /* cmd byte without channel bits */
+static unsigned int ads7828_lsb_resol; /* resolution of the ADC sample lsb */
+
+/* Each client has this additional data */
+struct ads7828_data {
+ struct i2c_client client;
+ struct device *hwmon_dev;
+ struct mutex update_lock; /* mutex protect updates */
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+ u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH 12-bit samples */
+};
+
+/* Function declaration - necessary due to function dependencies */
+static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind);
+
+/* The ADS7828 returns the 12-bit sample in two bytes,
+ these are read as a word then byte-swapped */
+static u16 ads7828_read_value(struct i2c_client *client, u8 reg)
+{
+ return swab16(i2c_smbus_read_word_data(client, reg));
+}
+
+static inline u8 channel_cmd_byte(int ch)
+{
+ /* cmd byte C2,C1,C0 - see datasheet */
+ u8 cmd = (((ch>>1) | (ch&0x01)<<2)<<4);
+ cmd |= ads7828_cmd_byte;
+ return cmd;
+}
+
+/* Update data for the device (all 8 channels) */
+static struct ads7828_data *ads7828_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ads7828_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ unsigned int ch;
+ dev_dbg(&client->dev, "Starting ads7828 update\n");
+
+ for (ch = 0; ch < ADS7828_NCH; ch++) {
+ u8 cmd = channel_cmd_byte(ch);
+ data->adc_input[ch] = ads7828_read_value(client, cmd);
+ }
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+/* sysfs callback function */
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct ads7828_data *data = ads7828_update_device(dev);
+ /* Print value (in mV as specified in sysfs-interface documentation) */
+ return sprintf(buf, "%d\n", (data->adc_input[attr->index] *
+ ads7828_lsb_resol)/1000);
+}
+
+#define in_reg(offset)\
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\
+ NULL, offset)
+
+in_reg(0);
+in_reg(1);
+in_reg(2);
+in_reg(3);
+in_reg(4);
+in_reg(5);
+in_reg(6);
+in_reg(7);
+
+static struct attribute *ads7828_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group ads7828_group = {
+ .attrs = ads7828_attributes,
+};
+
+static int ads7828_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, ads7828_detect);
+}
+
+static int ads7828_detach_client(struct i2c_client *client)
+{
+ struct ads7828_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &ads7828_group);
+ i2c_detach_client(client);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ads7828_driver = {
+ .driver = {
+ .name = "ads7828",
+ },
+ .attach_adapter = ads7828_attach_adapter,
+ .detach_client = ads7828_detach_client,
+};
+
+/* This function is called by i2c_probe */
+static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct ads7828_data *data;
+ int err = 0;
+ const char *name = "";
+
+ /* Check we have a valid client */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
+ goto exit;
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ client structure, even though we cannot fill it completely yet.
+ But it allows us to access ads7828_read_value. */
+ data = kzalloc(sizeof(struct ads7828_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &ads7828_driver;
+
+ /* Now, we do the remaining detection. There is no identification
+ dedicated register so attempt to sanity check using knowledge of
+ the chip
+ - Read from the 8 channel addresses
+ - Check the top 4 bits of each result are not set (12 data bits)
+ */
+ if (kind < 0) {
+ int ch;
+ for (ch = 0; ch < ADS7828_NCH; ch++) {
+ u16 in_data;
+ u8 cmd = channel_cmd_byte(ch);
+ in_data = ads7828_read_value(client, cmd);
+ if (in_data & 0xF000) {
+ printk(KERN_DEBUG
+ "%s : Doesn't look like an ads7828 device\n",
+ __FUNCTION__);
+ goto exit_free;
+ }
+ }
+ }
+
+ /* Determine the chip type - only one kind supported! */
+ if (kind <= 0)
+ kind = ads7828;
+
+ if (kind == ads7828)
+ name = "ads7828";
+
+ /* Fill in the remaining client fields, put it into the global list */
+ strlcpy(client->name, name, I2C_NAME_SIZE);
+
+ mutex_init(&data->update_lock);
+
+ /* Tell the I2C layer a new client has arrived */
+ err = i2c_attach_client(client);
+ if (err)
+ goto exit_free;
+
+ /* Register sysfs hooks */
+ err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
+ if (err)
+ goto exit_detach;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &ads7828_group);
+exit_detach:
+ i2c_detach_client(client);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int __init sensors_ads7828_init(void)
+{
+ /* Initialize the command byte according to module parameters */
+ ads7828_cmd_byte = se_input ?
+ ADS7828_CMD_SD_SE : ADS7828_CMD_SD_DIFF;
+ ads7828_cmd_byte |= int_vref ?
+ ADS7828_CMD_PD3 : ADS7828_CMD_PD1;
+
+ /* Calculate the LSB resolution */
+ ads7828_lsb_resol = (vref_mv*1000)/4096;
+
+ return i2c_add_driver(&ads7828_driver);
+}
+
+static void __exit sensors_ads7828_exit(void)
+{
+ i2c_del_driver(&ads7828_driver);
+}
+
+MODULE_AUTHOR("Steve Hardy <steve@linuxrealtime.co.uk>");
+MODULE_DESCRIPTION("ADS7828 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_ads7828_init);
+module_exit(sensors_ads7828_exit);
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 9810aaa0489..747693ab2ff 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -48,7 +48,22 @@ I2C_CLIENT_INSMOD_1(adt7470);
#define ADT7470_REG_CFG 0x40
#define ADT7470_FSPD_MASK 0x04
#define ADT7470_REG_ALARM1 0x41
+#define ADT7470_R1T_ALARM 0x01
+#define ADT7470_R2T_ALARM 0x02
+#define ADT7470_R3T_ALARM 0x04
+#define ADT7470_R4T_ALARM 0x08
+#define ADT7470_R5T_ALARM 0x10
+#define ADT7470_R6T_ALARM 0x20
+#define ADT7470_R7T_ALARM 0x40
+#define ADT7470_OOL_ALARM 0x80
#define ADT7470_REG_ALARM2 0x42
+#define ADT7470_R8T_ALARM 0x01
+#define ADT7470_R9T_ALARM 0x02
+#define ADT7470_R10T_ALARM 0x04
+#define ADT7470_FAN1_ALARM 0x10
+#define ADT7470_FAN2_ALARM 0x20
+#define ADT7470_FAN3_ALARM 0x40
+#define ADT7470_FAN4_ALARM 0x80
#define ADT7470_REG_TEMP_LIMITS_BASE_ADDR 0x44
#define ADT7470_REG_TEMP_LIMITS_MAX_ADDR 0x57
#define ADT7470_REG_FAN_MIN_BASE_ADDR 0x58
@@ -97,6 +112,8 @@ I2C_CLIENT_INSMOD_1(adt7470);
#define ADT7470_REG_PWM_AUTO_TEMP(x) (ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR + \
((x) / 2))
+#define ALARM2(x) ((x) << 8)
+
#define ADT7470_VENDOR 0x41
#define ADT7470_DEVICE 0x70
/* datasheet only mentions a revision 2 */
@@ -114,8 +131,6 @@ I2C_CLIENT_INSMOD_1(adt7470);
/* sleep 1s while gathering temperature data */
#define TEMP_COLLECTION_TIME 1000
-#define power_of_2(x) (((x) & ((x) - 1)) == 0)
-
/* datasheet says to divide this number by the fan reading to get fan rpm */
#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x))
#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM
@@ -138,7 +153,8 @@ struct adt7470_data {
u16 fan[ADT7470_FAN_COUNT];
u16 fan_min[ADT7470_FAN_COUNT];
u16 fan_max[ADT7470_FAN_COUNT];
- u16 alarms, alarms_mask;
+ u16 alarm;
+ u16 alarms_mask;
u8 force_pwm_max;
u8 pwm[ADT7470_PWM_COUNT];
u8 pwm_max[ADT7470_PWM_COUNT];
@@ -262,7 +278,10 @@ static struct adt7470_data *adt7470_update_device(struct device *dev)
else
data->force_pwm_max = 0;
- data->alarms = adt7470_read_word_data(client, ADT7470_REG_ALARM1);
+ data->alarm = i2c_smbus_read_byte_data(client, ADT7470_REG_ALARM1);
+ if (data->alarm & ADT7470_OOL_ALARM)
+ data->alarm |= ALARM2(i2c_smbus_read_byte_data(client,
+ ADT7470_REG_ALARM2));
data->alarms_mask = adt7470_read_word_data(client,
ADT7470_REG_ALARM1_MASK);
@@ -370,17 +389,13 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]);
}
-static ssize_t show_alarms(struct device *dev,
+static ssize_t show_alarm_mask(struct device *dev,
struct device_attribute *devattr,
char *buf)
{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
- if (attr->index)
- return sprintf(buf, "%x\n", data->alarms);
- else
- return sprintf(buf, "%x\n", data->alarms_mask);
+ return sprintf(buf, "%x\n", data->alarms_mask);
}
static ssize_t show_fan_max(struct device *dev,
@@ -677,7 +692,7 @@ static int cvt_auto_temp(int input)
{
if (input == ADT7470_PWM_ALL_TEMPS)
return 0;
- if (input < 1 || !power_of_2(input))
+ if (input < 1 || !is_power_of_2(input))
return -EINVAL;
return ilog2(input) + 1;
}
@@ -715,8 +730,20 @@ static ssize_t set_pwm_auto_temp(struct device *dev,
return count;
}
-static SENSOR_DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL, 0);
-static SENSOR_DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarms, NULL, 1);
+static ssize_t show_alarm(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+
+ if (data->alarm & attr->index)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarm_mask, NULL);
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
set_temp_max, 0);
@@ -771,6 +798,27 @@ static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7);
static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8);
static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_temp, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL,
+ ADT7470_R1T_ALARM);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL,
+ ADT7470_R2T_ALARM);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL,
+ ADT7470_R3T_ALARM);
+static SENSOR_DEVICE_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL,
+ ADT7470_R4T_ALARM);
+static SENSOR_DEVICE_ATTR(temp5_alarm, S_IRUGO, show_alarm, NULL,
+ ADT7470_R5T_ALARM);
+static SENSOR_DEVICE_ATTR(temp6_alarm, S_IRUGO, show_alarm, NULL,
+ ADT7470_R6T_ALARM);
+static SENSOR_DEVICE_ATTR(temp7_alarm, S_IRUGO, show_alarm, NULL,
+ ADT7470_R7T_ALARM);
+static SENSOR_DEVICE_ATTR(temp8_alarm, S_IRUGO, show_alarm, NULL,
+ ALARM2(ADT7470_R8T_ALARM));
+static SENSOR_DEVICE_ATTR(temp9_alarm, S_IRUGO, show_alarm, NULL,
+ ALARM2(ADT7470_R9T_ALARM));
+static SENSOR_DEVICE_ATTR(temp10_alarm, S_IRUGO, show_alarm, NULL,
+ ALARM2(ADT7470_R10T_ALARM));
+
static SENSOR_DEVICE_ATTR(fan1_max, S_IWUSR | S_IRUGO, show_fan_max,
set_fan_max, 0);
static SENSOR_DEVICE_ATTR(fan2_max, S_IWUSR | S_IRUGO, show_fan_max,
@@ -794,6 +842,15 @@ static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL,
+ ALARM2(ADT7470_FAN1_ALARM));
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL,
+ ALARM2(ADT7470_FAN2_ALARM));
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL,
+ ALARM2(ADT7470_FAN3_ALARM));
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL,
+ ALARM2(ADT7470_FAN4_ALARM));
+
static SENSOR_DEVICE_ATTR(force_pwm_max, S_IWUSR | S_IRUGO,
show_force_pwm_max, set_force_pwm_max, 0);
@@ -858,8 +915,7 @@ static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO,
static struct attribute *adt7470_attr[] =
{
- &sensor_dev_attr_alarms.dev_attr.attr,
- &sensor_dev_attr_alarm_mask.dev_attr.attr,
+ &dev_attr_alarm_mask.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
@@ -890,6 +946,16 @@ static struct attribute *adt7470_attr[] =
&sensor_dev_attr_temp8_input.dev_attr.attr,
&sensor_dev_attr_temp9_input.dev_attr.attr,
&sensor_dev_attr_temp10_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp5_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp6_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp7_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp8_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp9_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp10_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_max.dev_attr.attr,
&sensor_dev_attr_fan2_max.dev_attr.attr,
&sensor_dev_attr_fan3_max.dev_attr.attr,
@@ -902,6 +968,10 @@ static struct attribute *adt7470_attr[] =
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan4_alarm.dev_attr.attr,
&sensor_dev_attr_force_pwm_max.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm2.dev_attr.attr,
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 9460dba4cf7..950cea8d1d6 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -40,6 +40,7 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/init.h>
@@ -47,12 +48,6 @@
#include <linux/mutex.h>
#include "lm75.h"
-/*
- HISTORY:
- 2003-12-29 1.0.0 Ported from lm_sensors project for kernel 2.6
-*/
-#define ASB100_VERSION "1.0.0"
-
/* I2C addresses to scan */
static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
@@ -221,15 +216,16 @@ static struct i2c_driver asb100_driver = {
.driver = {
.name = "asb100",
},
- .id = I2C_DRIVERID_ASB100,
.attach_adapter = asb100_attach_adapter,
.detach_client = asb100_detach_client,
};
/* 7 Voltages */
#define show_in_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
{ \
+ int nr = to_sensor_dev_attr(attr)->index; \
struct asb100_data *data = asb100_update_device(dev); \
return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \
}
@@ -239,9 +235,10 @@ show_in_reg(in_min)
show_in_reg(in_max)
#define set_in_reg(REG, reg) \
-static ssize_t set_in_##reg(struct device *dev, const char *buf, \
- size_t count, int nr) \
+static ssize_t set_in_##reg(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
{ \
+ int nr = to_sensor_dev_attr(attr)->index; \
struct i2c_client *client = to_i2c_client(dev); \
struct asb100_data *data = i2c_get_clientdata(client); \
unsigned long val = simple_strtoul(buf, NULL, 10); \
@@ -258,37 +255,12 @@ set_in_reg(MIN, min)
set_in_reg(MAX, max)
#define sysfs_in(offset) \
-static ssize_t \
- show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in(dev, buf, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
- show_in##offset, NULL); \
-static ssize_t \
- show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_min(dev, buf, offset); \
-} \
-static ssize_t \
- show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_max(dev, buf, offset); \
-} \
-static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_min(dev, buf, count, offset); \
-} \
-static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_max(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
- show_in##offset##_min, set_in##offset##_min); \
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
- show_in##offset##_max, set_in##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in_max, set_in_max, offset)
sysfs_in(0);
sysfs_in(1);
@@ -299,29 +271,36 @@ sysfs_in(5);
sysfs_in(6);
/* 3 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct asb100_data *data = asb100_update_device(dev);
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
DIV_FROM_REG(data->fan_div[nr])));
}
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct asb100_data *data = asb100_update_device(dev);
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr])));
}
-static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct asb100_data *data = asb100_update_device(dev);
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
}
-static ssize_t set_fan_min(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct asb100_data *data = i2c_get_clientdata(client);
u32 val = simple_strtoul(buf, NULL, 10);
@@ -337,22 +316,23 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
determined in part by the fan divisor. This follows the principle of
least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
-static ssize_t set_fan_div(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct asb100_data *data = i2c_get_clientdata(client);
unsigned long min;
unsigned long val = simple_strtoul(buf, NULL, 10);
int reg;
-
+
mutex_lock(&data->update_lock);
min = FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr]));
data->fan_div[nr] = DIV_TO_REG(val);
- switch(nr) {
+ switch (nr) {
case 0: /* fan 1 */
reg = asb100_read_value(client, ASB100_REG_VID_FANDIV);
reg = (reg & 0xcf) | (data->fan_div[0] << 4);
@@ -382,34 +362,12 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
}
#define sysfs_fan(offset) \
-static ssize_t show_fan##offset(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_min(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_div(dev, buf, offset - 1); \
-} \
-static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- return set_fan_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- return set_fan_div(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
- show_fan##offset, NULL); \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
- show_fan##offset##_min, set_fan##offset##_min); \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
- show_fan##offset##_div, set_fan##offset##_div);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, set_fan_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+ show_fan_div, set_fan_div, offset - 1)
sysfs_fan(1);
sysfs_fan(2);
@@ -430,10 +388,12 @@ static int sprintf_temp_from_reg(u16 reg, char *buf, int nr)
}
return ret;
}
-
+
#define show_temp_reg(reg) \
-static ssize_t show_##reg(struct device *dev, char *buf, int nr) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
{ \
+ int nr = to_sensor_dev_attr(attr)->index; \
struct asb100_data *data = asb100_update_device(dev); \
return sprintf_temp_from_reg(data->reg[nr], buf, nr); \
}
@@ -443,9 +403,10 @@ show_temp_reg(temp_max);
show_temp_reg(temp_hyst);
#define set_temp_reg(REG, reg) \
-static ssize_t set_##reg(struct device *dev, const char *buf, \
- size_t count, int nr) \
+static ssize_t set_##reg(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
{ \
+ int nr = to_sensor_dev_attr(attr)->index; \
struct i2c_client *client = to_i2c_client(dev); \
struct asb100_data *data = i2c_get_clientdata(client); \
long val = simple_strtol(buf, NULL, 10); \
@@ -469,33 +430,12 @@ set_temp_reg(MAX, temp_max);
set_temp_reg(HYST, temp_hyst);
#define sysfs_temp(num) \
-static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp(dev, buf, num-1); \
-} \
-static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL); \
-static ssize_t show_temp_max##num(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_max(dev, buf, num-1); \
-} \
-static ssize_t set_temp_max##num(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- return set_temp_max(dev, buf, count, num-1); \
-} \
-static DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \
- show_temp_max##num, set_temp_max##num); \
-static ssize_t show_temp_hyst##num(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_hyst(dev, buf, num-1); \
-} \
-static ssize_t set_temp_hyst##num(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- return set_temp_hyst(dev, buf, count, num-1); \
-} \
-static DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \
- show_temp_hyst##num, set_temp_hyst##num);
+static SENSOR_DEVICE_ATTR(temp##num##_input, S_IRUGO, \
+ show_temp, NULL, num - 1); \
+static SENSOR_DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \
+ show_temp_max, set_temp_max, num - 1); \
+static SENSOR_DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \
+ show_temp_hyst, set_temp_hyst, num - 1)
sysfs_temp(1);
sysfs_temp(2);
@@ -503,7 +443,8 @@ sysfs_temp(3);
sysfs_temp(4);
/* VID */
-static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct asb100_data *data = asb100_update_device(dev);
return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
@@ -512,25 +453,26 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
/* VRM */
-static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct asb100_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->vrm);
}
-static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct asb100_data *data = i2c_get_clientdata(client);
- unsigned long val = simple_strtoul(buf, NULL, 10);
- data->vrm = val;
+ struct asb100_data *data = dev_get_drvdata(dev);
+ data->vrm = simple_strtoul(buf, NULL, 10);
return count;
}
/* Alarms */
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct asb100_data *data = asb100_update_device(dev);
return sprintf(buf, "%u\n", data->alarms);
@@ -538,14 +480,35 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct asb100_data *data = asb100_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
+
/* 1 PWM */
-static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct asb100_data *data = asb100_update_device(dev);
return sprintf(buf, "%d\n", ASB100_PWM_FROM_REG(data->pwm & 0x0f));
}
-static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct asb100_data *data = i2c_get_clientdata(client);
@@ -559,14 +522,15 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const
return count;
}
-static ssize_t show_pwm_enable1(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_pwm_enable1(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct asb100_data *data = asb100_update_device(dev);
return sprintf(buf, "%d\n", (data->pwm & 0x80) ? 1 : 0);
}
-static ssize_t set_pwm_enable1(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count)
+static ssize_t set_pwm_enable1(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct asb100_data *data = i2c_get_clientdata(client);
@@ -585,50 +549,62 @@ static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
show_pwm_enable1, set_pwm_enable1);
static struct attribute *asb100_attributes[] = {
- &dev_attr_in0_input.attr,
- &dev_attr_in0_min.attr,
- &dev_attr_in0_max.attr,
- &dev_attr_in1_input.attr,
- &dev_attr_in1_min.attr,
- &dev_attr_in1_max.attr,
- &dev_attr_in2_input.attr,
- &dev_attr_in2_min.attr,
- &dev_attr_in2_max.attr,
- &dev_attr_in3_input.attr,
- &dev_attr_in3_min.attr,
- &dev_attr_in3_max.attr,
- &dev_attr_in4_input.attr,
- &dev_attr_in4_min.attr,
- &dev_attr_in4_max.attr,
- &dev_attr_in5_input.attr,
- &dev_attr_in5_min.attr,
- &dev_attr_in5_max.attr,
- &dev_attr_in6_input.attr,
- &dev_attr_in6_min.attr,
- &dev_attr_in6_max.attr,
-
- &dev_attr_fan1_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan1_div.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan2_div.attr,
- &dev_attr_fan3_input.attr,
- &dev_attr_fan3_min.attr,
- &dev_attr_fan3_div.attr,
-
- &dev_attr_temp1_input.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp1_max_hyst.attr,
- &dev_attr_temp2_input.attr,
- &dev_attr_temp2_max.attr,
- &dev_attr_temp2_max_hyst.attr,
- &dev_attr_temp3_input.attr,
- &dev_attr_temp3_max.attr,
- &dev_attr_temp3_max_hyst.attr,
- &dev_attr_temp4_input.attr,
- &dev_attr_temp4_max.attr,
- &dev_attr_temp4_max_hyst.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_div.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
+
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
&dev_attr_cpu0_vid.attr,
&dev_attr_vrm.attr,
@@ -656,10 +632,10 @@ static int asb100_attach_adapter(struct i2c_adapter *adapter)
}
static int asb100_detect_subclients(struct i2c_adapter *adapter, int address,
- int kind, struct i2c_client *new_client)
+ int kind, struct i2c_client *client)
{
int i, id, err;
- struct asb100_data *data = i2c_get_clientdata(new_client);
+ struct asb100_data *data = i2c_get_clientdata(client);
data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (!(data->lm75[0])) {
@@ -679,26 +655,26 @@ static int asb100_detect_subclients(struct i2c_adapter *adapter, int address,
for (i = 2; i <= 3; i++) {
if (force_subclients[i] < 0x48 ||
force_subclients[i] > 0x4f) {
- dev_err(&new_client->dev, "invalid subclient "
+ dev_err(&client->dev, "invalid subclient "
"address %d; must be 0x48-0x4f\n",
force_subclients[i]);
err = -ENODEV;
goto ERROR_SC_2;
}
}
- asb100_write_value(new_client, ASB100_REG_I2C_SUBADDR,
+ asb100_write_value(client, ASB100_REG_I2C_SUBADDR,
(force_subclients[2] & 0x07) |
- ((force_subclients[3] & 0x07) <<4));
+ ((force_subclients[3] & 0x07) << 4));
data->lm75[0]->addr = force_subclients[2];
data->lm75[1]->addr = force_subclients[3];
} else {
- int val = asb100_read_value(new_client, ASB100_REG_I2C_SUBADDR);
+ int val = asb100_read_value(client, ASB100_REG_I2C_SUBADDR);
data->lm75[0]->addr = 0x48 + (val & 0x07);
data->lm75[1]->addr = 0x48 + ((val >> 4) & 0x07);
}
- if(data->lm75[0]->addr == data->lm75[1]->addr) {
- dev_err(&new_client->dev, "duplicate addresses 0x%x "
+ if (data->lm75[0]->addr == data->lm75[1]->addr) {
+ dev_err(&client->dev, "duplicate addresses 0x%x "
"for subclients\n", data->lm75[0]->addr);
err = -ENODEV;
goto ERROR_SC_2;
@@ -708,18 +684,17 @@ static int asb100_detect_subclients(struct i2c_adapter *adapter, int address,
i2c_set_clientdata(data->lm75[i], NULL);
data->lm75[i]->adapter = adapter;
data->lm75[i]->driver = &asb100_driver;
- data->lm75[i]->flags = 0;
strlcpy(data->lm75[i]->name, "asb100 subclient", I2C_NAME_SIZE);
}
if ((err = i2c_attach_client(data->lm75[0]))) {
- dev_err(&new_client->dev, "subclient %d registration "
+ dev_err(&client->dev, "subclient %d registration "
"at address 0x%x failed.\n", i, data->lm75[0]->addr);
goto ERROR_SC_2;
}
if ((err = i2c_attach_client(data->lm75[1]))) {
- dev_err(&new_client->dev, "subclient %d registration "
+ dev_err(&client->dev, "subclient %d registration "
"at address 0x%x failed.\n", i, data->lm75[1]->addr);
goto ERROR_SC_3;
}
@@ -740,7 +715,7 @@ ERROR_SC_0:
static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
{
int err;
- struct i2c_client *new_client;
+ struct i2c_client *client;
struct asb100_data *data;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
@@ -760,13 +735,12 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
goto ERROR0;
}
- new_client = &data->client;
+ client = &data->client;
mutex_init(&data->lock);
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &asb100_driver;
- new_client->flags = 0;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &asb100_driver;
/* Now, we do the remaining detection. */
@@ -776,15 +750,15 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
bank. */
if (kind < 0) {
- int val1 = asb100_read_value(new_client, ASB100_REG_BANK);
- int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN);
+ int val1 = asb100_read_value(client, ASB100_REG_BANK);
+ int val2 = asb100_read_value(client, ASB100_REG_CHIPMAN);
/* If we're in bank 0 */
- if ( (!(val1 & 0x07)) &&
+ if ((!(val1 & 0x07)) &&
/* Check for ASB100 ID (low byte) */
- ( ((!(val1 & 0x80)) && (val2 != 0x94)) ||
+ (((!(val1 & 0x80)) && (val2 != 0x94)) ||
/* Check for ASB100 ID (high byte ) */
- ((val1 & 0x80) && (val2 != 0x06)) ) ) {
+ ((val1 & 0x80) && (val2 != 0x06)))) {
pr_debug("asb100.o: detect failed, "
"bad chip id 0x%02x!\n", val2);
err = -ENODEV;
@@ -795,19 +769,19 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
/* We have either had a force parameter, or we have already detected
Winbond. Put it now into bank 0 and Vendor ID High Byte */
- asb100_write_value(new_client, ASB100_REG_BANK,
- (asb100_read_value(new_client, ASB100_REG_BANK) & 0x78) | 0x80);
+ asb100_write_value(client, ASB100_REG_BANK,
+ (asb100_read_value(client, ASB100_REG_BANK) & 0x78) | 0x80);
/* Determine the chip type. */
if (kind <= 0) {
- int val1 = asb100_read_value(new_client, ASB100_REG_WCHIPID);
- int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN);
+ int val1 = asb100_read_value(client, ASB100_REG_WCHIPID);
+ int val2 = asb100_read_value(client, ASB100_REG_CHIPMAN);
if ((val1 == 0x31) && (val2 == 0x06))
kind = asb100;
else {
if (kind == 0)
- dev_warn(&new_client->dev, "ignoring "
+ dev_warn(&client->dev, "ignoring "
"'force' parameter for unknown chip "
"at adapter %d, address 0x%02x.\n",
i2c_adapter_id(adapter), address);
@@ -817,34 +791,32 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Fill in remaining client fields and put it into the global list */
- strlcpy(new_client->name, "asb100", I2C_NAME_SIZE);
+ strlcpy(client->name, "asb100", I2C_NAME_SIZE);
data->type = kind;
-
- data->valid = 0;
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
+ if ((err = i2c_attach_client(client)))
goto ERROR1;
/* Attach secondary lm75 clients */
if ((err = asb100_detect_subclients(adapter, address, kind,
- new_client)))
+ client)))
goto ERROR2;
/* Initialize the chip */
- asb100_init_client(new_client);
+ asb100_init_client(client);
/* A few vars need to be filled upon startup */
- data->fan_min[0] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(0));
- data->fan_min[1] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(1));
- data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2));
+ data->fan_min[0] = asb100_read_value(client, ASB100_REG_FAN_MIN(0));
+ data->fan_min[1] = asb100_read_value(client, ASB100_REG_FAN_MIN(1));
+ data->fan_min[2] = asb100_read_value(client, ASB100_REG_FAN_MIN(2));
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &asb100_group)))
+ if ((err = sysfs_create_group(&client->dev.kobj, &asb100_group)))
goto ERROR3;
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto ERROR4;
@@ -853,14 +825,14 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
ERROR4:
- sysfs_remove_group(&new_client->dev.kobj, &asb100_group);
+ sysfs_remove_group(&client->dev.kobj, &asb100_group);
ERROR3:
i2c_detach_client(data->lm75[1]);
i2c_detach_client(data->lm75[0]);
kfree(data->lm75[1]);
kfree(data->lm75[0]);
ERROR2:
- i2c_detach_client(new_client);
+ i2c_detach_client(client);
ERROR1:
kfree(data);
ERROR0:
@@ -916,17 +888,17 @@ static int asb100_read_value(struct i2c_client *client, u16 reg)
/* convert from ISA to LM75 I2C addresses */
switch (reg & 0xff) {
case 0x50: /* TEMP */
- res = swab16(i2c_smbus_read_word_data (cl, 0));
+ res = swab16(i2c_smbus_read_word_data(cl, 0));
break;
case 0x52: /* CONFIG */
res = i2c_smbus_read_byte_data(cl, 1);
break;
case 0x53: /* HYST */
- res = swab16(i2c_smbus_read_word_data (cl, 2));
+ res = swab16(i2c_smbus_read_word_data(cl, 2));
break;
case 0x55: /* MAX */
default:
- res = swab16(i2c_smbus_read_word_data (cl, 3));
+ res = swab16(i2c_smbus_read_word_data(cl, 3));
break;
}
}
@@ -989,7 +961,7 @@ static void asb100_init_client(struct i2c_client *client)
vid = vid_from_reg(vid, data->vrm);
/* Start monitoring */
- asb100_write_value(client, ASB100_REG_CONFIG,
+ asb100_write_value(client, ASB100_REG_CONFIG,
(asb100_read_value(client, ASB100_REG_CONFIG) & 0xf7) | 0x01);
}
@@ -1078,4 +1050,3 @@ MODULE_LICENSE("GPL");
module_init(asb100_init);
module_exit(asb100_exit);
-
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index a878c98e252..ddddd9f34c1 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -44,6 +44,10 @@ static int force_start;
module_param(force_start, bool, 0);
MODULE_PARM_DESC(force_start, "Force the chip to start monitoring inputs");
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
/* Addresses to scan */
static unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
@@ -279,14 +283,21 @@ static inline int TEMP_HYST_TO_REG(int val, int ix, int reg)
/* Fan input RPM */
static inline int FAN_FROM_REG(int reg, int tpc)
{
- return (reg == 0 || reg == 0xffff) ? 0 :
- (tpc == 0) ? 90000 * 60 / reg : tpc * reg;
+ if (tpc) {
+ return tpc * reg;
+ } else {
+ return (reg == 0 || reg == 0xffff) ? 0 : 90000 * 60 / reg;
+ }
}
static inline int FAN_TO_REG(int val, int tpc)
{
- return SENSORS_LIMIT((tpc == 0) ? 90000 * 60 / val : val / tpc,
- 0, 0xffff);
+ if (tpc) {
+ return SENSORS_LIMIT(val / tpc, 0, 0xffff);
+ } else {
+ return (val <= 0) ? 0xffff :
+ SENSORS_LIMIT(90000 * 60 / val, 0, 0xfffe);
+ }
}
/* Fan TPC (tach pulse count)
@@ -2019,7 +2030,7 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
/* Check device ID
* The DME1737 can return either 0x78 or 0x77 as its device ID. */
- reg = dme1737_sio_inb(sio_cip, 0x20);
+ reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
if (!(reg == 0x77 || reg == 0x78)) {
err = -ENODEV;
goto exit;
@@ -2191,7 +2202,7 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr)
/* Check device ID
* We currently know about SCH3112 (0x7c), SCH3114 (0x7d), and
* SCH3116 (0x7f). */
- reg = dme1737_sio_inb(sio_cip, 0x20);
+ reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) {
err = -ENODEV;
goto exit;
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index b7bd000b130..3f5163de13c 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -94,7 +94,6 @@ static struct i2c_driver ds1621_driver = {
.driver = {
.name = "ds1621",
},
- .id = I2C_DRIVERID_DS1621,
.attach_adapter = ds1621_attach_adapter,
.detach_client = ds1621_detach_client,
};
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 5d9d5cc816a..7a14a2dbb75 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -41,6 +41,10 @@
#include <linux/ioport.h>
#include <asm/io.h>
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
static struct platform_device *pdev;
#define DRVNAME "f71805f"
@@ -1497,7 +1501,7 @@ static int __init f71805f_find(int sioaddr, unsigned short *address,
if (devid != SIO_FINTEK_ID)
goto exit;
- devid = superio_inw(sioaddr, SIO_REG_DEVID);
+ devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
switch (devid) {
case SIO_F71805F_ID:
sio_data->kind = f71805f;
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index 6db74434a02..cbeb4984b5c 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -74,6 +74,10 @@
#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
static struct platform_device *f71882fg_pdev = NULL;
/* Super-I/O Function prototypes */
@@ -843,7 +847,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address)
goto exit;
}
- devid = superio_inw(sioaddr, SIO_REG_DEVID);
+ devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
if (devid != SIO_F71882_ID) {
printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
goto exit;
diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c
index e67c36953b2..721c70177b1 100644
--- a/drivers/hwmon/fscher.c
+++ b/drivers/hwmon/fscher.c
@@ -123,7 +123,6 @@ static struct i2c_driver fscher_driver = {
.driver = {
.name = "fscher",
},
- .id = I2C_DRIVERID_FSCHER,
.attach_adapter = fscher_attach_adapter,
.detach_client = fscher_detach_client,
};
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index 63a4df0580d..b7c9eef0f92 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -41,6 +41,7 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/dmi.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
@@ -133,7 +134,7 @@ static const u8 FSCHMD_REG_TEMP_STATE[5][5] = {
{ 0x71, 0x81, 0x91 }, /* her */
{ 0x71, 0xd1, 0x81, 0x91 }, /* scy */
{ 0x71, 0x81, 0x91 }, /* hrc */
- { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */
+ { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */
};
/* temperature high limit registers, FSC does not document these. Proven to be
@@ -146,7 +147,7 @@ static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = {
{ 0x76, 0x86, 0x96 }, /* her */
{ 0x76, 0xd6, 0x86, 0x96 }, /* scy */
{ 0x76, 0x86, 0x96 }, /* hrc */
- { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */
+ { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */
};
/* These were found through experimenting with an fscher, currently they are
@@ -210,6 +211,13 @@ struct fschmd_data {
u8 fan_ripple[6]; /* divider for rps */
};
+/* Global variables to hold information read from special DMI tables, which are
+ available on FSC machines with an fscher or later chip. */
+static int dmi_mult[3] = { 490, 200, 100 };
+static int dmi_offset[3] = { 0, 0, 0 };
+static int dmi_vref = -1;
+
+
/*
* Sysfs attr show / store functions
*/
@@ -221,8 +229,13 @@ static ssize_t show_in_value(struct device *dev,
int index = to_sensor_dev_attr(devattr)->index;
struct fschmd_data *data = fschmd_update_device(dev);
- return sprintf(buf, "%d\n", (data->volt[index] *
- max_reading[index] + 128) / 255);
+ /* fscher / fschrc - 1 as data->kind is an array index, not a chips */
+ if (data->kind == (fscher - 1) || data->kind >= (fschrc - 1))
+ return sprintf(buf, "%d\n", (data->volt[index] * dmi_vref *
+ dmi_mult[index]) / 255 + dmi_offset[index]);
+ else
+ return sprintf(buf, "%d\n", (data->volt[index] *
+ max_reading[index] + 128) / 255);
}
@@ -525,6 +538,68 @@ static struct sensor_device_attribute fschmd_fan_attr[] = {
* Real code
*/
+/* DMI decode routine to read voltage scaling factors from special DMI tables,
+ which are available on FSC machines with an fscher or later chip. */
+static void fschmd_dmi_decode(const struct dmi_header *header)
+{
+ int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0;
+
+ /* dmi code ugliness, we get passed the address of the contents of
+ a complete DMI record, but in the form of a dmi_header pointer, in
+ reality this address holds header->length bytes of which the header
+ are the first 4 bytes */
+ u8 *dmi_data = (u8 *)header;
+
+ /* We are looking for OEM-specific type 185 */
+ if (header->type != 185)
+ return;
+
+ /* we are looking for what Siemens calls "subtype" 19, the subtype
+ is stored in byte 5 of the dmi block */
+ if (header->length < 5 || dmi_data[4] != 19)
+ return;
+
+ /* After the subtype comes 1 unknown byte and then blocks of 5 bytes,
+ consisting of what Siemens calls an "Entity" number, followed by
+ 2 16-bit words in LSB first order */
+ for (i = 6; (i + 4) < header->length; i += 5) {
+ /* entity 1 - 3: voltage multiplier and offset */
+ if (dmi_data[i] >= 1 && dmi_data[i] <= 3) {
+ /* Our in sensors order and the DMI order differ */
+ const int shuffle[3] = { 1, 0, 2 };
+ int in = shuffle[dmi_data[i] - 1];
+
+ /* Check for twice the same entity */
+ if (found & (1 << in))
+ return;
+
+ mult[in] = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
+ offset[in] = dmi_data[i + 3] | (dmi_data[i + 4] << 8);
+
+ found |= 1 << in;
+ }
+
+ /* entity 7: reference voltage */
+ if (dmi_data[i] == 7) {
+ /* Check for twice the same entity */
+ if (found & 0x08)
+ return;
+
+ vref = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
+
+ found |= 0x08;
+ }
+ }
+
+ if (found == 0x0F) {
+ for (i = 0; i < 3; i++) {
+ dmi_mult[i] = mult[i] * 10;
+ dmi_offset[i] = offset[i] * 10;
+ }
+ dmi_vref = vref;
+ }
+}
+
static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *client;
@@ -586,6 +661,17 @@ static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
data->temp_max[2] = 50 + 128;
}
+ /* Read the special DMI table for fscher and newer chips */
+ if (kind == fscher || kind >= fschrc) {
+ dmi_walk(fschmd_dmi_decode);
+ if (dmi_vref == -1) {
+ printk(KERN_WARNING FSCHMD_NAME
+ ": Couldn't get voltage scaling factors from "
+ "BIOS DMI table, using builtin defaults\n");
+ dmi_vref = 33;
+ }
+ }
+
/* i2c kind goes from 1-5, we want from 0-4 to address arrays */
data->kind = kind - 1;
strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE);
diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c
index 92c9703d0ac..2f1075323a1 100644
--- a/drivers/hwmon/fscpos.c
+++ b/drivers/hwmon/fscpos.c
@@ -105,7 +105,6 @@ static struct i2c_driver fscpos_driver = {
.driver = {
.name = "fscpos",
},
- .id = I2C_DRIVERID_FSCPOS,
.attach_adapter = fscpos_attach_adapter,
.detach_client = fscpos_detach_client,
};
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index bb58d9866a3..3b1ac48fce2 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -30,10 +30,6 @@
* We did not keep that part of the original driver in the Linux 2.6
* version, since it was making the driver significantly more complex
* with no real benefit.
- *
- * History:
- * 2004-01-28 Original port. (Hong-Gunn Chew)
- * 2004-01-31 Code review and approval. (Jean Delvare)
*/
#include <linux/module.h>
@@ -42,6 +38,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
@@ -99,10 +96,10 @@ static inline u8 FAN_TO_REG(long rpm, int div)
long rpmdiv;
if (rpm == 0)
return 0;
- rpmdiv = SENSORS_LIMIT(rpm, 1, 1920000) * div;
- return SENSORS_LIMIT((960000 + rpmdiv / 2) / rpmdiv, 1, 255);
+ rpmdiv = SENSORS_LIMIT(rpm, 1, 960000) * div;
+ return SENSORS_LIMIT((480000 + rpmdiv / 2) / rpmdiv, 1, 255);
}
-#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (960000/((val)*(div))))
+#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val)*(div))))
#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255))
#define IN_FROM_REG(val) ((val)*19)
@@ -110,7 +107,6 @@ static inline u8 FAN_TO_REG(long rpm, int div)
#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255))
#define VDD_FROM_REG(val) (((val)*95+2)/4)
-#define DIV_TO_REG(val) ((val)==4?2:(val)==2?1:(val)==1?0:3)
#define DIV_FROM_REG(val) (1 << (val))
#define BEEP_MASK_TO_REG(val) ((val) & 0x7f & data->alarm_mask)
@@ -129,7 +125,6 @@ struct gl518_data {
u8 voltage_in[4]; /* Register values; [0] = VDD */
u8 voltage_min[4]; /* Register values; [0] = VDD */
u8 voltage_max[4]; /* Register values; [0] = VDD */
- u8 iter_voltage_in[4]; /* Register values; [0] = VDD */
u8 fan_in[2];
u8 fan_min[2];
u8 fan_div[2]; /* Register encoding, shifted right */
@@ -138,7 +133,7 @@ struct gl518_data {
u8 temp_max; /* Register values */
u8 temp_hyst; /* Register values */
u8 alarms; /* Register value */
- u8 alarm_mask; /* Register value */
+ u8 alarm_mask;
u8 beep_mask; /* Register value */
u8 beep_enable; /* Boolean */
};
@@ -156,7 +151,6 @@ static struct i2c_driver gl518_driver = {
.driver = {
.name = "gl518sm",
},
- .id = I2C_DRIVERID_GL518,
.attach_adapter = gl518_attach_adapter,
.detach_client = gl518_detach_client,
};
@@ -172,24 +166,10 @@ static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", type##_FROM_REG(data->value)); \
}
-#define show_fan(suffix, value, index) \
-static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct gl518_data *data = gl518_update_device(dev); \
- return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[index], \
- DIV_FROM_REG(data->fan_div[index]))); \
-}
-
show(TEMP, temp_input1, temp_in);
show(TEMP, temp_max1, temp_max);
show(TEMP, temp_hyst1, temp_hyst);
show(BOOL, fan_auto1, fan_auto1);
-show_fan(fan_input1, fan_in, 0);
-show_fan(fan_input2, fan_in, 1);
-show_fan(fan_min1, fan_min, 0);
-show_fan(fan_min2, fan_min, 1);
-show(DIV, fan_div1, fan_div[0]);
-show(DIV, fan_div2, fan_div[1]);
show(VDD, in_input0, voltage_in[0]);
show(IN, in_input1, voltage_in[1]);
show(IN, in_input2, voltage_in[2]);
@@ -206,6 +186,32 @@ show(RAW, alarms, alarms);
show(BOOL, beep_enable, beep_enable);
show(BEEP_MASK, beep_mask, beep_mask);
+static ssize_t show_fan_input(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct gl518_data *data = gl518_update_device(dev);
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_in[nr],
+ DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t show_fan_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct gl518_data *data = gl518_update_device(dev);
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
+ DIV_FROM_REG(data->fan_div[nr])));
+}
+
+static ssize_t show_fan_div(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct gl518_data *data = gl518_update_device(dev);
+ return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
+}
+
#define set(type, suffix, value, reg) \
static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \
size_t count) \
@@ -247,8 +253,6 @@ static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, c
set(TEMP, temp_max1, temp_max, GL518_REG_TEMP_MAX);
set(TEMP, temp_hyst1, temp_hyst, GL518_REG_TEMP_HYST);
set_bits(BOOL, fan_auto1, fan_auto1, GL518_REG_MISC, 0x08, 3);
-set_bits(DIV, fan_div1, fan_div[0], GL518_REG_MISC, 0xc0, 6);
-set_bits(DIV, fan_div2, fan_div[1], GL518_REG_MISC, 0x30, 4);
set_low(VDD, in_min0, voltage_min[0], GL518_REG_VDD_LIMIT);
set_low(IN, in_min1, voltage_min[1], GL518_REG_VIN1_LIMIT);
set_low(IN, in_min2, voltage_min[2], GL518_REG_VIN2_LIMIT);
@@ -260,25 +264,27 @@ set_high(IN, in_max3, voltage_max[3], GL518_REG_VIN3_LIMIT);
set_bits(BOOL, beep_enable, beep_enable, GL518_REG_CONF, 0x04, 2);
set(BEEP_MASK, beep_mask, beep_mask, GL518_REG_ALARM);
-static ssize_t set_fan_min1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct gl518_data *data = i2c_get_clientdata(client);
+ int nr = to_sensor_dev_attr(attr)->index;
int regvalue;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT);
- data->fan_min[0] = FAN_TO_REG(val,
- DIV_FROM_REG(data->fan_div[0]));
- regvalue = (regvalue & 0x00ff) | (data->fan_min[0] << 8);
+ data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+ regvalue = (regvalue & (0xff << (8 * nr)))
+ | (data->fan_min[nr] << (8 * (1 - nr)));
gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue);
data->beep_mask = gl518_read_value(client, GL518_REG_ALARM);
- if (data->fan_min[0] == 0)
- data->alarm_mask &= ~0x20;
+ if (data->fan_min[nr] == 0)
+ data->alarm_mask &= ~(0x20 << nr);
else
- data->alarm_mask |= 0x20;
+ data->alarm_mask |= (0x20 << nr);
data->beep_mask &= data->alarm_mask;
gl518_write_value(client, GL518_REG_ALARM, data->beep_mask);
@@ -286,28 +292,32 @@ static ssize_t set_fan_min1(struct device *dev, struct device_attribute *attr, c
return count;
}
-static ssize_t set_fan_min2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct gl518_data *data = i2c_get_clientdata(client);
+ int nr = to_sensor_dev_attr(attr)->index;
int regvalue;
unsigned long val = simple_strtoul(buf, NULL, 10);
- mutex_lock(&data->update_lock);
- regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT);
- data->fan_min[1] = FAN_TO_REG(val,
- DIV_FROM_REG(data->fan_div[1]));
- regvalue = (regvalue & 0xff00) | data->fan_min[1];
- gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue);
-
- data->beep_mask = gl518_read_value(client, GL518_REG_ALARM);
- if (data->fan_min[1] == 0)
- data->alarm_mask &= ~0x40;
- else
- data->alarm_mask |= 0x40;
- data->beep_mask &= data->alarm_mask;
- gl518_write_value(client, GL518_REG_ALARM, data->beep_mask);
+ switch (val) {
+ case 1: val = 0; break;
+ case 2: val = 1; break;
+ case 4: val = 2; break;
+ case 8: val = 3; break;
+ default:
+ dev_err(dev, "Invalid fan clock divider %lu, choose one "
+ "of 1, 2, 4 or 8\n", val);
+ return -EINVAL;
+ }
+ mutex_lock(&data->update_lock);
+ regvalue = gl518_read_value(client, GL518_REG_MISC);
+ data->fan_div[nr] = val;
+ regvalue = (regvalue & ~(0xc0 >> (2 * nr)))
+ | (data->fan_div[nr] << (6 - 2 * nr));
+ gl518_write_value(client, GL518_REG_MISC, regvalue);
mutex_unlock(&data->update_lock);
return count;
}
@@ -317,12 +327,16 @@ static DEVICE_ATTR(temp1_max, S_IWUSR|S_IRUGO, show_temp_max1, set_temp_max1);
static DEVICE_ATTR(temp1_max_hyst, S_IWUSR|S_IRUGO,
show_temp_hyst1, set_temp_hyst1);
static DEVICE_ATTR(fan1_auto, S_IWUSR|S_IRUGO, show_fan_auto1, set_fan_auto1);
-static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL);
-static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL);
-static DEVICE_ATTR(fan1_min, S_IWUSR|S_IRUGO, show_fan_min1, set_fan_min1);
-static DEVICE_ATTR(fan2_min, S_IWUSR|S_IRUGO, show_fan_min2, set_fan_min2);
-static DEVICE_ATTR(fan1_div, S_IWUSR|S_IRUGO, show_fan_div1, set_fan_div1);
-static DEVICE_ATTR(fan2_div, S_IWUSR|S_IRUGO, show_fan_div2, set_fan_div2);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR|S_IRUGO,
+ show_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR|S_IRUGO,
+ show_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR|S_IRUGO,
+ show_fan_div, set_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR|S_IRUGO,
+ show_fan_div, set_fan_div, 1);
static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL);
static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL);
static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL);
@@ -341,10 +355,62 @@ static DEVICE_ATTR(beep_enable, S_IWUSR|S_IRUGO,
static DEVICE_ATTR(beep_mask, S_IWUSR|S_IRUGO,
show_beep_mask, set_beep_mask);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct gl518_data *data = gl518_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 6);
+
+static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct gl518_data *data = gl518_update_device(dev);
+ return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct gl518_data *data = i2c_get_clientdata(client);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ unsigned long bit;
+
+ bit = simple_strtoul(buf, NULL, 10);
+ if (bit & ~1)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->beep_mask = gl518_read_value(client, GL518_REG_ALARM);
+ if (bit)
+ data->beep_mask |= (1 << bitnr);
+ else
+ data->beep_mask &= ~(1 << bitnr);
+ gl518_write_value(client, GL518_REG_ALARM, data->beep_mask);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 1);
+static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 2);
+static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 3);
+static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 4);
+static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 5);
+static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 6);
+
static struct attribute *gl518_attributes[] = {
- &dev_attr_in0_input.attr,
- &dev_attr_in1_input.attr,
- &dev_attr_in2_input.attr,
&dev_attr_in3_input.attr,
&dev_attr_in0_min.attr,
&dev_attr_in1_min.attr,
@@ -354,18 +420,32 @@ static struct attribute *gl518_attributes[] = {
&dev_attr_in1_max.attr,
&dev_attr_in2_max.attr,
&dev_attr_in3_max.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in0_beep.dev_attr.attr,
+ &sensor_dev_attr_in1_beep.dev_attr.attr,
+ &sensor_dev_attr_in2_beep.dev_attr.attr,
+ &sensor_dev_attr_in3_beep.dev_attr.attr,
&dev_attr_fan1_auto.attr,
- &dev_attr_fan1_input.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan1_div.attr,
- &dev_attr_fan2_div.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan1_beep.dev_attr.attr,
+ &sensor_dev_attr_fan2_beep.dev_attr.attr,
&dev_attr_temp1_input.attr,
&dev_attr_temp1_max.attr,
&dev_attr_temp1_max_hyst.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_beep.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_beep_enable.attr,
@@ -377,6 +457,17 @@ static const struct attribute_group gl518_group = {
.attrs = gl518_attributes,
};
+static struct attribute *gl518_attributes_r80[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+ NULL
+};
+
+static const struct attribute_group gl518_group_r80 = {
+ .attrs = gl518_attributes_r80,
+};
+
/*
* Real code
*/
@@ -391,7 +482,7 @@ static int gl518_attach_adapter(struct i2c_adapter *adapter)
static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i;
- struct i2c_client *new_client;
+ struct i2c_client *client;
struct gl518_data *data;
int err = 0;
@@ -408,25 +499,24 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
+ client = &data->client;
+ i2c_set_clientdata(client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &gl518_driver;
- new_client->flags = 0;
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &gl518_driver;
/* Now, we do the remaining detection. */
if (kind < 0) {
- if ((gl518_read_value(new_client, GL518_REG_CHIP_ID) != 0x80)
- || (gl518_read_value(new_client, GL518_REG_CONF) & 0x80))
+ if ((gl518_read_value(client, GL518_REG_CHIP_ID) != 0x80)
+ || (gl518_read_value(client, GL518_REG_CONF) & 0x80))
goto exit_free;
}
/* Determine the chip type. */
if (kind <= 0) {
- i = gl518_read_value(new_client, GL518_REG_REVISION);
+ i = gl518_read_value(client, GL518_REG_REVISION);
if (i == 0x00) {
kind = gl518sm_r00;
} else if (i == 0x80) {
@@ -442,25 +532,27 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Fill in the remaining client fields */
- strlcpy(new_client->name, "gl518sm", I2C_NAME_SIZE);
+ strlcpy(client->name, "gl518sm", I2C_NAME_SIZE);
data->type = kind;
- data->valid = 0;
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
+ if ((err = i2c_attach_client(client)))
goto exit_free;
/* Initialize the GL518SM chip */
data->alarm_mask = 0xff;
- data->voltage_in[0]=data->voltage_in[1]=data->voltage_in[2]=0;
- gl518_init_client((struct i2c_client *) new_client);
+ gl518_init_client(client);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &gl518_group)))
+ if ((err = sysfs_create_group(&client->dev.kobj, &gl518_group)))
goto exit_detach;
+ if (data->type == gl518sm_r80)
+ if ((err = sysfs_create_group(&client->dev.kobj,
+ &gl518_group_r80)))
+ goto exit_remove_files;
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
@@ -469,9 +561,11 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &gl518_group);
+ sysfs_remove_group(&client->dev.kobj, &gl518_group);
+ if (data->type == gl518sm_r80)
+ sysfs_remove_group(&client->dev.kobj, &gl518_group_r80);
exit_detach:
- i2c_detach_client(new_client);
+ i2c_detach_client(client);
exit_free:
kfree(data);
exit:
@@ -504,6 +598,8 @@ static int gl518_detach_client(struct i2c_client *client)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &gl518_group);
+ if (data->type == gl518sm_r80)
+ sysfs_remove_group(&client->dev.kobj, &gl518_group_r80);
if ((err = i2c_detach_client(client)))
return err;
@@ -512,9 +608,9 @@ static int gl518_detach_client(struct i2c_client *client)
return 0;
}
-/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
+/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
GL518 uses a high-byte first convention, which is exactly opposite to
- the usual practice. */
+ the SMBus standard. */
static int gl518_read_value(struct i2c_client *client, u8 reg)
{
if ((reg >= 0x07) && (reg <= 0x0c))
@@ -523,9 +619,6 @@ static int gl518_read_value(struct i2c_client *client, u8 reg)
return i2c_smbus_read_byte_data(client, reg);
}
-/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
- GL518 uses a high-byte first convention, which is exactly opposite to
- the usual practice. */
static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value)
{
if ((reg >= 0x07) && (reg <= 0x0c))
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index 2d39d8fc238..03ecdc33476 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -27,6 +27,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
@@ -43,9 +44,9 @@ static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(gl520sm);
-/* Many GL520 constants specified below
+/* Many GL520 constants specified below
One of the inputs can be configured as either temp or voltage.
-That's why _TEMP2 and _IN4 access the same register
+That's why _TEMP2 and _IN4 access the same register
*/
/* The GL520 registers */
@@ -56,37 +57,14 @@ That's why _TEMP2 and _IN4 access the same register
#define GL520_REG_VID_INPUT 0x02
-#define GL520_REG_IN0_INPUT 0x15
-#define GL520_REG_IN0_LIMIT 0x0c
-#define GL520_REG_IN0_MIN GL520_REG_IN0_LIMIT
-#define GL520_REG_IN0_MAX GL520_REG_IN0_LIMIT
+static const u8 GL520_REG_IN_INPUT[] = { 0x15, 0x14, 0x13, 0x0d, 0x0e };
+static const u8 GL520_REG_IN_LIMIT[] = { 0x0c, 0x09, 0x0a, 0x0b };
+static const u8 GL520_REG_IN_MIN[] = { 0x0c, 0x09, 0x0a, 0x0b, 0x18 };
+static const u8 GL520_REG_IN_MAX[] = { 0x0c, 0x09, 0x0a, 0x0b, 0x17 };
-#define GL520_REG_IN1_INPUT 0x14
-#define GL520_REG_IN1_LIMIT 0x09
-#define GL520_REG_IN1_MIN GL520_REG_IN1_LIMIT
-#define GL520_REG_IN1_MAX GL520_REG_IN1_LIMIT
-
-#define GL520_REG_IN2_INPUT 0x13
-#define GL520_REG_IN2_LIMIT 0x0a
-#define GL520_REG_IN2_MIN GL520_REG_IN2_LIMIT
-#define GL520_REG_IN2_MAX GL520_REG_IN2_LIMIT
-
-#define GL520_REG_IN3_INPUT 0x0d
-#define GL520_REG_IN3_LIMIT 0x0b
-#define GL520_REG_IN3_MIN GL520_REG_IN3_LIMIT
-#define GL520_REG_IN3_MAX GL520_REG_IN3_LIMIT
-
-#define GL520_REG_IN4_INPUT 0x0e
-#define GL520_REG_IN4_MAX 0x17
-#define GL520_REG_IN4_MIN 0x18
-
-#define GL520_REG_TEMP1_INPUT 0x04
-#define GL520_REG_TEMP1_MAX 0x05
-#define GL520_REG_TEMP1_MAX_HYST 0x06
-
-#define GL520_REG_TEMP2_INPUT 0x0e
-#define GL520_REG_TEMP2_MAX 0x17
-#define GL520_REG_TEMP2_MAX_HYST 0x18
+static const u8 GL520_REG_TEMP_INPUT[] = { 0x04, 0x0e };
+static const u8 GL520_REG_TEMP_MAX[] = { 0x05, 0x17 };
+static const u8 GL520_REG_TEMP_MAX_HYST[] = { 0x06, 0x18 };
#define GL520_REG_FAN_INPUT 0x07
#define GL520_REG_FAN_MIN 0x08
@@ -114,7 +92,6 @@ static struct i2c_driver gl520_driver = {
.driver = {
.name = "gl520sm",
},
- .id = I2C_DRIVERID_GL520,
.attach_adapter = gl520_attach_adapter,
.detach_client = gl520_detach_client,
};
@@ -150,93 +127,13 @@ struct gl520_data {
* Sysfs stuff
*/
-#define sysfs_r(type, n, item, reg) \
-static ssize_t get_##type##item (struct gl520_data *, char *, int); \
-static ssize_t get_##type##n##item (struct device *, struct device_attribute *attr, char *); \
-static ssize_t get_##type##n##item (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct gl520_data *data = gl520_update_device(dev); \
- return get_##type##item(data, buf, (n)); \
-}
-
-#define sysfs_w(type, n, item, reg) \
-static ssize_t set_##type##item (struct i2c_client *, struct gl520_data *, const char *, size_t, int, int); \
-static ssize_t set_##type##n##item (struct device *, struct device_attribute *attr, const char *, size_t); \
-static ssize_t set_##type##n##item (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct gl520_data *data = i2c_get_clientdata(client); \
- return set_##type##item(client, data, buf, count, (n), reg); \
-}
-
-#define sysfs_rw_n(type, n, item, reg) \
-sysfs_r(type, n, item, reg) \
-sysfs_w(type, n, item, reg) \
-static DEVICE_ATTR(type##n##item, S_IRUGO | S_IWUSR, get_##type##n##item, set_##type##n##item);
-
-#define sysfs_ro_n(type, n, item, reg) \
-sysfs_r(type, n, item, reg) \
-static DEVICE_ATTR(type##n##item, S_IRUGO, get_##type##n##item, NULL);
-
-#define sysfs_rw(type, item, reg) \
-sysfs_r(type, 0, item, reg) \
-sysfs_w(type, 0, item, reg) \
-static DEVICE_ATTR(type##item, S_IRUGO | S_IWUSR, get_##type##0##item, set_##type##0##item);
-
-#define sysfs_ro(type, item, reg) \
-sysfs_r(type, 0, item, reg) \
-static DEVICE_ATTR(type##item, S_IRUGO, get_##type##0##item, NULL);
-
-
-#define sysfs_vid(n) \
-sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT)
-
-#define sysfs_in(n) \
-sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \
-sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \
-sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \
-
-#define sysfs_fan(n) \
-sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \
-sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \
-sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV)
-
-#define sysfs_fan_off(n) \
-sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \
-
-#define sysfs_temp(n) \
-sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \
-sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \
-sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST)
-
-#define sysfs_alarms() \
-sysfs_ro(alarms, , GL520_REG_ALARMS) \
-sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \
-sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK)
-
-
-sysfs_vid(0)
-
-sysfs_in(0)
-sysfs_in(1)
-sysfs_in(2)
-sysfs_in(3)
-sysfs_in(4)
-
-sysfs_fan(1)
-sysfs_fan(2)
-sysfs_fan_off(1)
-
-sysfs_temp(1)
-sysfs_temp(2)
-
-sysfs_alarms()
-
-
-static ssize_t get_cpu_vid(struct gl520_data *data, char *buf, int n)
+static ssize_t get_cpu_vid(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct gl520_data *data = gl520_update_device(dev);
return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL);
#define VDD_FROM_REG(val) (((val)*95+2)/4)
#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255))
@@ -244,8 +141,11 @@ static ssize_t get_cpu_vid(struct gl520_data *data, char *buf, int n)
#define IN_FROM_REG(val) ((val)*19)
#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255))
-static ssize_t get_in_input(struct gl520_data *data, char *buf, int n)
+static ssize_t get_in_input(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int n = to_sensor_dev_attr(attr)->index;
+ struct gl520_data *data = gl520_update_device(dev);
u8 r = data->in_input[n];
if (n == 0)
@@ -254,8 +154,11 @@ static ssize_t get_in_input(struct gl520_data *data, char *buf, int n)
return sprintf(buf, "%d\n", IN_FROM_REG(r));
}
-static ssize_t get_in_min(struct gl520_data *data, char *buf, int n)
+static ssize_t get_in_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int n = to_sensor_dev_attr(attr)->index;
+ struct gl520_data *data = gl520_update_device(dev);
u8 r = data->in_min[n];
if (n == 0)
@@ -264,8 +167,11 @@ static ssize_t get_in_min(struct gl520_data *data, char *buf, int n)
return sprintf(buf, "%d\n", IN_FROM_REG(r));
}
-static ssize_t get_in_max(struct gl520_data *data, char *buf, int n)
+static ssize_t get_in_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int n = to_sensor_dev_attr(attr)->index;
+ struct gl520_data *data = gl520_update_device(dev);
u8 r = data->in_max[n];
if (n == 0)
@@ -274,8 +180,12 @@ static ssize_t get_in_max(struct gl520_data *data, char *buf, int n)
return sprintf(buf, "%d\n", IN_FROM_REG(r));
}
-static ssize_t set_in_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct gl520_data *data = i2c_get_clientdata(client);
+ int n = to_sensor_dev_attr(attr)->index;
long v = simple_strtol(buf, NULL, 10);
u8 r;
@@ -289,16 +199,22 @@ static ssize_t set_in_min(struct i2c_client *client, struct gl520_data *data, co
data->in_min[n] = r;
if (n < 4)
- gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r);
+ gl520_write_value(client, GL520_REG_IN_MIN[n],
+ (gl520_read_value(client, GL520_REG_IN_MIN[n])
+ & ~0xff) | r);
else
- gl520_write_value(client, reg, r);
+ gl520_write_value(client, GL520_REG_IN_MIN[n], r);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_in_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct gl520_data *data = i2c_get_clientdata(client);
+ int n = to_sensor_dev_attr(attr)->index;
long v = simple_strtol(buf, NULL, 10);
u8 r;
@@ -312,57 +228,109 @@ static ssize_t set_in_max(struct i2c_client *client, struct gl520_data *data, co
data->in_max[n] = r;
if (n < 4)
- gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8));
+ gl520_write_value(client, GL520_REG_IN_MAX[n],
+ (gl520_read_value(client, GL520_REG_IN_MAX[n])
+ & ~0xff00) | (r << 8));
else
- gl520_write_value(client, reg, r);
+ gl520_write_value(client, GL520_REG_IN_MAX[n], r);
mutex_unlock(&data->update_lock);
return count;
}
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, get_in_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, get_in_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, get_in_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, get_in_input, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, get_in_input, NULL, 4);
+static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
+ get_in_min, set_in_min, 0);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR,
+ get_in_min, set_in_min, 1);
+static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR,
+ get_in_min, set_in_min, 2);
+static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO | S_IWUSR,
+ get_in_min, set_in_min, 3);
+static SENSOR_DEVICE_ATTR(in4_min, S_IRUGO | S_IWUSR,
+ get_in_min, set_in_min, 4);
+static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
+ get_in_max, set_in_max, 0);
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR,
+ get_in_max, set_in_max, 1);
+static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR,
+ get_in_max, set_in_max, 2);
+static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO | S_IWUSR,
+ get_in_max, set_in_max, 3);
+static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR,
+ get_in_max, set_in_max, 4);
+
#define DIV_FROM_REG(val) (1 << (val))
#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val) << (div))))
#define FAN_TO_REG(val,div) ((val)<=0?0:SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255));
-static ssize_t get_fan_input(struct gl520_data *data, char *buf, int n)
+static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n - 1], data->fan_div[n - 1]));
+ int n = to_sensor_dev_attr(attr)->index;
+ struct gl520_data *data = gl520_update_device(dev);
+
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n],
+ data->fan_div[n]));
}
-static ssize_t get_fan_min(struct gl520_data *data, char *buf, int n)
+static ssize_t get_fan_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n - 1], data->fan_div[n - 1]));
+ int n = to_sensor_dev_attr(attr)->index;
+ struct gl520_data *data = gl520_update_device(dev);
+
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n],
+ data->fan_div[n]));
}
-static ssize_t get_fan_div(struct gl520_data *data, char *buf, int n)
+static ssize_t get_fan_div(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n - 1]));
+ int n = to_sensor_dev_attr(attr)->index;
+ struct gl520_data *data = gl520_update_device(dev);
+
+ return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n]));
}
-static ssize_t get_fan_off(struct gl520_data *data, char *buf, int n)
+static ssize_t get_fan_off(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct gl520_data *data = gl520_update_device(dev);
return sprintf(buf, "%d\n", data->fan_off);
}
-static ssize_t set_fan_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct gl520_data *data = i2c_get_clientdata(client);
+ int n = to_sensor_dev_attr(attr)->index;
unsigned long v = simple_strtoul(buf, NULL, 10);
u8 r;
mutex_lock(&data->update_lock);
- r = FAN_TO_REG(v, data->fan_div[n - 1]);
- data->fan_min[n - 1] = r;
+ r = FAN_TO_REG(v, data->fan_div[n]);
+ data->fan_min[n] = r;
- if (n == 1)
- gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8));
+ if (n == 0)
+ gl520_write_value(client, GL520_REG_FAN_MIN,
+ (gl520_read_value(client, GL520_REG_FAN_MIN)
+ & ~0xff00) | (r << 8));
else
- gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r);
+ gl520_write_value(client, GL520_REG_FAN_MIN,
+ (gl520_read_value(client, GL520_REG_FAN_MIN)
+ & ~0xff) | r);
data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
- if (data->fan_min[n - 1] == 0)
- data->alarm_mask &= (n == 1) ? ~0x20 : ~0x40;
+ if (data->fan_min[n] == 0)
+ data->alarm_mask &= (n == 0) ? ~0x20 : ~0x40;
else
- data->alarm_mask |= (n == 1) ? 0x20 : 0x40;
+ data->alarm_mask |= (n == 0) ? 0x20 : 0x40;
data->beep_mask &= data->alarm_mask;
gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
@@ -370,8 +338,12 @@ static ssize_t set_fan_min(struct i2c_client *client, struct gl520_data *data, c
return count;
}
-static ssize_t set_fan_div(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct gl520_data *data = i2c_get_clientdata(client);
+ int n = to_sensor_dev_attr(attr)->index;
unsigned long v = simple_strtoul(buf, NULL, 10);
u8 r;
@@ -386,133 +358,282 @@ static ssize_t set_fan_div(struct i2c_client *client, struct gl520_data *data, c
}
mutex_lock(&data->update_lock);
- data->fan_div[n - 1] = r;
+ data->fan_div[n] = r;
- if (n == 1)
- gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xc0) | (r << 6));
+ if (n == 0)
+ gl520_write_value(client, GL520_REG_FAN_DIV,
+ (gl520_read_value(client, GL520_REG_FAN_DIV)
+ & ~0xc0) | (r << 6));
else
- gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x30) | (r << 4));
+ gl520_write_value(client, GL520_REG_FAN_DIV,
+ (gl520_read_value(client, GL520_REG_FAN_DIV)
+ & ~0x30) | (r << 4));
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_fan_off(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+static ssize_t set_fan_off(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct gl520_data *data = i2c_get_clientdata(client);
u8 r = simple_strtoul(buf, NULL, 10)?1:0;
mutex_lock(&data->update_lock);
data->fan_off = r;
- gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x0c) | (r << 2));
+ gl520_write_value(client, GL520_REG_FAN_OFF,
+ (gl520_read_value(client, GL520_REG_FAN_OFF)
+ & ~0x0c) | (r << 2));
mutex_unlock(&data->update_lock);
return count;
}
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
+ get_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
+ get_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
+ get_fan_div, set_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
+ get_fan_div, set_fan_div, 1);
+static DEVICE_ATTR(fan1_off, S_IRUGO | S_IWUSR,
+ get_fan_off, set_fan_off);
+
#define TEMP_FROM_REG(val) (((val) - 130) * 1000)
#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-500:(val)+500) / 1000)+130),0,255))
-static ssize_t get_temp_input(struct gl520_data *data, char *buf, int n)
+static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n - 1]));
+ int n = to_sensor_dev_attr(attr)->index;
+ struct gl520_data *data = gl520_update_device(dev);
+
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n]));
}
-static ssize_t get_temp_max(struct gl520_data *data, char *buf, int n)
+static ssize_t get_temp_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n - 1]));
+ int n = to_sensor_dev_attr(attr)->index;
+ struct gl520_data *data = gl520_update_device(dev);
+
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n]));
}
-static ssize_t get_temp_max_hyst(struct gl520_data *data, char *buf, int n)
+static ssize_t get_temp_max_hyst(struct device *dev, struct device_attribute
+ *attr, char *buf)
{
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n - 1]));
+ int n = to_sensor_dev_attr(attr)->index;
+ struct gl520_data *data = gl520_update_device(dev);
+
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n]));
}
-static ssize_t set_temp_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct gl520_data *data = i2c_get_clientdata(client);
+ int n = to_sensor_dev_attr(attr)->index;
long v = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
- data->temp_max[n - 1] = TEMP_TO_REG(v);
- gl520_write_value(client, reg, data->temp_max[n - 1]);
+ data->temp_max[n] = TEMP_TO_REG(v);
+ gl520_write_value(client, GL520_REG_TEMP_MAX[n], data->temp_max[n]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_temp_max_hyst(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+static ssize_t set_temp_max_hyst(struct device *dev, struct device_attribute
+ *attr, const char *buf, size_t count)
{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct gl520_data *data = i2c_get_clientdata(client);
+ int n = to_sensor_dev_attr(attr)->index;
long v = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
- data->temp_max_hyst[n - 1] = TEMP_TO_REG(v);
- gl520_write_value(client, reg, data->temp_max_hyst[n - 1]);
+ data->temp_max_hyst[n] = TEMP_TO_REG(v);
+ gl520_write_value(client, GL520_REG_TEMP_MAX_HYST[n],
+ data->temp_max_hyst[n]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t get_alarms(struct gl520_data *data, char *buf, int n)
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_temp_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_temp_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+ get_temp_max, set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR,
+ get_temp_max, set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
+ get_temp_max_hyst, set_temp_max_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR,
+ get_temp_max_hyst, set_temp_max_hyst, 1);
+
+static ssize_t get_alarms(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct gl520_data *data = gl520_update_device(dev);
return sprintf(buf, "%d\n", data->alarms);
}
-static ssize_t get_beep_enable(struct gl520_data *data, char *buf, int n)
+static ssize_t get_beep_enable(struct device *dev, struct device_attribute
+ *attr, char *buf)
{
+ struct gl520_data *data = gl520_update_device(dev);
return sprintf(buf, "%d\n", data->beep_enable);
}
-static ssize_t get_beep_mask(struct gl520_data *data, char *buf, int n)
+static ssize_t get_beep_mask(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ struct gl520_data *data = gl520_update_device(dev);
return sprintf(buf, "%d\n", data->beep_mask);
}
-static ssize_t set_beep_enable(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+static ssize_t set_beep_enable(struct device *dev, struct device_attribute
+ *attr, const char *buf, size_t count)
{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct gl520_data *data = i2c_get_clientdata(client);
u8 r = simple_strtoul(buf, NULL, 10)?0:1;
mutex_lock(&data->update_lock);
data->beep_enable = !r;
- gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x04) | (r << 2));
+ gl520_write_value(client, GL520_REG_BEEP_ENABLE,
+ (gl520_read_value(client, GL520_REG_BEEP_ENABLE)
+ & ~0x04) | (r << 2));
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_beep_mask(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg)
+static ssize_t set_beep_mask(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct gl520_data *data = i2c_get_clientdata(client);
u8 r = simple_strtoul(buf, NULL, 10);
-
+
mutex_lock(&data->update_lock);
r &= data->alarm_mask;
data->beep_mask = r;
- gl520_write_value(client, reg, r);
+ gl520_write_value(client, GL520_REG_BEEP_MASK, r);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
+static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
+ get_beep_enable, set_beep_enable);
+static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
+ get_beep_mask, set_beep_mask);
+
+static ssize_t get_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bit_nr = to_sensor_dev_attr(attr)->index;
+ struct gl520_data *data = gl520_update_device(dev);
+
+ return sprintf(buf, "%d\n", (data->alarms >> bit_nr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, get_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, get_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, get_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, get_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, get_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, get_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, get_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, get_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, get_alarm, NULL, 7);
+
+static ssize_t get_beep(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct gl520_data *data = gl520_update_device(dev);
+
+ return sprintf(buf, "%d\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct gl520_data *data = i2c_get_clientdata(client);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ unsigned long bit;
+
+ bit = simple_strtoul(buf, NULL, 10);
+ if (bit & ~1)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
+ if (bit)
+ data->beep_mask |= (1 << bitnr);
+ else
+ data->beep_mask &= ~(1 << bitnr);
+ gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
mutex_unlock(&data->update_lock);
return count;
}
+static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 0);
+static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 1);
+static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 2);
+static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 3);
+static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 4);
+static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 5);
+static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 6);
+static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 7);
+static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 7);
+
static struct attribute *gl520_attributes[] = {
&dev_attr_cpu0_vid.attr,
- &dev_attr_in0_input.attr,
- &dev_attr_in0_min.attr,
- &dev_attr_in0_max.attr,
- &dev_attr_in1_input.attr,
- &dev_attr_in1_min.attr,
- &dev_attr_in1_max.attr,
- &dev_attr_in2_input.attr,
- &dev_attr_in2_min.attr,
- &dev_attr_in2_max.attr,
- &dev_attr_in3_input.attr,
- &dev_attr_in3_min.attr,
- &dev_attr_in3_max.attr,
-
- &dev_attr_fan1_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan1_div.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in0_beep.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_beep.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_beep.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_beep.dev_attr.attr,
+
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan1_beep.dev_attr.attr,
&dev_attr_fan1_off.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan2_div.attr,
-
- &dev_attr_temp1_input.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp1_max_hyst.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_beep.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_beep.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_beep_enable.attr,
@@ -525,13 +646,17 @@ static const struct attribute_group gl520_group = {
};
static struct attribute *gl520_attributes_opt[] = {
- &dev_attr_in4_input.attr,
- &dev_attr_in4_min.attr,
- &dev_attr_in4_max.attr,
-
- &dev_attr_temp2_input.attr,
- &dev_attr_temp2_max.attr,
- &dev_attr_temp2_max_hyst.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_beep.dev_attr.attr,
+
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_beep.dev_attr.attr,
NULL
};
@@ -553,7 +678,7 @@ static int gl520_attach_adapter(struct i2c_adapter *adapter)
static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
{
- struct i2c_client *new_client;
+ struct i2c_client *client;
struct gl520_data *data;
int err = 0;
@@ -570,59 +695,65 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &gl520_driver;
- new_client->flags = 0;
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &gl520_driver;
/* Determine the chip type. */
if (kind < 0) {
- if ((gl520_read_value(new_client, GL520_REG_CHIP_ID) != 0x20) ||
- ((gl520_read_value(new_client, GL520_REG_REVISION) & 0x7f) != 0x00) ||
- ((gl520_read_value(new_client, GL520_REG_CONF) & 0x80) != 0x00)) {
- dev_dbg(&new_client->dev, "Unknown chip type, skipping\n");
+ if ((gl520_read_value(client, GL520_REG_CHIP_ID) != 0x20) ||
+ ((gl520_read_value(client, GL520_REG_REVISION) & 0x7f) != 0x00) ||
+ ((gl520_read_value(client, GL520_REG_CONF) & 0x80) != 0x00)) {
+ dev_dbg(&client->dev, "Unknown chip type, skipping\n");
goto exit_free;
}
}
/* Fill in the remaining client fields */
- strlcpy(new_client->name, "gl520sm", I2C_NAME_SIZE);
- data->valid = 0;
+ strlcpy(client->name, "gl520sm", I2C_NAME_SIZE);
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
+ if ((err = i2c_attach_client(client)))
goto exit_free;
/* Initialize the GL520SM chip */
- gl520_init_client(new_client);
+ gl520_init_client(client);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &gl520_group)))
+ if ((err = sysfs_create_group(&client->dev.kobj, &gl520_group)))
goto exit_detach;
if (data->two_temps) {
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_temp2_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_temp2_max))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_temp2_max_hyst)))
+ if ((err = device_create_file(&client->dev,
+ &sensor_dev_attr_temp2_input.dev_attr))
+ || (err = device_create_file(&client->dev,
+ &sensor_dev_attr_temp2_max.dev_attr))
+ || (err = device_create_file(&client->dev,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr))
+ || (err = device_create_file(&client->dev,
+ &sensor_dev_attr_temp2_alarm.dev_attr))
+ || (err = device_create_file(&client->dev,
+ &sensor_dev_attr_temp2_beep.dev_attr)))
goto exit_remove_files;
} else {
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_in4_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in4_min))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in4_max)))
+ if ((err = device_create_file(&client->dev,
+ &sensor_dev_attr_in4_input.dev_attr))
+ || (err = device_create_file(&client->dev,
+ &sensor_dev_attr_in4_min.dev_attr))
+ || (err = device_create_file(&client->dev,
+ &sensor_dev_attr_in4_max.dev_attr))
+ || (err = device_create_file(&client->dev,
+ &sensor_dev_attr_in4_alarm.dev_attr))
+ || (err = device_create_file(&client->dev,
+ &sensor_dev_attr_in4_beep.dev_attr)))
goto exit_remove_files;
}
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
@@ -631,10 +762,10 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &gl520_group);
- sysfs_remove_group(&new_client->dev.kobj, &gl520_group_opt);
+ sysfs_remove_group(&client->dev.kobj, &gl520_group);
+ sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
exit_detach:
- i2c_detach_client(new_client);
+ i2c_detach_client(client);
exit_free:
kfree(data);
exit:
@@ -697,7 +828,7 @@ static int gl520_detach_client(struct i2c_client *client)
}
-/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
+/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
GL520 uses a high-byte first convention */
static int gl520_read_value(struct i2c_client *client, u8 reg)
{
@@ -720,7 +851,7 @@ static struct gl520_data *gl520_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct gl520_data *data = i2c_get_clientdata(client);
- int val;
+ int val, i;
mutex_lock(&data->update_lock);
@@ -732,18 +863,13 @@ static struct gl520_data *gl520_update_device(struct device *dev)
data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
data->vid = gl520_read_value(client, GL520_REG_VID_INPUT) & 0x1f;
- val = gl520_read_value(client, GL520_REG_IN0_LIMIT);
- data->in_min[0] = val & 0xff;
- data->in_max[0] = (val >> 8) & 0xff;
- val = gl520_read_value(client, GL520_REG_IN1_LIMIT);
- data->in_min[1] = val & 0xff;
- data->in_max[1] = (val >> 8) & 0xff;
- val = gl520_read_value(client, GL520_REG_IN2_LIMIT);
- data->in_min[2] = val & 0xff;
- data->in_max[2] = (val >> 8) & 0xff;
- val = gl520_read_value(client, GL520_REG_IN3_LIMIT);
- data->in_min[3] = val & 0xff;
- data->in_max[3] = (val >> 8) & 0xff;
+ for (i = 0; i < 4; i++) {
+ data->in_input[i] = gl520_read_value(client,
+ GL520_REG_IN_INPUT[i]);
+ val = gl520_read_value(client, GL520_REG_IN_LIMIT[i]);
+ data->in_min[i] = val & 0xff;
+ data->in_max[i] = (val >> 8) & 0xff;
+ }
val = gl520_read_value(client, GL520_REG_FAN_INPUT);
data->fan_input[0] = (val >> 8) & 0xff;
@@ -753,9 +879,12 @@ static struct gl520_data *gl520_update_device(struct device *dev)
data->fan_min[0] = (val >> 8) & 0xff;
data->fan_min[1] = val & 0xff;
- data->temp_input[0] = gl520_read_value(client, GL520_REG_TEMP1_INPUT);
- data->temp_max[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX);
- data->temp_max_hyst[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX_HYST);
+ data->temp_input[0] = gl520_read_value(client,
+ GL520_REG_TEMP_INPUT[0]);
+ data->temp_max[0] = gl520_read_value(client,
+ GL520_REG_TEMP_MAX[0]);
+ data->temp_max_hyst[0] = gl520_read_value(client,
+ GL520_REG_TEMP_MAX_HYST[0]);
val = gl520_read_value(client, GL520_REG_FAN_DIV);
data->fan_div[0] = (val >> 6) & 0x03;
@@ -767,20 +896,21 @@ static struct gl520_data *gl520_update_device(struct device *dev)
val = gl520_read_value(client, GL520_REG_CONF);
data->beep_enable = !((val >> 2) & 1);
- data->in_input[0] = gl520_read_value(client, GL520_REG_IN0_INPUT);
- data->in_input[1] = gl520_read_value(client, GL520_REG_IN1_INPUT);
- data->in_input[2] = gl520_read_value(client, GL520_REG_IN2_INPUT);
- data->in_input[3] = gl520_read_value(client, GL520_REG_IN3_INPUT);
-
/* Temp1 and Vin4 are the same input */
if (data->two_temps) {
- data->temp_input[1] = gl520_read_value(client, GL520_REG_TEMP2_INPUT);
- data->temp_max[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX);
- data->temp_max_hyst[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX_HYST);
+ data->temp_input[1] = gl520_read_value(client,
+ GL520_REG_TEMP_INPUT[1]);
+ data->temp_max[1] = gl520_read_value(client,
+ GL520_REG_TEMP_MAX[1]);
+ data->temp_max_hyst[1] = gl520_read_value(client,
+ GL520_REG_TEMP_MAX_HYST[1]);
} else {
- data->in_input[4] = gl520_read_value(client, GL520_REG_IN4_INPUT);
- data->in_min[4] = gl520_read_value(client, GL520_REG_IN4_MIN);
- data->in_max[4] = gl520_read_value(client, GL520_REG_IN4_MAX);
+ data->in_input[4] = gl520_read_value(client,
+ GL520_REG_IN_INPUT[4]);
+ data->in_min[4] = gl520_read_value(client,
+ GL520_REG_IN_MIN[4]);
+ data->in_max[4] = gl520_read_value(client,
+ GL520_REG_IN_MAX[4]);
}
data->last_updated = jiffies;
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index ad6c8a31990..e12c132ff83 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -17,8 +17,8 @@
IT8726F Super I/O chip w/LPC interface
Sis950 A clone of the IT8705F
- Copyright (C) 2001 Chris Gauthron <chrisg@0-in.com>
- Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2001 Chris Gauthron
+ Copyright (C) 2005-2007 Jean Delvare <khali@linux-fr.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -52,6 +52,10 @@
enum chips { it87, it8712, it8716, it8718 };
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
static struct platform_device *pdev;
#define REG 0x2e /* The register to read/write */
@@ -776,6 +780,30 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct it87_data *data = it87_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 18);
+
static ssize_t
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -837,6 +865,14 @@ static struct attribute *it87_attributes[] = {
&sensor_dev_attr_in5_max.dev_attr.attr,
&sensor_dev_attr_in6_max.dev_attr.attr,
&sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
@@ -850,6 +886,9 @@ static struct attribute *it87_attributes[] = {
&sensor_dev_attr_temp1_type.dev_attr.attr,
&sensor_dev_attr_temp2_type.dev_attr.attr,
&sensor_dev_attr_temp3_type.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_name.attr,
@@ -882,12 +921,21 @@ static struct attribute *it87_attributes_opt[] = {
&sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan3_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan4_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan5_alarm.dev_attr.attr,
+
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm2.dev_attr.attr,
&sensor_dev_attr_pwm3.dev_attr.attr,
+ &dev_attr_pwm1_freq.attr,
+ &dev_attr_pwm2_freq.attr,
+ &dev_attr_pwm3_freq.attr,
&dev_attr_vrm.attr,
&dev_attr_cpu0_vid.attr,
@@ -906,7 +954,7 @@ static int __init it87_find(unsigned short *address,
u16 chip_type;
superio_enter();
- chip_type = superio_inw(DEVID);
+ chip_type = force_id ? force_id : superio_inw(DEVID);
switch (chip_type) {
case IT8705F_DEVID:
@@ -1027,35 +1075,45 @@ static int __devinit it87_probe(struct platform_device *pdev)
if ((err = device_create_file(dev,
&sensor_dev_attr_fan1_input16.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_fan1_min16.dev_attr)))
+ &sensor_dev_attr_fan1_min16.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan1_alarm.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 1)) {
if ((err = device_create_file(dev,
&sensor_dev_attr_fan2_input16.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_fan2_min16.dev_attr)))
+ &sensor_dev_attr_fan2_min16.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan2_alarm.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 2)) {
if ((err = device_create_file(dev,
&sensor_dev_attr_fan3_input16.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_fan3_min16.dev_attr)))
+ &sensor_dev_attr_fan3_min16.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan3_alarm.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 3)) {
if ((err = device_create_file(dev,
&sensor_dev_attr_fan4_input16.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_fan4_min16.dev_attr)))
+ &sensor_dev_attr_fan4_min16.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan4_alarm.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 4)) {
if ((err = device_create_file(dev,
&sensor_dev_attr_fan5_input16.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_fan5_min16.dev_attr)))
+ &sensor_dev_attr_fan5_min16.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan5_alarm.dev_attr)))
goto ERROR4;
}
} else {
@@ -1066,7 +1124,9 @@ static int __devinit it87_probe(struct platform_device *pdev)
|| (err = device_create_file(dev,
&sensor_dev_attr_fan1_min.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_fan1_div.dev_attr)))
+ &sensor_dev_attr_fan1_div.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan1_alarm.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 1)) {
@@ -1075,7 +1135,9 @@ static int __devinit it87_probe(struct platform_device *pdev)
|| (err = device_create_file(dev,
&sensor_dev_attr_fan2_min.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_fan2_div.dev_attr)))
+ &sensor_dev_attr_fan2_div.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan2_alarm.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 2)) {
@@ -1084,7 +1146,9 @@ static int __devinit it87_probe(struct platform_device *pdev)
|| (err = device_create_file(dev,
&sensor_dev_attr_fan3_min.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_fan3_div.dev_attr)))
+ &sensor_dev_attr_fan3_div.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan3_alarm.dev_attr)))
goto ERROR4;
}
}
@@ -1488,7 +1552,7 @@ static void __exit sm_it87_exit(void)
}
-MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>, "
+MODULE_AUTHOR("Chris Gauthron, "
"Jean Delvare <khali@linux-fr.org>");
MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8726F, SiS950 driver");
module_param(update_vbat, bool, 0);
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 37a8cc032ff..e5c35a355a5 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -74,7 +74,6 @@ static struct i2c_driver lm75_driver = {
.driver = {
.name = "lm75",
},
- .id = I2C_DRIVERID_LM75,
.attach_adapter = lm75_attach_adapter,
.detach_client = lm75_detach_client,
};
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index cee5c2e8cfa..459b70ad6be 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -31,6 +31,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
@@ -113,7 +114,6 @@ show(temp_input);
show(temp_crit);
show(temp_min);
show(temp_max);
-show(alarms);
/* read routines for hysteresis values */
static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf)
@@ -186,6 +186,14 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
return count;
}
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct lm77_data *data = lm77_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
static DEVICE_ATTR(temp1_input, S_IRUGO,
show_temp_input, NULL);
static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
@@ -202,8 +210,9 @@ static DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
static DEVICE_ATTR(temp1_max_hyst, S_IRUGO,
show_temp_max_hyst, NULL);
-static DEVICE_ATTR(alarms, S_IRUGO,
- show_alarms, NULL);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
static int lm77_attach_adapter(struct i2c_adapter *adapter)
{
@@ -220,8 +229,9 @@ static struct attribute *lm77_attributes[] = {
&dev_attr_temp1_crit_hyst.attr,
&dev_attr_temp1_min_hyst.attr,
&dev_attr_temp1_max_hyst.attr,
- &dev_attr_alarms.attr,
-
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
NULL
};
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 3f7055ee679..0a9eb1f6f4e 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -37,10 +37,8 @@
static struct platform_device *pdev;
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24,
- 0x25, 0x26, 0x27, 0x28, 0x29,
- 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
- 0x2f, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+ 0x2e, 0x2f, I2C_CLIENT_END };
static unsigned short isa_address = 0x290;
/* Insmod parameters */
@@ -170,7 +168,6 @@ static struct i2c_driver lm78_driver = {
.driver = {
.name = "lm78",
},
- .id = I2C_DRIVERID_LM78,
.attach_adapter = lm78_attach_adapter,
.detach_client = lm78_detach_client,
};
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index 063cdba00a8..a2ca055f392 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -27,6 +27,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
@@ -127,7 +128,7 @@ struct lm80_data {
u16 alarms; /* Register encoding, combined */
};
-/*
+/*
* Functions declaration
*/
@@ -147,7 +148,6 @@ static struct i2c_driver lm80_driver = {
.driver = {
.name = "lm80",
},
- .id = I2C_DRIVERID_LM80,
.attach_adapter = lm80_attach_adapter,
.detach_client = lm80_detach_client,
};
@@ -159,105 +159,74 @@ static struct i2c_driver lm80_driver = {
#define show_in(suffix, value) \
static ssize_t show_in_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
+ int nr = to_sensor_dev_attr(attr)->index; \
struct lm80_data *data = lm80_update_device(dev); \
- return sprintf(buf, "%d\n", IN_FROM_REG(data->value)); \
+ return sprintf(buf, "%d\n", IN_FROM_REG(data->value[nr])); \
}
-show_in(min0, in_min[0]);
-show_in(min1, in_min[1]);
-show_in(min2, in_min[2]);
-show_in(min3, in_min[3]);
-show_in(min4, in_min[4]);
-show_in(min5, in_min[5]);
-show_in(min6, in_min[6]);
-show_in(max0, in_max[0]);
-show_in(max1, in_max[1]);
-show_in(max2, in_max[2]);
-show_in(max3, in_max[3]);
-show_in(max4, in_max[4]);
-show_in(max5, in_max[5]);
-show_in(max6, in_max[6]);
-show_in(input0, in[0]);
-show_in(input1, in[1]);
-show_in(input2, in[2]);
-show_in(input3, in[3]);
-show_in(input4, in[4]);
-show_in(input5, in[5]);
-show_in(input6, in[6]);
+show_in(min, in_min)
+show_in(max, in_max)
+show_in(input, in)
#define set_in(suffix, value, reg) \
static ssize_t set_in_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \
size_t count) \
{ \
+ int nr = to_sensor_dev_attr(attr)->index; \
struct i2c_client *client = to_i2c_client(dev); \
struct lm80_data *data = i2c_get_clientdata(client); \
long val = simple_strtol(buf, NULL, 10); \
\
mutex_lock(&data->update_lock);\
- data->value = IN_TO_REG(val); \
- lm80_write_value(client, reg, data->value); \
+ data->value[nr] = IN_TO_REG(val); \
+ lm80_write_value(client, reg(nr), data->value[nr]); \
mutex_unlock(&data->update_lock);\
return count; \
}
-set_in(min0, in_min[0], LM80_REG_IN_MIN(0));
-set_in(min1, in_min[1], LM80_REG_IN_MIN(1));
-set_in(min2, in_min[2], LM80_REG_IN_MIN(2));
-set_in(min3, in_min[3], LM80_REG_IN_MIN(3));
-set_in(min4, in_min[4], LM80_REG_IN_MIN(4));
-set_in(min5, in_min[5], LM80_REG_IN_MIN(5));
-set_in(min6, in_min[6], LM80_REG_IN_MIN(6));
-set_in(max0, in_max[0], LM80_REG_IN_MAX(0));
-set_in(max1, in_max[1], LM80_REG_IN_MAX(1));
-set_in(max2, in_max[2], LM80_REG_IN_MAX(2));
-set_in(max3, in_max[3], LM80_REG_IN_MAX(3));
-set_in(max4, in_max[4], LM80_REG_IN_MAX(4));
-set_in(max5, in_max[5], LM80_REG_IN_MAX(5));
-set_in(max6, in_max[6], LM80_REG_IN_MAX(6));
-
-#define show_fan(suffix, value, div) \
+set_in(min, in_min, LM80_REG_IN_MIN)
+set_in(max, in_max, LM80_REG_IN_MAX)
+
+#define show_fan(suffix, value) \
static ssize_t show_fan_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
+ int nr = to_sensor_dev_attr(attr)->index; \
struct lm80_data *data = lm80_update_device(dev); \
- return sprintf(buf, "%d\n", FAN_FROM_REG(data->value, \
- DIV_FROM_REG(data->div))); \
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[nr], \
+ DIV_FROM_REG(data->fan_div[nr]))); \
}
-show_fan(min1, fan_min[0], fan_div[0]);
-show_fan(min2, fan_min[1], fan_div[1]);
-show_fan(input1, fan[0], fan_div[0]);
-show_fan(input2, fan[1], fan_div[1]);
+show_fan(min, fan_min)
+show_fan(input, fan)
-#define show_fan_div(suffix, value) \
-static ssize_t show_fan_div##suffix(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct lm80_data *data = lm80_update_device(dev); \
- return sprintf(buf, "%d\n", DIV_FROM_REG(data->value)); \
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct lm80_data *data = lm80_update_device(dev);
+ return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
}
-show_fan_div(1, fan_div[0]);
-show_fan_div(2, fan_div[1]);
-#define set_fan(suffix, value, reg, div) \
-static ssize_t set_fan_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm80_data *data = i2c_get_clientdata(client); \
- long val = simple_strtoul(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock);\
- data->value = FAN_TO_REG(val, DIV_FROM_REG(data->div)); \
- lm80_write_value(client, reg, data->value); \
- mutex_unlock(&data->update_lock);\
- return count; \
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm80_data *data = i2c_get_clientdata(client);
+ long val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+ lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
}
-set_fan(min1, fan_min[0], LM80_REG_FAN_MIN(1), fan_div[0]);
-set_fan(min2, fan_min[1], LM80_REG_FAN_MIN(2), fan_div[1]);
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor. This follows the principle of
least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
-static ssize_t set_fan_div(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm80_data *data = i2c_get_clientdata(client);
unsigned long min, val = simple_strtoul(buf, NULL, 10);
@@ -292,15 +261,6 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
return count;
}
-#define set_fan_div(number) \
-static ssize_t set_fan_div##number(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- return set_fan_div(dev, buf, count, number - 1); \
-}
-set_fan_div(1);
-set_fan_div(2);
-
static ssize_t show_temp_input1(struct device *dev, struct device_attribute *attr, char *buf)
{
struct lm80_data *data = lm80_update_device(dev);
@@ -337,41 +297,66 @@ set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST);
set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX);
set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST);
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct lm80_data *data = lm80_update_device(dev);
return sprintf(buf, "%u\n", data->alarms);
}
-static DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min0, set_in_min0);
-static DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min1, set_in_min1);
-static DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min2, set_in_min2);
-static DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min3, set_in_min3);
-static DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min4, set_in_min4);
-static DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min5, set_in_min5);
-static DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min6, set_in_min6);
-static DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max0, set_in_max0);
-static DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max1, set_in_max1);
-static DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max2, set_in_max2);
-static DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max3, set_in_max3);
-static DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max4, set_in_max4);
-static DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max5, set_in_max5);
-static DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max6, set_in_max6);
-static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL);
-static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL);
-static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL);
-static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL);
-static DEVICE_ATTR(in4_input, S_IRUGO, show_in_input4, NULL);
-static DEVICE_ATTR(in5_input, S_IRUGO, show_in_input5, NULL);
-static DEVICE_ATTR(in6_input, S_IRUGO, show_in_input6, NULL);
-static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min1,
- set_fan_min1);
-static DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min2,
- set_fan_min2);
-static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL);
-static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL);
-static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div1, set_fan_div1);
-static DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div2, set_fan_div2);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct lm80_data *data = lm80_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO,
+ show_in_min, set_in_min, 0);
+static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO,
+ show_in_min, set_in_min, 1);
+static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO,
+ show_in_min, set_in_min, 2);
+static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO,
+ show_in_min, set_in_min, 3);
+static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO,
+ show_in_min, set_in_min, 4);
+static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO,
+ show_in_min, set_in_min, 5);
+static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO,
+ show_in_min, set_in_min, 6);
+static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO,
+ show_in_max, set_in_max, 0);
+static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO,
+ show_in_max, set_in_max, 1);
+static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO,
+ show_in_max, set_in_max, 2);
+static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO,
+ show_in_max, set_in_max, 3);
+static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO,
+ show_in_max, set_in_max, 4);
+static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO,
+ show_in_max, set_in_max, 5);
+static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO,
+ show_in_max, set_in_max, 6);
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in_input, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in_input, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in_input, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in_input, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
+ show_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
+ show_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO,
+ show_fan_div, set_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO,
+ show_fan_div, set_fan_div, 1);
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max,
set_temp_hot_max);
@@ -382,6 +367,17 @@ static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max,
static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst,
set_temp_os_hyst);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 13);
/*
* Real code
@@ -395,40 +391,50 @@ static int lm80_attach_adapter(struct i2c_adapter *adapter)
}
static struct attribute *lm80_attributes[] = {
- &dev_attr_in0_min.attr,
- &dev_attr_in1_min.attr,
- &dev_attr_in2_min.attr,
- &dev_attr_in3_min.attr,
- &dev_attr_in4_min.attr,
- &dev_attr_in5_min.attr,
- &dev_attr_in6_min.attr,
- &dev_attr_in0_max.attr,
- &dev_attr_in1_max.attr,
- &dev_attr_in2_max.attr,
- &dev_attr_in3_max.attr,
- &dev_attr_in4_max.attr,
- &dev_attr_in5_max.attr,
- &dev_attr_in6_max.attr,
- &dev_attr_in0_input.attr,
- &dev_attr_in1_input.attr,
- &dev_attr_in2_input.attr,
- &dev_attr_in3_input.attr,
- &dev_attr_in4_input.attr,
- &dev_attr_in5_input.attr,
- &dev_attr_in6_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan1_input.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan1_div.attr,
- &dev_attr_fan2_div.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
&dev_attr_temp1_input.attr,
&dev_attr_temp1_max.attr,
&dev_attr_temp1_max_hyst.attr,
&dev_attr_temp1_crit.attr,
&dev_attr_temp1_crit_hyst.attr,
&dev_attr_alarms.attr,
-
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
NULL
};
@@ -439,7 +445,7 @@ static const struct attribute_group lm80_group = {
static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i, cur;
- struct i2c_client *new_client;
+ struct i2c_client *client;
struct lm80_data *data;
int err = 0;
const char *name;
@@ -455,21 +461,20 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &lm80_driver;
- new_client->flags = 0;
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &lm80_driver;
/* Now, we do the remaining detection. It is lousy. */
- if (lm80_read_value(new_client, LM80_REG_ALARM2) & 0xc0)
+ if (lm80_read_value(client, LM80_REG_ALARM2) & 0xc0)
goto error_free;
for (i = 0x2a; i <= 0x3d; i++) {
- cur = i2c_smbus_read_byte_data(new_client, i);
- if ((i2c_smbus_read_byte_data(new_client, i + 0x40) != cur)
- || (i2c_smbus_read_byte_data(new_client, i + 0x80) != cur)
- || (i2c_smbus_read_byte_data(new_client, i + 0xc0) != cur))
+ cur = i2c_smbus_read_byte_data(client, i);
+ if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur)
+ || (i2c_smbus_read_byte_data(client, i + 0x80) != cur)
+ || (i2c_smbus_read_byte_data(client, i + 0xc0) != cur))
goto error_free;
}
@@ -477,27 +482,26 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
kind = lm80;
name = "lm80";
- /* Fill in the remaining client fields and put it into the global list */
- strlcpy(new_client->name, name, I2C_NAME_SIZE);
- data->valid = 0;
+ /* Fill in the remaining client fields */
+ strlcpy(client->name, name, I2C_NAME_SIZE);
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
+ if ((err = i2c_attach_client(client)))
goto error_free;
/* Initialize the LM80 chip */
- lm80_init_client(new_client);
+ lm80_init_client(client);
/* A few vars need to be filled upon startup */
- data->fan_min[0] = lm80_read_value(new_client, LM80_REG_FAN_MIN(1));
- data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2));
+ data->fan_min[0] = lm80_read_value(client, LM80_REG_FAN_MIN(1));
+ data->fan_min[1] = lm80_read_value(client, LM80_REG_FAN_MIN(2));
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &lm80_group)))
+ if ((err = sysfs_create_group(&client->dev.kobj, &lm80_group)))
goto error_detach;
- data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto error_remove;
@@ -506,9 +510,9 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
error_remove:
- sysfs_remove_group(&new_client->dev.kobj, &lm80_group);
+ sysfs_remove_group(&client->dev.kobj, &lm80_group);
error_detach:
- i2c_detach_client(new_client);
+ i2c_detach_client(client);
error_free:
kfree(data);
exit:
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index 0336b4572a6..6e8903a6e90 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -133,7 +133,6 @@ static struct i2c_driver lm83_driver = {
.driver = {
.name = "lm83",
},
- .id = I2C_DRIVERID_LM83,
.attach_adapter = lm83_attach_adapter,
.detach_client = lm83_detach_client,
};
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index a02480be65f..4bb0f291a6b 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -367,7 +367,6 @@ static struct i2c_driver lm85_driver = {
.driver = {
.name = "lm85",
},
- .id = I2C_DRIVERID_LM85,
.attach_adapter = lm85_attach_adapter,
.detach_client = lm85_detach_client,
};
@@ -444,12 +443,8 @@ static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, c
static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm85_data *data = i2c_get_clientdata(client);
- u32 val;
-
- val = simple_strtoul(buf, NULL, 10);
- data->vrm = val;
+ struct lm85_data *data = dev_get_drvdata(dev);
+ data->vrm = simple_strtoul(buf, NULL, 10);
return count;
}
@@ -519,17 +514,64 @@ static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
{
int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
- int pwm_zone;
+ int pwm_zone, enable;
pwm_zone = ZONE_FROM_REG(data->autofan[nr].config);
- return sprintf(buf,"%d\n", (pwm_zone != 0 && pwm_zone != -1) );
+ switch (pwm_zone) {
+ case -1: /* PWM is always at 100% */
+ enable = 0;
+ break;
+ case 0: /* PWM is always at 0% */
+ case -2: /* PWM responds to manual control */
+ enable = 1;
+ break;
+ default: /* PWM in automatic mode */
+ enable = 2;
+ }
+ return sprintf(buf, "%d\n", enable);
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute
+ *attr, const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm85_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+ u8 config;
+
+ switch (val) {
+ case 0:
+ config = 3;
+ break;
+ case 1:
+ config = 7;
+ break;
+ case 2:
+ /* Here we have to choose arbitrarily one of the 5 possible
+ configurations; I go for the safest */
+ config = 6;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->update_lock);
+ data->autofan[nr].config = lm85_read_value(client,
+ LM85_REG_AFAN_CONFIG(nr));
+ data->autofan[nr].config = (data->autofan[nr].config & ~0xe0)
+ | (config << 5);
+ lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr),
+ data->autofan[nr].config);
+ mutex_unlock(&data->update_lock);
+ return count;
}
#define show_pwm_reg(offset) \
static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
show_pwm, set_pwm, offset - 1); \
-static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \
- show_pwm_enable, NULL, offset - 1)
+static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
+ show_pwm_enable, set_pwm_enable, offset - 1)
show_pwm_reg(1);
show_pwm_reg(2);
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index 28cdff0c556..8ee07c5c97a 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -5,7 +5,7 @@
* Philip Edelbrock <phil@netroedge.com>
* Stephen Rousset <stephen.rousset@rocketlogix.com>
* Dan Eaton <dan.eaton@rocketlogix.com>
- * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004,2007 Jean Delvare <khali@linux-fr.org>
*
* Original port to Linux 2.6 by Jeff Oliver.
*
@@ -37,6 +37,11 @@
* instead. The LM87 is the only hardware monitoring chipset I know of
* which uses amplitude modulation. Be careful when using this feature.
*
+ * This driver also supports the ADM1024, a sensor chip made by Analog
+ * Devices. That chip is fully compatible with the LM87. Complete
+ * datasheet can be obtained from Analog's website at:
+ * http://www.analog.com/en/prod/0,2877,ADM1024,00.html
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -74,7 +79,7 @@ static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
* Insmod parameters
*/
-I2C_CLIENT_INSMOD_1(lm87);
+I2C_CLIENT_INSMOD_2(lm87, adm1024);
/*
* The LM87 registers
@@ -166,7 +171,6 @@ static struct i2c_driver lm87_driver = {
.driver = {
.name = "lm87",
},
- .id = I2C_DRIVERID_LM87,
.attach_adapter = lm87_attach_adapter,
.detach_client = lm87_detach_client,
};
@@ -506,8 +510,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char
}
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm87_data *data = i2c_get_clientdata(client);
+ struct lm87_data *data = dev_get_drvdata(dev);
data->vrm = simple_strtoul(buf, NULL, 10);
return count;
}
@@ -662,6 +665,7 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
struct i2c_client *new_client;
struct lm87_data *data;
int err = 0;
+ static const char *names[] = { "lm87", "adm1024" };
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
goto exit;
@@ -686,11 +690,18 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
/* Now, we do the remaining detection. */
if (kind < 0) {
+ u8 cid = lm87_read_value(new_client, LM87_REG_COMPANY_ID);
u8 rev = lm87_read_value(new_client, LM87_REG_REVISION);
- if (rev < 0x01 || rev > 0x08
- || (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80)
- || lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02) {
+ if (cid == 0x02 /* National Semiconductor */
+ && (rev >= 0x01 && rev <= 0x08))
+ kind = lm87;
+ else if (cid == 0x41 /* Analog Devices */
+ && (rev & 0xf0) == 0x10)
+ kind = adm1024;
+
+ if (kind < 0
+ || (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80)) {
dev_dbg(&adapter->dev,
"LM87 detection failed at 0x%02x.\n",
address);
@@ -699,7 +710,7 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* We can fill in the remaining client fields */
- strlcpy(new_client->name, "lm87", I2C_NAME_SIZE);
+ strlcpy(new_client->name, names[kind - 1], I2C_NAME_SIZE);
data->valid = 0;
mutex_init(&data->update_lock);
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 960df9fa75a..f7ec95bedbf 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -204,7 +204,6 @@ static struct i2c_driver lm90_driver = {
.driver = {
.name = "lm90",
},
- .id = I2C_DRIVERID_LM90,
.attach_adapter = lm90_attach_adapter,
.detach_client = lm90_detach_client,
};
@@ -531,24 +530,24 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
kind = lm90;
if (kind < 0) { /* detection and identification */
- u8 man_id, chip_id, reg_config1, reg_convrate;
-
- if (lm90_read_reg(new_client, LM90_REG_R_MAN_ID,
- &man_id) < 0
- || lm90_read_reg(new_client, LM90_REG_R_CHIP_ID,
- &chip_id) < 0
- || lm90_read_reg(new_client, LM90_REG_R_CONFIG1,
- &reg_config1) < 0
- || lm90_read_reg(new_client, LM90_REG_R_CONVRATE,
- &reg_convrate) < 0)
+ int man_id, chip_id, reg_config1, reg_convrate;
+
+ if ((man_id = i2c_smbus_read_byte_data(new_client,
+ LM90_REG_R_MAN_ID)) < 0
+ || (chip_id = i2c_smbus_read_byte_data(new_client,
+ LM90_REG_R_CHIP_ID)) < 0
+ || (reg_config1 = i2c_smbus_read_byte_data(new_client,
+ LM90_REG_R_CONFIG1)) < 0
+ || (reg_convrate = i2c_smbus_read_byte_data(new_client,
+ LM90_REG_R_CONVRATE)) < 0)
goto exit_free;
if ((address == 0x4C || address == 0x4D)
&& man_id == 0x01) { /* National Semiconductor */
- u8 reg_config2;
+ int reg_config2;
- if (lm90_read_reg(new_client, LM90_REG_R_CONFIG2,
- &reg_config2) < 0)
+ if ((reg_config2 = i2c_smbus_read_byte_data(new_client,
+ LM90_REG_R_CONFIG2)) < 0)
goto exit_free;
if ((reg_config1 & 0x2A) == 0x00
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index 61d1bd1d5b6..af5c77d568f 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -428,7 +428,6 @@ static struct i2c_driver lm92_driver = {
.driver = {
.name = "lm92",
},
- .id = I2C_DRIVERID_LM92,
.attach_adapter = lm92_attach_adapter,
.detach_client = lm92_detach_client,
};
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index 9d660133d51..9b462bb13fa 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -59,6 +59,10 @@ MODULE_PARM_DESC(init,
" 2: Forcibly enable all voltage and temperature channels, except in9\n"
" 3: Forcibly enable all voltage and temperature channels, including in9");
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
/*
* Super-I/O registers and operations
*/
@@ -826,7 +830,7 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses
/* No superio_enter */
/* Identify device */
- val = superio_inb(sioaddr, DEVID);
+ val = force_id ? force_id : superio_inb(sioaddr, DEVID);
switch (val) {
case 0xE1: /* PC87360 */
case 0xE8: /* PC87363 */
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index d40509ad6ae..7265f22ae5c 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -34,6 +34,10 @@
#include <linux/ioport.h>
#include <asm/io.h>
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
static struct platform_device *pdev;
#define DRVNAME "pc87427"
@@ -555,7 +559,7 @@ static int __init pc87427_find(int sioaddr, unsigned short *address)
int i, err = 0;
/* Identify device */
- val = superio_inb(sioaddr, SIOREG_DEVID);
+ val = force_id ? force_id : superio_inb(sioaddr, SIOREG_DEVID);
if (val != 0xf2) { /* PC87427 */
err = -ENODEV;
goto exit;
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index 0b57d2ea2cf..f61d8f4185b 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -38,6 +38,10 @@
#include <linux/mutex.h>
#include <asm/io.h>
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
static struct platform_device *pdev;
#define DRVNAME "smsc47b397"
@@ -333,7 +337,7 @@ static int __init smsc47b397_find(unsigned short *addr)
u8 id, rev;
superio_enter();
- id = superio_inb(SUPERIO_REG_DEVID);
+ id = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
if ((id != 0x6f) && (id != 0x81) && (id != 0x85)) {
superio_exit();
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index a10a380868e..0d7f0c4d06b 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -39,6 +39,10 @@
#include <linux/sysfs.h>
#include <asm/io.h>
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
static struct platform_device *pdev;
#define DRVNAME "smsc47m1"
@@ -399,7 +403,7 @@ static int __init smsc47m1_find(unsigned short *addr,
u8 val;
superio_enter();
- val = superio_inb(SUPERIO_REG_DEVID);
+ val = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
/*
* SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index b8755265258..8b0c188e60f 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -341,8 +341,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct smsc47m192_data *data = i2c_get_clientdata(client);
+ struct smsc47m192_data *data = dev_get_drvdata(dev);
data->vrm = simple_strtoul(buf, NULL, 10);
return count;
}
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index 7dfcc8dd316..12b43590fa5 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -42,6 +42,10 @@ static int int_mode = -1;
module_param(int_mode, int, 0);
MODULE_PARM_DESC(int_mode, "Force the temperature interrupt mode");
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
static struct platform_device *pdev;
#define DRVNAME "vt1211"
@@ -1280,10 +1284,12 @@ EXIT:
static int __init vt1211_find(int sio_cip, unsigned short *address)
{
int err = -ENODEV;
+ int devid;
superio_enter(sio_cip);
- if (superio_inb(sio_cip, SIO_VT1211_DEVID) != SIO_VT1211_ID) {
+ devid = force_id ? force_id : superio_inb(sio_cip, SIO_VT1211_DEVID);
+ if (devid != SIO_VT1211_ID) {
goto EXIT;
}
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index 2196a84603f..f87661775fe 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -504,7 +504,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
case 4: data->fan_div[nr] = 2; break;
case 8: data->fan_div[nr] = 3; break;
default:
- dev_err(dev, "fan_div value %ld not supported."
+ dev_err(dev, "fan_div value %ld not supported. "
"Choose one of 1, 2, 4 or 8!\n", val);
mutex_unlock(&data->update_lock);
return -EINVAL;
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index d5aa25ce5db..075164dd65a 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -59,6 +59,10 @@ static const char * w83627ehf_device_names[] = {
"w83627dhg",
};
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
#define DRVNAME "w83627ehf"
/*
@@ -1198,8 +1202,7 @@ static void w83627ehf_device_remove_files(struct device *dev)
device_remove_file(dev, &sda_temp[i].dev_attr);
device_remove_file(dev, &dev_attr_name);
- if (data->vid != 0x3f)
- device_remove_file(dev, &dev_attr_cpu0_vid);
+ device_remove_file(dev, &dev_attr_cpu0_vid);
}
/* Get the monitoring functions started */
@@ -1299,11 +1302,16 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
}
}
- data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA) & 0x3f;
+ data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA);
+ if (sio_data->kind == w83627ehf) /* 6 VID pins only */
+ data->vid &= 0x3f;
+
+ err = device_create_file(dev, &dev_attr_cpu0_vid);
+ if (err)
+ goto exit_release;
} else {
dev_info(dev, "VID pins in output mode, CPU VID not "
"available\n");
- data->vid = 0x3f;
}
/* fan4 and fan5 share some pins with the GPIO and serial flash */
@@ -1386,12 +1394,6 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
if (err)
goto exit_remove;
- if (data->vid != 0x3f) {
- err = device_create_file(dev, &dev_attr_cpu0_vid);
- if (err)
- goto exit_remove;
- }
-
data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
@@ -1445,8 +1447,11 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
superio_enter(sioaddr);
- val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
- | superio_inb(sioaddr, SIO_REG_DEVID + 1);
+ if (force_id)
+ val = force_id;
+ else
+ val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
+ | superio_inb(sioaddr, SIO_REG_DEVID + 1);
switch (val & SIO_ID_MASK) {
case SIO_W83627EHF_ID:
sio_data->kind = w83627ehf;
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 879d0a6544c..9564fb06995 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -75,6 +75,10 @@ static int init = 1;
module_param(init, bool, 0);
MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
/* modified from kernel/include/traps.c */
static int REG; /* The register to read/write */
#define DEV 0x07 /* Register: Logical device select */
@@ -319,10 +323,8 @@ static inline u8 pwm_freq_to_reg(unsigned long val)
return (0x80 | (180000UL / (val << 8)));
}
-#define BEEP_MASK_FROM_REG(val) (val)
-#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff)
-#define BEEP_ENABLE_TO_REG(val) ((val)?1:0)
-#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0)
+#define BEEP_MASK_FROM_REG(val) ((val) & 0xff7fff)
+#define BEEP_MASK_TO_REG(val) ((val) & 0xff7fff)
#define DIV_FROM_REG(val) (1 << (val))
@@ -363,7 +365,6 @@ struct w83627hf_data {
u8 vid; /* Register encoding, combined */
u32 alarms; /* Register encoding, combined */
u32 beep_mask; /* Register encoding, combined */
- u8 beep_enable; /* Boolean */
u8 pwm[3]; /* Register value */
u8 pwm_freq[3]; /* Register value */
u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode;
@@ -713,65 +714,151 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
-#define show_beep_reg(REG, reg) \
-static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct w83627hf_data *data = w83627hf_update_device(dev); \
- return sprintf(buf,"%ld\n", \
- (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \
+static ssize_t
+show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
}
-show_beep_reg(ENABLE, enable)
-show_beep_reg(MASK, mask)
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
-#define BEEP_ENABLE 0 /* Store beep_enable */
-#define BEEP_MASK 1 /* Store beep_mask */
+static ssize_t
+show_beep_mask(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ return sprintf(buf, "%ld\n",
+ (long)BEEP_MASK_FROM_REG(data->beep_mask));
+}
static ssize_t
-store_beep_reg(struct device *dev, const char *buf, size_t count,
- int update_mask)
+store_beep_mask(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct w83627hf_data *data = dev_get_drvdata(dev);
- u32 val, val2;
+ unsigned long val;
val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
- if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
- data->beep_mask = BEEP_MASK_TO_REG(val);
- w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
- data->beep_mask & 0xff);
- w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
- ((data->beep_mask) >> 16) & 0xff);
- val2 = (data->beep_mask >> 8) & 0x7f;
- } else { /* We are storing beep_enable */
- val2 =
- w83627hf_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
- data->beep_enable = BEEP_ENABLE_TO_REG(val);
- }
-
+ /* preserve beep enable */
+ data->beep_mask = (data->beep_mask & 0x8000)
+ | BEEP_MASK_TO_REG(val);
+ w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
+ data->beep_mask & 0xff);
+ w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
+ ((data->beep_mask) >> 16) & 0xff);
w83627hf_write_value(data, W83781D_REG_BEEP_INTS2,
- val2 | data->beep_enable << 7);
+ (data->beep_mask >> 8) & 0xff);
mutex_unlock(&data->update_lock);
return count;
}
-#define sysfs_beep(REG, reg) \
-static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_beep_##reg(dev, attr, buf); \
-} \
-static ssize_t \
-store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_beep_reg(dev, buf, count, BEEP_##REG); \
-} \
-static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
- show_regs_beep_##reg, store_regs_beep_##reg);
+static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
+ show_beep_mask, store_beep_mask);
+
+static ssize_t
+show_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct w83627hf_data *data = dev_get_drvdata(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ unsigned long bit;
+ u8 reg;
+
+ bit = simple_strtoul(buf, NULL, 10);
+ if (bit & ~1)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ if (bit)
+ data->beep_mask |= (1 << bitnr);
+ else
+ data->beep_mask &= ~(1 << bitnr);
+
+ if (bitnr < 8) {
+ reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS1);
+ if (bit)
+ reg |= (1 << bitnr);
+ else
+ reg &= ~(1 << bitnr);
+ w83627hf_write_value(data, W83781D_REG_BEEP_INTS1, reg);
+ } else if (bitnr < 16) {
+ reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
+ if (bit)
+ reg |= (1 << (bitnr - 8));
+ else
+ reg &= ~(1 << (bitnr - 8));
+ w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, reg);
+ } else {
+ reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS3);
+ if (bit)
+ reg |= (1 << (bitnr - 16));
+ else
+ reg &= ~(1 << (bitnr - 16));
+ w83627hf_write_value(data, W83781D_REG_BEEP_INTS3, reg);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
-sysfs_beep(ENABLE, enable);
-sysfs_beep(MASK, mask);
+static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 0);
+static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 1);
+static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 2);
+static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 3);
+static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 8);
+static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 9);
+static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 10);
+static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 16);
+static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 17);
+static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 6);
+static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 7);
+static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 11);
+static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 4);
+static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 5);
+static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 13);
+static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 15);
static ssize_t
show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
@@ -1014,7 +1101,7 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
VAL = sioaddr + 1;
superio_enter();
- val= superio_inb(DEVID);
+ val = force_id ? force_id : superio_inb(DEVID);
switch (val) {
case W627_DEVID:
sio_data->type = w83627hf;
@@ -1073,23 +1160,31 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
#define VIN_UNIT_ATTRS(_X_) \
&sensor_dev_attr_in##_X_##_input.dev_attr.attr, \
&sensor_dev_attr_in##_X_##_min.dev_attr.attr, \
- &sensor_dev_attr_in##_X_##_max.dev_attr.attr
+ &sensor_dev_attr_in##_X_##_max.dev_attr.attr, \
+ &sensor_dev_attr_in##_X_##_alarm.dev_attr.attr, \
+ &sensor_dev_attr_in##_X_##_beep.dev_attr.attr
#define FAN_UNIT_ATTRS(_X_) \
&sensor_dev_attr_fan##_X_##_input.dev_attr.attr, \
&sensor_dev_attr_fan##_X_##_min.dev_attr.attr, \
- &sensor_dev_attr_fan##_X_##_div.dev_attr.attr
+ &sensor_dev_attr_fan##_X_##_div.dev_attr.attr, \
+ &sensor_dev_attr_fan##_X_##_alarm.dev_attr.attr, \
+ &sensor_dev_attr_fan##_X_##_beep.dev_attr.attr
#define TEMP_UNIT_ATTRS(_X_) \
&sensor_dev_attr_temp##_X_##_input.dev_attr.attr, \
&sensor_dev_attr_temp##_X_##_max.dev_attr.attr, \
&sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr, \
- &sensor_dev_attr_temp##_X_##_type.dev_attr.attr
+ &sensor_dev_attr_temp##_X_##_type.dev_attr.attr, \
+ &sensor_dev_attr_temp##_X_##_alarm.dev_attr.attr, \
+ &sensor_dev_attr_temp##_X_##_beep.dev_attr.attr
static struct attribute *w83627hf_attributes[] = {
&dev_attr_in0_input.attr,
&dev_attr_in0_min.attr,
&dev_attr_in0_max.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in0_beep.dev_attr.attr,
VIN_UNIT_ATTRS(2),
VIN_UNIT_ATTRS(3),
VIN_UNIT_ATTRS(4),
@@ -1103,7 +1198,7 @@ static struct attribute *w83627hf_attributes[] = {
TEMP_UNIT_ATTRS(2),
&dev_attr_alarms.attr,
- &dev_attr_beep_enable.attr,
+ &sensor_dev_attr_beep_enable.dev_attr.attr,
&dev_attr_beep_mask.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
@@ -1193,12 +1288,20 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
|| (err = device_create_file(dev,
&sensor_dev_attr_in5_max.dev_attr))
|| (err = device_create_file(dev,
+ &sensor_dev_attr_in5_alarm.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in5_beep.dev_attr))
+ || (err = device_create_file(dev,
&sensor_dev_attr_in6_input.dev_attr))
|| (err = device_create_file(dev,
&sensor_dev_attr_in6_min.dev_attr))
|| (err = device_create_file(dev,
&sensor_dev_attr_in6_max.dev_attr))
|| (err = device_create_file(dev,
+ &sensor_dev_attr_in6_alarm.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in6_beep.dev_attr))
+ || (err = device_create_file(dev,
&sensor_dev_attr_pwm1_freq.dev_attr))
|| (err = device_create_file(dev,
&sensor_dev_attr_pwm2_freq.dev_attr)))
@@ -1212,18 +1315,30 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
|| (err = device_create_file(dev,
&sensor_dev_attr_in1_max.dev_attr))
|| (err = device_create_file(dev,
+ &sensor_dev_attr_in1_alarm.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in1_beep.dev_attr))
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan3_input.dev_attr))
|| (err = device_create_file(dev,
&sensor_dev_attr_fan3_min.dev_attr))
|| (err = device_create_file(dev,
&sensor_dev_attr_fan3_div.dev_attr))
|| (err = device_create_file(dev,
+ &sensor_dev_attr_fan3_alarm.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan3_beep.dev_attr))
+ || (err = device_create_file(dev,
&sensor_dev_attr_temp3_input.dev_attr))
|| (err = device_create_file(dev,
&sensor_dev_attr_temp3_max.dev_attr))
|| (err = device_create_file(dev,
&sensor_dev_attr_temp3_max_hyst.dev_attr))
|| (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_alarm.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_beep.dev_attr))
+ || (err = device_create_file(dev,
&sensor_dev_attr_temp3_type.dev_attr)))
goto ERROR4;
@@ -1511,6 +1626,11 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
(w83627hf_read_value(data,
W83781D_REG_CONFIG) & 0xf7)
| 0x01);
+
+ /* Enable VBAT monitoring if needed */
+ tmp = w83627hf_read_value(data, W83781D_REG_VBAT);
+ if (!(tmp & 0x01))
+ w83627hf_write_value(data, W83781D_REG_VBAT, tmp | 0x01);
}
static void w83627hf_update_fan_div(struct w83627hf_data *data)
@@ -1603,8 +1723,7 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
(w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
(w83627hf_read_value(data, W83781D_REG_ALARM3) << 16);
i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
- data->beep_enable = i >> 7;
- data->beep_mask = ((i & 0x7f) << 8) |
+ data->beep_mask = (i << 8) |
w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) |
w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16;
data->last_updated = jiffies;
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index e0fa7520400..7421f6ea53e 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -28,7 +28,6 @@
as99127f 7 3 0 3 0x31 0x12c3 yes no
as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no
w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes
- w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC)
w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes
w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no
@@ -54,13 +53,12 @@
static struct platform_device *pdev;
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
- 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
- 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+ 0x2e, 0x2f, I2C_CLIENT_END };
static unsigned short isa_address = 0x290;
/* Insmod parameters */
-I2C_CLIENT_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f);
+I2C_CLIENT_INSMOD_4(w83781d, w83782d, w83783s, as99127f);
I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
@@ -114,7 +112,7 @@ MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
#define W83781D_REG_ALARM1 0x41
#define W83781D_REG_ALARM2 0x42
-/* Real-time status (W83782D, W83783S, W83627HF) */
+/* Real-time status (W83782D, W83783S) */
#define W83782D_REG_ALARM1 0x459
#define W83782D_REG_ALARM2 0x45A
#define W83782D_REG_ALARM3 0x45B
@@ -153,10 +151,6 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
#define W83781D_DEFAULT_BETA 3435
-/* RT Table registers */
-#define W83781D_REG_RT_IDX 0x50
-#define W83781D_REG_RT_VAL 0x51
-
/* Conversions */
#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
#define IN_FROM_REG(val) ((val) * 16)
@@ -271,7 +265,6 @@ static struct i2c_driver w83781d_driver = {
.driver = {
.name = "w83781d",
},
- .id = I2C_DRIVERID_W83781D,
.attach_adapter = w83781d_attach_adapter,
.detach_client = w83781d_detach_client,
};
@@ -696,7 +689,7 @@ store_fan_div(struct device *dev, struct device_attribute *da,
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
-
+
/* Save fan_min */
min = FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr]));
@@ -963,8 +956,6 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
client_name = "w83782d subclient";
else if (kind == w83783s)
client_name = "w83783s subclient";
- else if (kind == w83627hf)
- client_name = "w83627hf subclient";
else if (kind == as99127f)
client_name = "as99127f subclient";
@@ -1004,7 +995,7 @@ ERROR_SC_0:
#define IN_UNIT_ATTRS(X) \
&sensor_dev_attr_in##X##_input.dev_attr.attr, \
&sensor_dev_attr_in##X##_min.dev_attr.attr, \
- &sensor_dev_attr_in##X##_max.dev_attr.attr, \
+ &sensor_dev_attr_in##X##_max.dev_attr.attr, \
&sensor_dev_attr_in##X##_alarm.dev_attr.attr, \
&sensor_dev_attr_in##X##_beep.dev_attr.attr
@@ -1268,9 +1259,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
kind = w83782d;
else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
kind = w83783s;
- else if (val1 == 0x21 && vendid == winbond)
- kind = w83627hf;
- else if (val1 == 0x31 && address >= 0x28)
+ else if (val1 == 0x31)
kind = as99127f;
else {
if (kind == 0)
@@ -1288,8 +1277,6 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
client_name = "w83782d";
} else if (kind == w83783s) {
client_name = "w83783s";
- } else if (kind == w83627hf) {
- client_name = "w83627hf";
} else if (kind == as99127f) {
client_name = "as99127f";
}
@@ -1396,10 +1383,6 @@ w83781d_isa_probe(struct platform_device *pdev)
reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
switch (reg) {
- case 0x21:
- data->type = w83627hf;
- name = "w83627hf";
- break;
case 0x30:
data->type = w83782d;
name = "w83782d";
@@ -1453,9 +1436,9 @@ w83781d_isa_remove(struct platform_device *pdev)
}
/* The SMBus locks itself, usually, but nothing may access the Winbond between
- bank switches. ISA access must always be locked explicitly!
+ bank switches. ISA access must always be locked explicitly!
We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
- would slow down the W83781D access and should not be necessary.
+ would slow down the W83781D access and should not be necessary.
There are some ugly typecasts here, but the good news is - they should
nowhere else be necessary! */
static int
@@ -1599,11 +1582,6 @@ w83781d_init_device(struct device *dev)
int type = data->type;
u8 tmp;
- if (type == w83627hf)
- dev_info(dev, "The W83627HF chip is better supported by the "
- "w83627hf driver, support will be dropped from the "
- "w83781d driver soon\n");
-
if (reset && type != as99127f) { /* this resets registers we don't have
documentation for on the as99127f */
/* Resetting the chip has been the default for a long time,
@@ -1717,8 +1695,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
w83781d_read_value(data, W83781D_REG_IN_MIN(i));
data->in_max[i] =
w83781d_read_value(data, W83781D_REG_IN_MAX(i));
- if ((data->type != w83782d)
- && (data->type != w83627hf) && (i == 6))
+ if ((data->type != w83782d) && (i == 6))
break;
}
for (i = 0; i < 3; i++) {
@@ -1776,7 +1753,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
data->fan_div[1] |= (i >> 4) & 0x04;
data->fan_div[2] |= (i >> 5) & 0x04;
}
- if ((data->type == w83782d) || (data->type == w83627hf)) {
+ if (data->type == w83782d) {
data->alarms = w83781d_read_value(data,
W83782D_REG_ALARM1)
| (w83781d_read_value(data,
@@ -1886,13 +1863,11 @@ w83781d_isa_found(unsigned short address)
outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
val = inb_p(address + W83781D_DATA_REG_OFFSET);
if ((val & 0xfe) == 0x10 /* W83781D */
- || val == 0x30 /* W83782D */
- || val == 0x21) /* W83627HF */
+ || val == 0x30) /* W83782D */
found = 1;
if (found)
pr_info("w83781d: Found a %s chip at %#x\n",
- val == 0x21 ? "W83627HF" :
val == 0x30 ? "W83782D" : "W83781D", (int)address);
release:
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index a9c01a6f005..85bd21ee329 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -840,14 +840,12 @@ static ssize_t store_vrm_reg(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83791d_data *data = i2c_get_clientdata(client);
- unsigned long val = simple_strtoul(buf, NULL, 10);
+ struct w83791d_data *data = dev_get_drvdata(dev);
/* No lock needed as vrm is internal to the driver
(not read from a chip register) and so is not
updated in w83791d_update_device() */
- data->vrm = val;
+ data->vrm = simple_strtoul(buf, NULL, 10);
return count;
}
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 48599e1cc55..3ba1d6b3347 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -131,6 +131,7 @@ static u8 scale_in_add[] = { 0, 0, 0, 0, 0, 0, 0, 150, 150, 0 };
#define PWM_DUTY 0
#define PWM_START 1
#define PWM_NONSTOP 2
+#define PWM_STOP_TIME 3
#define W83793_REG_PWM(index, nr) (((nr) == 0 ? 0xb3 : \
(nr) == 1 ? 0x220 : 0x218) + (index))
@@ -242,9 +243,7 @@ static struct i2c_driver w83793_driver = {
static ssize_t
show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83793_data *data = i2c_get_clientdata(client);
-
+ struct w83793_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->vrm);
}
@@ -263,9 +262,7 @@ static ssize_t
store_vrm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83793_data *data = i2c_get_clientdata(client);
-
+ struct w83793_data *data = dev_get_drvdata(dev);
data->vrm = simple_strtoul(buf, NULL, 10);
return count;
}
@@ -407,10 +404,6 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
return count;
}
-#define PWM_DUTY 0
-#define PWM_START 1
-#define PWM_NONSTOP 2
-#define PWM_STOP_TIME 3
static ssize_t
show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
{
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index b5db354e2f1..1d6259d29e7 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -96,7 +96,6 @@ static struct i2c_driver w83l785ts_driver = {
.driver = {
.name = "w83l785ts",
},
- .id = I2C_DRIVERID_W83L785TS,
.attach_adapter = w83l785ts_attach_adapter,
.detach_client = w83l785ts_detach_client,
};
diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c
new file mode 100644
index 00000000000..1dbee4fa23a
--- /dev/null
+++ b/drivers/hwmon/w83l786ng.c
@@ -0,0 +1,821 @@
+/*
+ w83l786ng.c - Linux kernel driver for hardware monitoring
+ Copyright (c) 2007 Kevin Lo <kevlo@kevlo.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation - version 2.
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+*/
+
+/*
+ Supports following chips:
+
+ Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
+ w83l786ng 3 2 2 2 0x7b 0x5ca3 yes no
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2e, 0x2f, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(w83l786ng);
+
+static int reset;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
+
+#define W83L786NG_REG_IN_MIN(nr) (0x2C + (nr) * 2)
+#define W83L786NG_REG_IN_MAX(nr) (0x2B + (nr) * 2)
+#define W83L786NG_REG_IN(nr) ((nr) + 0x20)
+
+#define W83L786NG_REG_FAN(nr) ((nr) + 0x28)
+#define W83L786NG_REG_FAN_MIN(nr) ((nr) + 0x3B)
+
+#define W83L786NG_REG_CONFIG 0x40
+#define W83L786NG_REG_ALARM1 0x41
+#define W83L786NG_REG_ALARM2 0x42
+#define W83L786NG_REG_GPIO_EN 0x47
+#define W83L786NG_REG_MAN_ID2 0x4C
+#define W83L786NG_REG_MAN_ID1 0x4D
+#define W83L786NG_REG_CHIP_ID 0x4E
+
+#define W83L786NG_REG_DIODE 0x53
+#define W83L786NG_REG_FAN_DIV 0x54
+#define W83L786NG_REG_FAN_CFG 0x80
+
+#define W83L786NG_REG_TOLERANCE 0x8D
+
+static const u8 W83L786NG_REG_TEMP[2][3] = {
+ { 0x25, /* TEMP 0 in DataSheet */
+ 0x35, /* TEMP 0 Over in DataSheet */
+ 0x36 }, /* TEMP 0 Hyst in DataSheet */
+ { 0x26, /* TEMP 1 in DataSheet */
+ 0x37, /* TEMP 1 Over in DataSheet */
+ 0x38 } /* TEMP 1 Hyst in DataSheet */
+};
+
+static const u8 W83L786NG_PWM_MODE_SHIFT[] = {6, 7};
+static const u8 W83L786NG_PWM_ENABLE_SHIFT[] = {2, 4};
+
+/* FAN Duty Cycle, be used to control */
+static const u8 W83L786NG_REG_PWM[] = {0x81, 0x87};
+
+
+static inline u8
+FAN_TO_REG(long rpm, int div)
+{
+ if (rpm == 0)
+ return 255;
+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \
+ ((val) == 255 ? 0 : \
+ 1350000 / ((val) * (div))))
+
+/* for temp */
+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
+ : (val)) / 1000, 0, 0xff))
+#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
+
+/* The analog voltage inputs have 8mV LSB. Since the sysfs output is
+ in mV as would be measured on the chip input pin, need to just
+ multiply/divide by 8 to translate from/to register values. */
+#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 4) / 8), 0, 255))
+#define IN_FROM_REG(val) ((val) * 8)
+
+#define DIV_FROM_REG(val) (1 << (val))
+
+static inline u8
+DIV_TO_REG(long val)
+{
+ int i;
+ val = SENSORS_LIMIT(val, 1, 128) >> 1;
+ for (i = 0; i < 7; i++) {
+ if (val == 0)
+ break;
+ val >>= 1;
+ }
+ return ((u8) i);
+}
+
+struct w83l786ng_data {
+ struct i2c_client client;
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+ unsigned long last_nonvolatile; /* In jiffies, last time we update the
+ nonvolatile registers */
+
+ u8 in[3];
+ u8 in_max[3];
+ u8 in_min[3];
+ u8 fan[2];
+ u8 fan_div[2];
+ u8 fan_min[2];
+ u8 temp_type[2];
+ u8 temp[2][3];
+ u8 pwm[2];
+ u8 pwm_mode[2]; /* 0->DC variable voltage
+ 1->PWM variable duty cycle */
+
+ u8 pwm_enable[2]; /* 1->manual
+ 2->thermal cruise (also called SmartFan I) */
+ u8 tolerance[2];
+};
+
+static int w83l786ng_attach_adapter(struct i2c_adapter *adapter);
+static int w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind);
+static int w83l786ng_detach_client(struct i2c_client *client);
+static void w83l786ng_init_client(struct i2c_client *client);
+static struct w83l786ng_data *w83l786ng_update_device(struct device *dev);
+
+static struct i2c_driver w83l786ng_driver = {
+ .driver = {
+ .name = "w83l786ng",
+ },
+ .attach_adapter = w83l786ng_attach_adapter,
+ .detach_client = w83l786ng_detach_client,
+};
+
+static u8
+w83l786ng_read_value(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int
+w83l786ng_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/* following are the sysfs callback functions */
+#define show_in_reg(reg) \
+static ssize_t \
+show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ int nr = to_sensor_dev_attr(attr)->index; \
+ struct w83l786ng_data *data = w83l786ng_update_device(dev); \
+ return sprintf(buf,"%d\n", IN_FROM_REG(data->reg[nr])); \
+}
+
+show_in_reg(in)
+show_in_reg(in_min)
+show_in_reg(in_max)
+
+#define store_in_reg(REG, reg) \
+static ssize_t \
+store_in_##reg (struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ int nr = to_sensor_dev_attr(attr)->index; \
+ struct i2c_client *client = to_i2c_client(dev); \
+ struct w83l786ng_data *data = i2c_get_clientdata(client); \
+ unsigned long val = simple_strtoul(buf, NULL, 10); \
+ mutex_lock(&data->update_lock); \
+ data->in_##reg[nr] = IN_TO_REG(val); \
+ w83l786ng_write_value(client, W83L786NG_REG_IN_##REG(nr), \
+ data->in_##reg[nr]); \
+ mutex_unlock(&data->update_lock); \
+ return count; \
+}
+
+store_in_reg(MIN, min)
+store_in_reg(MAX, max)
+
+static struct sensor_device_attribute sda_in_input[] = {
+ SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+ SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+ SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+};
+
+static struct sensor_device_attribute sda_in_min[] = {
+ SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
+ SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
+ SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
+};
+
+static struct sensor_device_attribute sda_in_max[] = {
+ SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
+ SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
+ SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
+};
+
+#define show_fan_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ int nr = to_sensor_dev_attr(attr)->index; \
+ struct w83l786ng_data *data = w83l786ng_update_device(dev); \
+ return sprintf(buf,"%d\n", \
+ FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr]))); \
+}
+
+show_fan_reg(fan);
+show_fan_reg(fan_min);
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83l786ng_data *data = i2c_get_clientdata(client);
+ u32 val;
+
+ val = simple_strtoul(buf, NULL, 10);
+ mutex_lock(&data->update_lock);
+ data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+ w83l786ng_write_value(client, W83L786NG_REG_FAN_MIN(nr),
+ data->fan_min[nr]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct w83l786ng_data *data = w83l786ng_update_device(dev);
+ return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr]));
+}
+
+/* Note: we save and restore the fan minimum here, because its value is
+ determined in part by the fan divisor. This follows the principle of
+ least surprise; the user doesn't expect the fan minimum to change just
+ because the divisor changed. */
+static ssize_t
+store_fan_div(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83l786ng_data *data = i2c_get_clientdata(client);
+
+ unsigned long min;
+ u8 tmp_fan_div;
+ u8 fan_div_reg;
+ u8 keep_mask = 0;
+ u8 new_shift = 0;
+
+ /* Save fan_min */
+ mutex_lock(&data->update_lock);
+ min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
+
+ data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10));
+
+ switch (nr) {
+ case 0:
+ keep_mask = 0xf8;
+ new_shift = 0;
+ break;
+ case 1:
+ keep_mask = 0x8f;
+ new_shift = 4;
+ break;
+ }
+
+ fan_div_reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV)
+ & keep_mask;
+
+ tmp_fan_div = (data->fan_div[nr] << new_shift) & ~keep_mask;
+
+ w83l786ng_write_value(client, W83L786NG_REG_FAN_DIV,
+ fan_div_reg | tmp_fan_div);
+
+ /* Restore fan_min */
+ data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+ w83l786ng_write_value(client, W83L786NG_REG_FAN_MIN(nr),
+ data->fan_min[nr]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static struct sensor_device_attribute sda_fan_input[] = {
+ SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
+ SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
+};
+
+static struct sensor_device_attribute sda_fan_min[] = {
+ SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+ store_fan_min, 0),
+ SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+ store_fan_min, 1),
+};
+
+static struct sensor_device_attribute sda_fan_div[] = {
+ SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div,
+ store_fan_div, 0),
+ SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div,
+ store_fan_div, 1),
+};
+
+
+/* read/write the temperature, includes measured value and limits */
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct w83l786ng_data *data = w83l786ng_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index]));
+}
+
+static ssize_t
+store_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83l786ng_data *data = i2c_get_clientdata(client);
+ s32 val;
+
+ val = simple_strtol(buf, NULL, 10);
+ mutex_lock(&data->update_lock);
+ data->temp[nr][index] = TEMP_TO_REG(val);
+ w83l786ng_write_value(client, W83L786NG_REG_TEMP[nr][index],
+ data->temp[nr][index]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static struct sensor_device_attribute_2 sda_temp_input[] = {
+ SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
+ SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0),
+};
+
+static struct sensor_device_attribute_2 sda_temp_max[] = {
+ SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR,
+ show_temp, store_temp, 0, 1),
+ SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR,
+ show_temp, store_temp, 1, 1),
+};
+
+static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
+ SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp, store_temp, 0, 2),
+ SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp, store_temp, 1, 2),
+};
+
+#define show_pwm_reg(reg) \
+static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct w83l786ng_data *data = w83l786ng_update_device(dev); \
+ int nr = to_sensor_dev_attr(attr)->index; \
+ return sprintf(buf, "%d\n", data->reg[nr]); \
+}
+
+show_pwm_reg(pwm_mode)
+show_pwm_reg(pwm_enable)
+show_pwm_reg(pwm)
+
+static ssize_t
+store_pwm_mode(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83l786ng_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 reg;
+
+ if (val > 1)
+ return -EINVAL;
+ mutex_lock(&data->update_lock);
+ data->pwm_mode[nr] = val;
+ reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG);
+ reg &= ~(1 << W83L786NG_PWM_MODE_SHIFT[nr]);
+ if (!val)
+ reg |= 1 << W83L786NG_PWM_MODE_SHIFT[nr];
+ w83l786ng_write_value(client, W83L786NG_REG_FAN_CFG, reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83l786ng_data *data = i2c_get_clientdata(client);
+ u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
+
+ mutex_lock(&data->update_lock);
+ data->pwm[nr] = val;
+ w83l786ng_write_value(client, W83L786NG_REG_PWM[nr], val);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+store_pwm_enable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83l786ng_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ u8 reg;
+
+ if (!val || (val > 2)) /* only modes 1 and 2 are supported */
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG);
+ data->pwm_enable[nr] = val;
+ reg &= ~(0x02 << W83L786NG_PWM_ENABLE_SHIFT[nr]);
+ reg |= (val - 1) << W83L786NG_PWM_ENABLE_SHIFT[nr];
+ w83l786ng_write_value(client, W83L786NG_REG_FAN_CFG, reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static struct sensor_device_attribute sda_pwm[] = {
+ SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
+ SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
+};
+
+static struct sensor_device_attribute sda_pwm_mode[] = {
+ SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 0),
+ SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 1),
+};
+
+static struct sensor_device_attribute sda_pwm_enable[] = {
+ SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 0),
+ SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 1),
+};
+
+/* For Smart Fan I/Thermal Cruise and Smart Fan II */
+static ssize_t
+show_tolerance(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct w83l786ng_data *data = w83l786ng_update_device(dev);
+ return sprintf(buf, "%ld\n", (long)data->tolerance[nr]);
+}
+
+static ssize_t
+store_tolerance(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83l786ng_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 tol_tmp, tol_mask;
+
+ val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ tol_mask = w83l786ng_read_value(client,
+ W83L786NG_REG_TOLERANCE) & ((nr == 1) ? 0x0f : 0xf0);
+ tol_tmp = SENSORS_LIMIT(val, 0, 15);
+ tol_tmp &= 0x0f;
+ data->tolerance[nr] = tol_tmp;
+ if (nr == 1) {
+ tol_tmp <<= 4;
+ }
+
+ w83l786ng_write_value(client, W83L786NG_REG_TOLERANCE,
+ tol_mask | tol_tmp);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static struct sensor_device_attribute sda_tolerance[] = {
+ SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO,
+ show_tolerance, store_tolerance, 0),
+ SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO,
+ show_tolerance, store_tolerance, 1),
+};
+
+
+#define IN_UNIT_ATTRS(X) \
+ &sda_in_input[X].dev_attr.attr, \
+ &sda_in_min[X].dev_attr.attr, \
+ &sda_in_max[X].dev_attr.attr
+
+#define FAN_UNIT_ATTRS(X) \
+ &sda_fan_input[X].dev_attr.attr, \
+ &sda_fan_min[X].dev_attr.attr, \
+ &sda_fan_div[X].dev_attr.attr
+
+#define TEMP_UNIT_ATTRS(X) \
+ &sda_temp_input[X].dev_attr.attr, \
+ &sda_temp_max[X].dev_attr.attr, \
+ &sda_temp_max_hyst[X].dev_attr.attr
+
+#define PWM_UNIT_ATTRS(X) \
+ &sda_pwm[X].dev_attr.attr, \
+ &sda_pwm_mode[X].dev_attr.attr, \
+ &sda_pwm_enable[X].dev_attr.attr
+
+#define TOLERANCE_UNIT_ATTRS(X) \
+ &sda_tolerance[X].dev_attr.attr
+
+static struct attribute *w83l786ng_attributes[] = {
+ IN_UNIT_ATTRS(0),
+ IN_UNIT_ATTRS(1),
+ IN_UNIT_ATTRS(2),
+ FAN_UNIT_ATTRS(0),
+ FAN_UNIT_ATTRS(1),
+ TEMP_UNIT_ATTRS(0),
+ TEMP_UNIT_ATTRS(1),
+ PWM_UNIT_ATTRS(0),
+ PWM_UNIT_ATTRS(1),
+ TOLERANCE_UNIT_ATTRS(0),
+ TOLERANCE_UNIT_ATTRS(1),
+ NULL
+};
+
+static const struct attribute_group w83l786ng_group = {
+ .attrs = w83l786ng_attributes,
+};
+
+static int
+w83l786ng_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, w83l786ng_detect);
+}
+
+static int
+w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct device *dev;
+ struct w83l786ng_data *data;
+ int i, err = 0;
+ u8 reg_tmp;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ goto exit;
+ }
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ client structure, even though we cannot fill it completely yet.
+ But it allows us to access w83l786ng_{read,write}_value. */
+
+ if (!(data = kzalloc(sizeof(struct w83l786ng_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &data->client;
+ dev = &client->dev;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &w83l786ng_driver;
+
+ /*
+ * Now we do the remaining detection. A negative kind means that
+ * the driver was loaded with no force parameter (default), so we
+ * must both detect and identify the chip (actually there is only
+ * one possible kind of chip for now, W83L786NG). A zero kind means
+ * that the driver was loaded with the force parameter, the detection
+ * step shall be skipped. A positive kind means that the driver
+ * was loaded with the force parameter and a given kind of chip is
+ * requested, so both the detection and the identification steps
+ * are skipped.
+ */
+ if (kind < 0) { /* detection */
+ if (((w83l786ng_read_value(client,
+ W83L786NG_REG_CONFIG) & 0x80) != 0x00)) {
+ dev_dbg(&adapter->dev,
+ "W83L786NG detection failed at 0x%02x.\n",
+ address);
+ goto exit_free;
+ }
+ }
+
+ if (kind <= 0) { /* identification */
+ u16 man_id;
+ u8 chip_id;
+
+ man_id = (w83l786ng_read_value(client,
+ W83L786NG_REG_MAN_ID1) << 8) +
+ w83l786ng_read_value(client, W83L786NG_REG_MAN_ID2);
+ chip_id = w83l786ng_read_value(client, W83L786NG_REG_CHIP_ID);
+
+ if (man_id == 0x5CA3) { /* Winbond */
+ if (chip_id == 0x80) { /* W83L786NG */
+ kind = w83l786ng;
+ }
+ }
+
+ if (kind <= 0) { /* identification failed */
+ dev_info(&adapter->dev,
+ "Unsupported chip (man_id=0x%04X, "
+ "chip_id=0x%02X).\n", man_id, chip_id);
+ goto exit_free;
+ }
+ }
+
+ /* Fill in the remaining client fields and put into the global list */
+ strlcpy(client->name, "w83l786ng", I2C_NAME_SIZE);
+ mutex_init(&data->update_lock);
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ /* Initialize the chip */
+ w83l786ng_init_client(client);
+
+ /* A few vars need to be filled upon startup */
+ for (i = 0; i < 2; i++) {
+ data->fan_min[i] = w83l786ng_read_value(client,
+ W83L786NG_REG_FAN_MIN(i));
+ }
+
+ /* Update the fan divisor */
+ reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV);
+ data->fan_div[0] = reg_tmp & 0x07;
+ data->fan_div[1] = (reg_tmp >> 4) & 0x07;
+
+ /* Register sysfs hooks */
+ if ((err = sysfs_create_group(&client->dev.kobj, &w83l786ng_group)))
+ goto exit_remove;
+
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ return 0;
+
+ /* Unregister sysfs hooks */
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
+ i2c_detach_client(client);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int
+w83l786ng_detach_client(struct i2c_client *client)
+{
+ struct w83l786ng_data *data = i2c_get_clientdata(client);
+ int err;
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
+
+ return 0;
+}
+
+static void
+w83l786ng_init_client(struct i2c_client *client)
+{
+ u8 tmp;
+
+ if (reset)
+ w83l786ng_write_value(client, W83L786NG_REG_CONFIG, 0x80);
+
+ /* Start monitoring */
+ tmp = w83l786ng_read_value(client, W83L786NG_REG_CONFIG);
+ if (!(tmp & 0x01))
+ w83l786ng_write_value(client, W83L786NG_REG_CONFIG, tmp | 0x01);
+}
+
+static struct w83l786ng_data *w83l786ng_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83l786ng_data *data = i2c_get_clientdata(client);
+ int i, j;
+ u8 reg_tmp, pwmcfg;
+
+ mutex_lock(&data->update_lock);
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ dev_dbg(&client->dev, "Updating w83l786ng data.\n");
+
+ /* Update the voltages measured value and limits */
+ for (i = 0; i < 3; i++) {
+ data->in[i] = w83l786ng_read_value(client,
+ W83L786NG_REG_IN(i));
+ data->in_min[i] = w83l786ng_read_value(client,
+ W83L786NG_REG_IN_MIN(i));
+ data->in_max[i] = w83l786ng_read_value(client,
+ W83L786NG_REG_IN_MAX(i));
+ }
+
+ /* Update the fan counts and limits */
+ for (i = 0; i < 2; i++) {
+ data->fan[i] = w83l786ng_read_value(client,
+ W83L786NG_REG_FAN(i));
+ data->fan_min[i] = w83l786ng_read_value(client,
+ W83L786NG_REG_FAN_MIN(i));
+ }
+
+ /* Update the fan divisor */
+ reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV);
+ data->fan_div[0] = reg_tmp & 0x07;
+ data->fan_div[1] = (reg_tmp >> 4) & 0x07;
+
+ pwmcfg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG);
+ for (i = 0; i < 2; i++) {
+ data->pwm_mode[i] =
+ ((pwmcfg >> W83L786NG_PWM_MODE_SHIFT[i]) & 1)
+ ? 0 : 1;
+ data->pwm_enable[i] =
+ ((pwmcfg >> W83L786NG_PWM_ENABLE_SHIFT[i]) & 2) + 1;
+ data->pwm[i] = w83l786ng_read_value(client,
+ W83L786NG_REG_PWM[i]);
+ }
+
+
+ /* Update the temperature sensors */
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 3; j++) {
+ data->temp[i][j] = w83l786ng_read_value(client,
+ W83L786NG_REG_TEMP[i][j]);
+ }
+ }
+
+ /* Update Smart Fan I/II tolerance */
+ reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_TOLERANCE);
+ data->tolerance[0] = reg_tmp & 0x0f;
+ data->tolerance[1] = (reg_tmp >> 4) & 0x0f;
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+static int __init
+sensors_w83l786ng_init(void)
+{
+ return i2c_add_driver(&w83l786ng_driver);
+}
+
+static void __exit
+sensors_w83l786ng_exit(void)
+{
+ i2c_del_driver(&w83l786ng_driver);
+}
+
+MODULE_AUTHOR("Kevin Lo");
+MODULE_DESCRIPTION("w83l786ng driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_w83l786ng_init);
+module_exit(sensors_w83l786ng_exit);
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
index fde297b21ad..7dee001e513 100644
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -71,7 +71,6 @@ static struct i2c_driver eeprom_driver = {
.driver = {
.name = "eeprom",
},
- .id = I2C_DRIVERID_EEPROM,
.attach_adapter = eeprom_attach_adapter,
.detach_client = eeprom_detach_client,
};
diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c
index b3b830ccf20..e5b31329b56 100644
--- a/drivers/i2c/chips/pcf8574.c
+++ b/drivers/i2c/chips/pcf8574.c
@@ -67,7 +67,6 @@ static struct i2c_driver pcf8574_driver = {
.driver = {
.name = "pcf8574",
},
- .id = I2C_DRIVERID_PCF8574,
.attach_adapter = pcf8574_attach_adapter,
.detach_client = pcf8574_detach_client,
};
diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c
index 865f4409c06..66c7c3bb942 100644
--- a/drivers/i2c/chips/pcf8591.c
+++ b/drivers/i2c/chips/pcf8591.c
@@ -92,7 +92,6 @@ static struct i2c_driver pcf8591_driver = {
.driver = {
.name = "pcf8591",
},
- .id = I2C_DRIVERID_PCF8591,
.attach_adapter = pcf8591_attach_adapter,
.detach_client = pcf8591_detach_client,
};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 78cd3386176..7b5220ca7d7 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -285,4 +285,13 @@ 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/drivers/misc/Makefile b/drivers/misc/Makefile
index 1f41654aae4..7f13549cc87 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -20,3 +20,4 @@ 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/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
new file mode 100644
index 00000000000..6fcb0e96adf
--- /dev/null
+++ b/drivers/misc/enclosure.c
@@ -0,0 +1,484 @@
+/*
+ * Enclosure Services
+ *
+ * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com>
+ *
+**-----------------------------------------------------------------------------
+**
+** 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 <linux/device.h>
+#include <linux/enclosure.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+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/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 14fc7f39e83..a5f0aaaf0dd 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -179,7 +179,15 @@ config CHR_DEV_SCH
say M here and read <file:Documentation/kbuild/modules.txt> and
<file:Documentation/scsi/scsi.txt>. 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
@@ -350,17 +358,6 @@ 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
@@ -1263,17 +1260,6 @@ 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
@@ -1600,45 +1586,6 @@ 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
@@ -1666,15 +1613,6 @@ 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
- <http://amiga.resource.cx/exp/search.pl?product=oktagon>.
-
config ATARI_SCSI
tristate "Atari native SCSI support"
depends on ATARI && SCSI
@@ -1727,18 +1665,6 @@ config MAC_SCSI
SCSI-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
-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
- <http://www.tldp.org/docs.html#howto>.
-
- 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
@@ -1779,6 +1705,7 @@ 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/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 93e1428d03f..925c26b4fff 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -44,15 +44,8 @@ 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
@@ -95,7 +88,6 @@ 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
@@ -112,13 +104,12 @@ 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) += NCR53C9x.o sun3x_esp.o
+obj-$(CONFIG_SUN3X_ESP) += esp_scsi.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
@@ -138,6 +129,7 @@ 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/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
deleted file mode 100644
index 5b0efc90391..00000000000
--- a/drivers/scsi/NCR53C9x.c
+++ /dev/null
@@ -1,3654 +0,0 @@
-/* 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 <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "NCR53C9x.h"
-
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-/* 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<NUM_ESP_COMMANDS; i++)
- if(esp_cmd_strings[i].cmdchar == espcmd)
- break;
- if(i==NUM_ESP_COMMANDS)
- printk("ESP_Unknown");
- else
- printk("%s%s", esp_cmd_strings[i].text,
- ((dma_bit) ? "+DMA" : ""));
-}
-
-/* Print the status register's value */
-static inline void esp_print_statreg(unchar statreg)
-{
- unchar phase;
-
- printk("STATUS<");
- phase = statreg & ESP_STAT_PMASK;
- printk("%s,", (phase == ESP_DOP ? "DATA-OUT" :
- (phase == ESP_DIP ? "DATA-IN" :
- (phase == ESP_CMDP ? "COMMAND" :
- (phase == ESP_STATP ? "STATUS" :
- (phase == ESP_MOP ? "MSG-OUT" :
- (phase == ESP_MIP ? "MSG_IN" :
- "unknown")))))));
- if(statreg & ESP_STAT_TDONE)
- printk("TRANS_DONE,");
- if(statreg & ESP_STAT_TCNT)
- printk("TCOUNT_ZERO,");
- if(statreg & ESP_STAT_PERR)
- printk("P_ERROR,");
- if(statreg & ESP_STAT_SPAM)
- printk("SPAM,");
- if(statreg & ESP_STAT_INTR)
- printk("IRQ,");
- printk(">");
-}
-
-/* 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<<target)) || !(esp_dev->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(;j<i;j++)
- esp_write(eregs->esp_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;j<fifocnt;j++)
- p[i++] = esp_read(eregs->esp_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;j<this_count;j++)
- esp_write(eregs->esp_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<<scmd_id(SCptr)) & esp->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<<scmd_id(SCptr));
-
- /* What if the target ignores the sdtr? */
- if(esp->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<<SCptr->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<<SCptr->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/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
deleted file mode 100644
index 00a0ba040db..00000000000
--- a/drivers/scsi/NCR53C9x.h
+++ /dev/null
@@ -1,668 +0,0 @@
-/* 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 <linux/interrupt.h>
-
-/* 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 <asm/wbflush.h>
-#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/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index d7235f42cf5..bfd0e64964a 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -859,44 +859,31 @@ static int setinqserial(struct aac_dev *dev, void *data, int cid)
le32_to_cpu(dev->adapter_info.serial[0]), cid);
}
-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)
+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)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ u8 *sense_buf = (u8 *)sense_data;
+ /* Sense data valid, err code 70h */
+ sense_buf[0] = 0x70; /* No info field */
sense_buf[1] = 0; /* Segment number, always zero */
- 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[2] = sense_key; /* Sense key */
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[15] = 0;
+ sense_buf[7] = 10; /* Additional sense length */
- if (sense_code == SENCODE_INVALID_PARAM_FIELD)
- sense_buf[15] = 0x80;/* Std sense key specific field */
+ sense_buf[15] = bit_pointer;
/* 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)
@@ -906,11 +893,9 @@ 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((u8 *) &dev->fsa_dev[cid].sense_data,
- HARDWARE_ERROR,
- SENCODE_INTERNAL_TARGET_FAILURE,
- ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
- 0, 0);
+ set_sense(&dev->fsa_dev[cid].sense_data,
+ HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
+ ASENCODE_INTERNAL_TARGET_FAILURE, 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));
@@ -1520,11 +1505,9 @@ 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((u8 *) &dev->fsa_dev[cid].sense_data,
- HARDWARE_ERROR,
- SENCODE_INTERNAL_TARGET_FAILURE,
- ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
- 0, 0);
+ set_sense(&dev->fsa_dev[cid].sense_data,
+ HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
+ ASENCODE_INTERNAL_TARGET_FAILURE, 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));
@@ -1733,11 +1716,9 @@ 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((u8 *)&dev->fsa_dev[cid].sense_data,
- HARDWARE_ERROR,
- SENCODE_INTERNAL_TARGET_FAILURE,
- ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
- 0, 0);
+ set_sense(&dev->fsa_dev[cid].sense_data,
+ HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
+ ASENCODE_INTERNAL_TARGET_FAILURE, 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));
@@ -1945,10 +1926,9 @@ 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((u8 *) &dev->fsa_dev[cid].sense_data,
- ILLEGAL_REQUEST,
- SENCODE_INVALID_COMMAND,
- ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
+ set_sense(&dev->fsa_dev[cid].sense_data,
+ ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
+ ASENCODE_INVALID_COMMAND, 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));
@@ -1995,10 +1975,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
scsicmd->result = DID_OK << 16 |
COMMAND_COMPLETE << 8 |
SAM_STAT_CHECK_CONDITION;
- set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
- ILLEGAL_REQUEST,
- SENCODE_INVALID_CDB_FIELD,
- ASENCODE_NO_SENSE, 0, 7, 2, 0);
+ set_sense(&dev->fsa_dev[cid].sense_data,
+ ILLEGAL_REQUEST, SENCODE_INVALID_CDB_FIELD,
+ ASENCODE_NO_SENSE, 7, 2);
memcpy(scsicmd->sense_buffer,
&dev->fsa_dev[cid].sense_data,
min_t(size_t,
@@ -2254,9 +2233,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((u8 *) &dev->fsa_dev[cid].sense_data,
- ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
- ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
+ set_sense(&dev->fsa_dev[cid].sense_data,
+ ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
+ ASENCODE_INVALID_COMMAND, 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/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index f8afa358b6b..abef05146d7 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -243,6 +243,7 @@ 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;
@@ -251,24 +252,25 @@ 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
@@ -414,8 +416,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)
@@ -463,7 +465,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;
@@ -517,11 +519,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));
@@ -786,9 +788,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/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index fb0886140dd..e80d2a0c46a 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -1130,31 +1130,29 @@ 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) &&
- (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;
+ (shost->sg_tablesize > 34)) {
+ shost->sg_tablesize = 34;
+ shost->max_sectors = (shost->sg_tablesize * 8) + 112;
}
if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) &&
- (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;
+ (shost->sg_tablesize > 17)) {
+ shost->sg_tablesize = 17;
+ shost->max_sectors = (shost->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;
+
/*
- * Firware printf works only with older firmware.
+ * Firmware printf works only with older firmware.
*/
if (aac_drivers[index].quirks & AAC_QUIRK_34SG)
aac->printf_enabled = 1;
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 374ed025dc5..ccef891d642 100644
--- a/drivers/scsi/advansys.c
+++ b/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'.
*/
-void __devinit
+static 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'.
*/
-void __devinit
+static 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'.
*/
-void __devinit
+static void __devinit
AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
{
ushort *wbuf;
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index a67e29f83ae..57786502e3e 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/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/08/30"
+#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/12/24"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
#define ARCMSR_MAX_XFER_SECTORS_B 4096
@@ -248,6 +248,7 @@ 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 */
@@ -256,6 +257,7 @@ 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/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index f4a202e8df2..4f9ff32cfed 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -315,9 +315,6 @@ 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++) {
@@ -371,8 +368,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,
- acb->dma_coherent, acb->dma_coherent_handle);
+ (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 +
+ sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle);
return -ENOMEM;
}
@@ -509,6 +506,7 @@ 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);
@@ -748,6 +746,7 @@ 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);
}
@@ -886,7 +885,7 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \
}
}
-static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
+static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd)
{
struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
@@ -906,6 +905,8 @@ static void 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) {
@@ -946,6 +947,7 @@ static void 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)
@@ -1036,18 +1038,22 @@ 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)
@@ -1273,7 +1279,9 @@ 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);
}
@@ -1380,12 +1388,13 @@ 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;
- ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
- if (!ver_addr) {
+ tmp = kmalloc(1032, GFP_KERNEL|GFP_DMA);
+ ver_addr = (unsigned long *)tmp;
+ if (!tmp) {
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
}
@@ -1421,18 +1430,19 @@ 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;
- pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
+ kfree(tmp);
}
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;
- ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
- if (!ver_addr) {
+ tmp = kmalloc(1032, GFP_KERNEL|GFP_DMA);
+ ver_addr = (unsigned long *)tmp;
+ if (!tmp) {
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
}
@@ -1482,7 +1492,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
retvalue = ARCMSR_MESSAGE_FAIL;
}
}
- pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
+ kfree(tmp);
}
break;
@@ -1682,8 +1692,11 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
ccb = arcmsr_get_freeccb(acb);
if (!ccb)
return SCSI_MLQUEUE_HOST_BUSY;
-
- arcmsr_build_ccb(acb, ccb, cmd);
+ if ( arcmsr_build_ccb( acb, ccb, cmd ) == FAILED ) {
+ cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1);
+ cmd->scsi_done(cmd);
+ return 0;
+ }
arcmsr_post_ccb(acb, ccb);
return 0;
}
@@ -1844,7 +1857,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;
@@ -1878,7 +1891,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) {
+ if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
printk(KERN_NOTICE "arcmsr%d: \
scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n"
,acb->host->host_no
@@ -1901,7 +1914,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) {
@@ -2026,6 +2039,7 @@ 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;
}
@@ -2090,19 +2104,39 @@ 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;
- arcmsr_wait_firmware_ready(acb);
- arcmsr_iop_confirm(acb);
/* disable all outbound interrupt */
intmask_org = arcmsr_disable_outbound_ints(acb);
+ arcmsr_wait_firmware_ready(acb);
+ arcmsr_iop_confirm(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;
@@ -2275,6 +2309,7 @@ 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/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index eceacf6d49e..3bedf2466bd 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -1790,7 +1790,7 @@ int acornscsi_starttransfer(AS_Host *host)
return 0;
}
- residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred;
+ residual = scsi_bufflen(host->SCpnt) - 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 = host->SCpnt->request_bufflen -
+ host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -
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 = host->SCpnt->request_bufflen -
+ host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -
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 = host->SCpnt->request_bufflen -
+ host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -
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 = host->SCpnt->request_bufflen -
+ host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -
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 = host->SCpnt->request_bufflen -
+ host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -
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 = host->SCpnt->request_bufflen -
+ host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) -
acornscsi_sbic_xfcount(host);
acornscsi_dma_stop(host);
acornscsi_dma_adjust(host);
diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
index bb6550e3192..138a521ba1a 100644
--- a/drivers/scsi/arm/scsi.h
+++ b/drivers/scsi/arm/scsi.h
@@ -18,17 +18,32 @@
* 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)
- memcpy(sg + 1, SCp->buffer + 1,
- sizeof(struct scatterlist) * bufs);
+ 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);
+ }
+
return bufs + 1;
}
@@ -36,7 +51,7 @@ static inline int next_SCp(struct scsi_pointer *SCp)
{
int ret = SCp->buffers_residual;
if (ret) {
- SCp->buffer++;
+ SCp->buffer = sg_next(SCp->buffer);
SCp->buffers_residual--;
SCp->ptr = sg_virt(SCp->buffer);
SCp->this_residual = SCp->buffer->length;
@@ -68,46 +83,46 @@ static inline void init_SCp(struct scsi_cmnd *SCpnt)
{
memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer));
- if (SCpnt->use_sg) {
+ if (scsi_bufflen(SCpnt)) {
unsigned long len = 0;
- int buf;
- SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
- SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+ SCpnt->SCp.buffer = scsi_sglist(SCpnt);
+ SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
SCpnt->SCp.ptr = sg_virt(SCpnt->SCp.buffer);
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
- SCpnt->SCp.phase = SCpnt->request_bufflen;
+ SCpnt->SCp.phase = scsi_bufflen(SCpnt);
#ifdef BELT_AND_BRACES
- /*
- * 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;
+ { /*
+ * 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));
+ }
+ }
#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/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c
deleted file mode 100644
index 23f7c24ab80..00000000000
--- a/drivers/scsi/blz1230.c
+++ /dev/null
@@ -1,353 +0,0 @@
-/* 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 <linux/module.h>
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/interrupt.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "NCR53C9x.h"
-
-#include <linux/zorro.h>
-#include <asm/irq.h>
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-
-#include <asm/pgtable.h>
-
-#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/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c
deleted file mode 100644
index b6203ec0096..00000000000
--- a/drivers/scsi/blz2060.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/* 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 <linux/module.h>
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/interrupt.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "NCR53C9x.h"
-
-#include <linux/zorro.h>
-#include <asm/irq.h>
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-
-#include <asm/pgtable.h>
-
-/* 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/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c
deleted file mode 100644
index c6b98a42e89..00000000000
--- a/drivers/scsi/cyberstorm.c
+++ /dev/null
@@ -1,377 +0,0 @@
-/* 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 <linux/module.h>
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/interrupt.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "NCR53C9x.h"
-
-#include <linux/zorro.h>
-#include <asm/irq.h>
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-
-#include <asm/pgtable.h>
-
-/* 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/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c
deleted file mode 100644
index e336e853e66..00000000000
--- a/drivers/scsi/cyberstormII.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/* 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 <linux/module.h>
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/interrupt.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "NCR53C9x.h"
-
-#include <linux/zorro.h>
-#include <asm/irq.h>
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-
-#include <asm/pgtable.h>
-
-/* 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/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 22ef3716e78..e351db6c007 100644
--- a/drivers/scsi/dc395x.c
+++ b/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 *ptr;
+ struct SGentry *uninitialized_var(ptr);
for (i = 0; i < DC395x_MAX_SRB_CNT; i++)
acb->srb_array[i].segment_x = NULL;
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
deleted file mode 100644
index d42ad663ffe..00000000000
--- a/drivers/scsi/dec_esp.c
+++ /dev/null
@@ -1,687 +0,0 @@
-/*
- * 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 <flo@rfc822.org>
- * 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 <flo@rfc822.org>
- *
- * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki
- */
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/stat.h>
-#include <linux/tc.h>
-
-#include <asm/dma.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-
-#include <asm/dec/interrupts.h>
-#include <asm/dec/ioasic.h>
-#include <asm/dec/ioasic_addrs.h>
-#include <asm/dec/ioasic_ints.h>
-#include <asm/dec/machtype.h>
-#include <asm/dec/system.h>
-
-#define DEC_SCSI_SREG 0
-#define DEC_SCSI_DMAREG 0x40000
-#define DEC_SCSI_SRAM 0x80000
-#define DEC_SCSI_DIAG 0xC0000
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#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/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c
deleted file mode 100644
index 4266a2139b5..00000000000
--- a/drivers/scsi/fastlane.c
+++ /dev/null
@@ -1,421 +0,0 @@
-/* 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 <linux/module.h>
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/interrupt.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "NCR53C9x.h"
-
-#include <linux/zorro.h>
-#include <asm/irq.h>
-
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-
-#include <asm/pgtable.h>
-
-/* 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/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index b6f99dfbb03..8a178674cb1 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -629,8 +629,9 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
int rc;
if (tcp_conn->in.datalen) {
- printk(KERN_ERR "iscsi_tcp: invalid R2t with datalen %d\n",
- tcp_conn->in.datalen);
+ iscsi_conn_printk(KERN_ERR, conn,
+ "invalid R2t with datalen %d\n",
+ tcp_conn->in.datalen);
return ISCSI_ERR_DATALEN;
}
@@ -644,8 +645,9 @@ 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) {
- printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in "
- "recovery...\n", ctask->itt);
+ iscsi_conn_printk(KERN_INFO, conn,
+ "dropping R2T itt %d in recovery.\n",
+ ctask->itt);
return 0;
}
@@ -655,7 +657,8 @@ 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) {
- printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n");
+ iscsi_conn_printk(KERN_ERR, conn,
+ "invalid R2T with zero data len\n");
__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
sizeof(void*));
return ISCSI_ERR_DATALEN;
@@ -668,9 +671,10 @@ 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)) {
- 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));
+ 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));
__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
sizeof(void*));
return ISCSI_ERR_DATALEN;
@@ -736,8 +740,9 @@ 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) {
- printk(KERN_ERR "iscsi_tcp: datalen %d > %d\n",
- 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);
return ISCSI_ERR_DATALEN;
}
@@ -819,10 +824,12 @@ 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) {
- 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);
+ 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);
rc = ISCSI_ERR_PROTO;
break;
}
@@ -1496,30 +1503,25 @@ 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)) {
- 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));
+ if (IS_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)) {
- 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));
+ if (IS_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);
@@ -1627,7 +1629,8 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
/* lookup for existing socket */
sock = sockfd_lookup((int)transport_eph, &err);
if (!sock) {
- printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err);
+ iscsi_conn_printk(KERN_ERR, conn,
+ "sockfd_lookup failed %d\n", err);
return -EEXIST;
}
/*
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 553168ae44f..59f8445eab0 100644
--- a/drivers/scsi/libiscsi.c
+++ b/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, conn->id, session->age);
+ hdr->itt = build_itt(ctask->itt, session->age);
hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
hdr->cmdsn = cpu_to_be32(session->cmdsn);
session->cmdsn++;
@@ -416,8 +416,9 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (datalen < 2) {
invalid_datalen:
- printk(KERN_ERR "iscsi: Got CHECK_CONDITION but "
- "invalid data buffer size of %d\n", datalen);
+ iscsi_conn_printk(KERN_ERR, conn,
+ "Got CHECK_CONDITION but invalid data "
+ "buffer size of %d\n", datalen);
sc->result = DID_BAD_TARGET << 16;
goto out;
}
@@ -494,7 +495,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) {
- printk(KERN_ERR "Could not send nopout\n");
+ iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
return;
}
@@ -522,9 +523,10 @@ 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);
- printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected "
- "due to DataDigest error.\n", itt,
- rejected_pdu.opcode);
+ iscsi_conn_printk(KERN_ERR, conn,
+ "itt 0x%x had pdu (op 0x%x) rejected "
+ "due to DataDigest error.\n", itt,
+ rejected_pdu.opcode);
}
}
return 0;
@@ -541,8 +543,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.
*/
-int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- char *data, int datalen)
+static 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;
@@ -672,7 +674,6 @@ 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)
@@ -697,18 +698,13 @@ 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)) {
- printk(KERN_ERR "iscsi: received itt %x expected "
- "session age (%x)\n", (__force u32)hdr->itt,
- session->age & ISCSI_AGE_MASK);
+ iscsi_conn_printk(KERN_ERR, conn,
+ "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;
@@ -717,16 +713,17 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
ctask = session->cmds[itt];
if (!ctask->sc) {
- printk(KERN_INFO "iscsi: dropping ctask with "
- "itt 0x%x\n", ctask->itt);
+ iscsi_conn_printk(KERN_INFO, conn, "dropping ctask "
+ "with itt 0x%x\n", ctask->itt);
/* force drop */
return ISCSI_ERR_NO_SCSI_CMD;
}
if (ctask->sc->SCp.phase != session->age) {
- printk(KERN_ERR "iscsi: ctask's session age %d, "
- "expected %d\n", 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);
return ISCSI_ERR_SESSION_FAILED;
}
}
@@ -771,7 +768,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, conn->id, session->age);
+ hdr->itt = build_itt(mtask->itt, session->age);
/*
* TODO: We always use immediate, so we never hit this.
* If we start to send tmfs or nops as non-immediate then
@@ -997,6 +994,7 @@ 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 *))
@@ -1017,6 +1015,12 @@ 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
@@ -1033,18 +1037,23 @@ 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;
- goto reject;
+ sc->result = DID_IMM_RETRY << 16;
+ break;
case ISCSI_STATE_LOGGING_OUT:
reason = FAILURE_SESSION_LOGGING_OUT;
- goto reject;
+ sc->result = DID_IMM_RETRY << 16;
+ break;
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;
}
@@ -1052,6 +1061,7 @@ 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;
}
@@ -1091,9 +1101,7 @@ reject:
fault:
spin_unlock(&session->lock);
- printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n",
- sc->cmnd[0], reason);
- sc->result = (DID_NO_CONNECT << 16);
+ debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason);
scsi_set_resid(sc, scsi_bufflen(sc));
sc->scsi_done(sc);
spin_lock(host->host_lock);
@@ -1160,7 +1168,8 @@ failed:
mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->lock);
if (session->state == ISCSI_STATE_LOGGED_IN)
- printk(KERN_INFO "iscsi: host reset succeeded\n");
+ iscsi_session_printk(KERN_INFO, session,
+ "host reset succeeded\n");
else
goto failed;
spin_unlock_bh(&session->lock);
@@ -1239,7 +1248,8 @@ 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)
+static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
+ int error)
{
struct iscsi_cmd_task *ctask, *tmp;
@@ -1251,7 +1261,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, DID_BUS_BUSY << 16);
+ fail_command(conn, ctask, error << 16);
}
}
@@ -1259,7 +1269,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, DID_BUS_BUSY << 16);
+ fail_command(conn, ctask, error << 16);
}
}
@@ -1357,10 +1367,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)) {
- 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);
+ 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);
spin_unlock(&session->lock);
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return;
@@ -1373,14 +1383,11 @@ 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;
- }
- if (next_timeout) {
- debug_scsi("Setting next tmo %lu\n", next_timeout);
- mod_timer(&conn->transport_timer, next_timeout);
- }
+ debug_scsi("Setting next tmo %lu\n", next_timeout);
+ mod_timer(&conn->transport_timer, next_timeout);
done:
spin_unlock(&session->lock);
}
@@ -1573,7 +1580,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);
+ fail_all_commands(conn, sc->device->lun, DID_ERROR);
conn->tmf_state = TMF_INITIAL;
spin_unlock(&session->lock);
write_unlock_bh(conn->recv_lock);
@@ -1944,9 +1951,10 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
}
spin_unlock_irqrestore(session->host->host_lock, flags);
msleep_interruptible(500);
- printk(KERN_INFO "iscsi: scsi conn_destroy(): host_busy %d "
- "host_failed %d\n", session->host->host_busy,
- session->host->host_failed);
+ iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): "
+ "host_busy %d host_failed %d\n",
+ session->host->host_busy,
+ session->host->host_failed);
/*
* force eh_abort() to unblock
*/
@@ -1975,27 +1983,28 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
struct iscsi_session *session = conn->session;
if (!session) {
- printk(KERN_ERR "iscsi: can't start unbound connection\n");
+ iscsi_conn_printk(KERN_ERR, conn,
+ "can't start unbound connection\n");
return -EPERM;
}
if ((session->imm_data_en || !session->initial_r2t_en) &&
session->first_burst > session->max_burst) {
- printk("iscsi: invalid burst lengths: "
- "first_burst %d max_burst %d\n",
- 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);
return -EINVAL;
}
if (conn->ping_timeout && !conn->recv_timeout) {
- printk(KERN_ERR "iscsi: invalid recv timeout of zero "
- "Using 5 seconds\n.");
+ iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of "
+ "zero. Using 5 seconds\n.");
conn->recv_timeout = 5;
}
if (conn->recv_timeout && !conn->ping_timeout) {
- printk(KERN_ERR "iscsi: invalid ping timeout of zero "
- "Using 5 seconds.\n");
+ iscsi_conn_printk(KERN_ERR, conn, "invalid ping timeout of "
+ "zero. Using 5 seconds.\n");
conn->ping_timeout = 5;
}
@@ -2019,11 +2028,9 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
conn->stop_stage = 0;
conn->tmf_state = TMF_INITIAL;
session->age++;
- spin_unlock_bh(&session->lock);
-
- iscsi_unblock_session(session_to_cls(session));
- wake_up(&conn->ehwait);
- return 0;
+ if (session->age == 16)
+ session->age = 0;
+ break;
case STOP_CONN_TERM:
conn->stop_stage = 0;
break;
@@ -2032,6 +2039,8 @@ 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);
@@ -2123,7 +2132,8 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
* flush queues.
*/
spin_lock_bh(&session->lock);
- fail_all_commands(conn, -1);
+ fail_all_commands(conn, -1,
+ STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR);
flush_control_queues(session, conn);
spin_unlock_bh(&session->lock);
mutex_unlock(&session->eh_mutex);
@@ -2140,7 +2150,8 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
iscsi_start_session_recovery(session, conn, flag);
break;
default:
- printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);
+ iscsi_conn_printk(KERN_ERR, conn,
+ "invalid stop flag %d\n", flag);
}
}
EXPORT_SYMBOL_GPL(iscsi_conn_stop);
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
deleted file mode 100644
index bcb49021b7e..00000000000
--- a/drivers/scsi/mac_esp.c
+++ /dev/null
@@ -1,751 +0,0 @@
-/*
- * 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 <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "NCR53C9x.h"
-
-#include <asm/io.h>
-
-#include <asm/setup.h>
-#include <asm/irq.h>
-#include <asm/macints.h>
-#include <asm/machw.h>
-#include <asm/mac_via.h>
-
-#include <asm/pgtable.h>
-
-#include <asm/macintosh.h>
-
-/* #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=<num_esps>,<disconnect>,<nosync>,<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
- * 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/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c
deleted file mode 100644
index d693d0f2139..00000000000
--- a/drivers/scsi/mca_53c9x.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/* 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 <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/mca.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/mca-legacy.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "NCR53C9x.h"
-
-#include <asm/dma.h>
-#include <asm/irq.h>
-#include <asm/mca_dma.h>
-#include <asm/pgtable.h>
-
-/*
- * 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 <disabled>
- * 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 : <disabled>
- * 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/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
deleted file mode 100644
index 8e5eadbd5c5..00000000000
--- a/drivers/scsi/oktagon_esp.c
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * 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 <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/reboot.h>
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <asm/pgtable.h>
-
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "NCR53C9x.h"
-
-#include <linux/zorro.h>
-#include <asm/irq.h>
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-
-#ifdef USE_BOTTOM_HALF
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#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/drivers/scsi/oktagon_io.S b/drivers/scsi/oktagon_io.S
deleted file mode 100644
index 8a7340b0270..00000000000
--- a/drivers/scsi/oktagon_io.S
+++ /dev/null
@@ -1,194 +0,0 @@
-/* -*- 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 <kcozens@interlog.com>
-*/
-
-#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/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c
index 17b4a7c4618..0cd614a0fa7 100644
--- a/drivers/scsi/ps3rom.c
+++ b/drivers/scsi/ps3rom.c
@@ -35,7 +35,7 @@
#define BOUNCE_SIZE (64*1024)
-#define PS3ROM_MAX_SECTORS (BOUNCE_SIZE / CD_FRAMESIZE)
+#define PS3ROM_MAX_SECTORS (BOUNCE_SIZE >> 9)
struct ps3rom_private {
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index adf97320574..4894dc886b6 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -428,6 +428,19 @@ 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) {
@@ -835,7 +848,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 = shost_priv(shost);
+ scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost));
uint32_t speed = 0;
switch (ha->link_data_rate) {
@@ -848,6 +861,9 @@ 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;
}
@@ -855,7 +871,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 = shost_priv(shost);
+ scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost));
uint32_t port_type = FC_PORTTYPE_UNKNOWN;
switch (ha->current_topology) {
@@ -965,7 +981,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 = shost_priv(shost);
+ scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost));
int rval;
struct link_statistics *stats;
dma_addr_t stats_dma;
@@ -1049,7 +1065,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 = shost_priv(shost);
+ scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost));
if (!ha->flags.online)
fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index b72c7f17085..3750319f496 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2041,8 +2041,6 @@ 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/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index ba35fc26ce6..193f688ec3d 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -66,6 +66,7 @@ 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/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index d0633ca894b..d5c7853e7eb 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -925,6 +925,16 @@ 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(&reg->hccr, (HCCR_ENABLE_PARITY + 0x0));
+ RD_REG_WORD(&reg->hccr);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ }
/* Load firmware sequences */
rval = ha->isp_ops->load_risc(ha, &srisc_address);
@@ -968,6 +978,19 @@ 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(&reg->hccr, HCCR_ENABLE_PARITY + 0x1);
+ else
+ /* SRAM, Instruction RAM and GP RAM parity */
+ WRT_REG_WORD(&reg->hccr, HCCR_ENABLE_PARITY + 0x7);
+ RD_REG_WORD(&reg->hccr);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ }
+
if (rval) {
DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
ha->host_no));
@@ -3213,9 +3236,6 @@ 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) {
@@ -3236,19 +3256,8 @@ 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. */
- 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);
+ qla2x00_abort_all_cmds(ha, DID_RESET << 16);
ha->isp_ops->get_flash_version(ha, ha->request_ring);
@@ -3273,6 +3282,7 @@ 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) {
@@ -3357,60 +3367,15 @@ 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 (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(&reg->hccr,
- (HCCR_ENABLE_PARITY + 0x0));
- RD_REG_WORD(&reg->hccr);
- }
-
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
+ if (!(status = ha->isp_ops->chip_diag(ha)))
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(&reg->hccr,
- (HCCR_ENABLE_PARITY + 0x1));
- else
- /*
- * SRAM, Instruction RAM and GP RAM
- * parity.
- */
- WRT_REG_WORD(&reg->hccr,
- (HCCR_ENABLE_PARITY + 0x7));
- RD_REG_WORD(&reg->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/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 8e3b04464cf..5d1a3f7c408 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -119,6 +119,13 @@ 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/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 642a0c3f09c..14e6f22944b 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1815,6 +1815,8 @@ 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))
@@ -1846,7 +1848,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));
- return ret;
+ goto clear_risc_ints;
}
qla_printk(KERN_WARNING, ha,
"MSI-X: Falling back-to INTa mode -- %d.\n", ret);
@@ -1864,15 +1866,30 @@ skip_msi:
ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
- if (!ret) {
- ha->flags.inta_enabled = 1;
- ha->host->irq = ha->pdev->irq;
- } else {
+ if (ret) {
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(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
+ WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
+ } else {
+ WRT_REG_WORD(&reg->isp.semaphore, 0);
+ WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_RISC_INT);
+ WRT_REG_WORD(&reg->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/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 0c10c0b0fb7..99d29fff836 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/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->fw_attributes & BIT_2)
+ if (ha->flags.npiv_supported)
mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE;
else
mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 8f69caf8327..3c1b43356ad 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -204,10 +204,8 @@ static int qla2x00_do_dpc(void *data);
static void qla2x00_rst_aen(scsi_qla_host_t *);
-static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+static int 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 *);
/* -------------------------------------------------------------------------- */
@@ -1117,6 +1115,27 @@ 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)
{
@@ -1557,10 +1576,8 @@ 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;
@@ -1608,6 +1625,7 @@ 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);
@@ -1621,8 +1639,6 @@ 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;
@@ -1751,34 +1767,6 @@ 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(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
- WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
- } else {
- WRT_REG_WORD(&reg->isp.semaphore, 0);
- WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_RISC_INT);
- WRT_REG_WORD(&reg->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(&reg->isp.hccr,
- (HCCR_ENABLE_PARITY + 0x1));
- else
- /* SRAM, Instruction RAM and GP RAM parity */
- WRT_REG_WORD(&reg->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;
@@ -1848,10 +1836,14 @@ 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;
@@ -1870,8 +1862,6 @@ 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);
@@ -2010,196 +2000,109 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
*
* Returns:
* 0 = success.
-* 1 = failure.
+* !0 = failure.
*/
-static uint8_t
+static int
qla2x00_mem_alloc(scsi_qla_host_t *ha)
{
char name[16];
- uint8_t status = 1;
- int retry= 10;
-
- 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");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
-
- 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");
-
- 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);
+ 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;
- 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);
+ 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;
- if (status) {
- printk(KERN_WARNING
- "%s(): **** FAILED ****\n", __func__);
+ /* 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;
}
- return(status);
+ return 0;
+
+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;
}
/*
@@ -2215,14 +2118,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
struct list_head *fcpl, *fcptemp;
fc_port_t *fcport;
- if (ha == NULL) {
- /* error */
- DEBUG2(printk("%s(): ERROR invalid ha pointer.\n", __func__));
- return;
- }
-
- /* free sp pool */
- qla2x00_free_sp_pool(ha);
+ if (ha->srb_mempool)
+ mempool_destroy(ha->srb_mempool);
if (ha->fce)
dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
@@ -2270,6 +2167,7 @@ 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;
@@ -2308,44 +2206,6 @@ 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
@@ -2367,6 +2227,9 @@ 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;
@@ -2409,6 +2272,18 @@ 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));
}
@@ -3029,3 +2904,4 @@ 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/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index b68fb73613e..26822c8807e 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -893,6 +893,8 @@ 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)
{
@@ -902,15 +904,12 @@ 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(&reg->gpioe);
- gpio_data = RD_REG_WORD_PIO(&reg->gpiod);
+ gpio_enable = RD_REG_WORD_PIO(PIO_REG(ha, gpioe));
+ gpio_data = RD_REG_WORD_PIO(PIO_REG(ha, gpiod));
} else {
gpio_enable = RD_REG_WORD(&reg->gpioe);
gpio_data = RD_REG_WORD(&reg->gpiod);
@@ -920,7 +919,7 @@ qla2x00_beacon_blink(struct scsi_qla_host *ha)
gpio_enable |= GPIO_LED_MASK;
if (ha->pio_address) {
- WRT_REG_WORD_PIO(&reg->gpioe, gpio_enable);
+ WRT_REG_WORD_PIO(PIO_REG(ha, gpioe), gpio_enable);
} else {
WRT_REG_WORD(&reg->gpioe, gpio_enable);
RD_REG_WORD(&reg->gpioe);
@@ -936,7 +935,7 @@ qla2x00_beacon_blink(struct scsi_qla_host *ha)
/* Set the modified gpio_data values */
if (ha->pio_address) {
- WRT_REG_WORD_PIO(&reg->gpiod, gpio_data);
+ WRT_REG_WORD_PIO(PIO_REG(ha, gpiod), gpio_data);
} else {
WRT_REG_WORD(&reg->gpiod, gpio_data);
RD_REG_WORD(&reg->gpiod);
@@ -962,14 +961,11 @@ 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(&reg->gpioe);
- gpio_data = RD_REG_WORD_PIO(&reg->gpiod);
+ gpio_enable = RD_REG_WORD_PIO(PIO_REG(ha, gpioe));
+ gpio_data = RD_REG_WORD_PIO(PIO_REG(ha, gpiod));
} else {
gpio_enable = RD_REG_WORD(&reg->gpioe);
gpio_data = RD_REG_WORD(&reg->gpiod);
@@ -978,7 +974,7 @@ qla2x00_beacon_on(struct scsi_qla_host *ha)
/* Set the modified gpio_enable values. */
if (ha->pio_address) {
- WRT_REG_WORD_PIO(&reg->gpioe, gpio_enable);
+ WRT_REG_WORD_PIO(PIO_REG(ha, gpioe), gpio_enable);
} else {
WRT_REG_WORD(&reg->gpioe, gpio_enable);
RD_REG_WORD(&reg->gpioe);
@@ -987,7 +983,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(&reg->gpiod, gpio_data);
+ WRT_REG_WORD_PIO(PIO_REG(ha, gpiod), gpio_data);
} else {
WRT_REG_WORD(&reg->gpiod, gpio_data);
RD_REG_WORD(&reg->gpiod);
@@ -1244,13 +1240,12 @@ qla2x00_read_flash_byte(scsi_qla_host_t *ha, uint32_t addr)
if (ha->pio_address) {
uint16_t data2;
- reg = (struct device_reg_2xxx __iomem *)ha->pio_address;
- WRT_REG_WORD_PIO(&reg->flash_address, (uint16_t)addr);
+ WRT_REG_WORD_PIO(PIO_REG(ha, flash_address), (uint16_t)addr);
do {
- data = RD_REG_WORD_PIO(&reg->flash_data);
+ data = RD_REG_WORD_PIO(PIO_REG(ha, flash_data));
barrier();
cpu_relax();
- data2 = RD_REG_WORD_PIO(&reg->flash_data);
+ data2 = RD_REG_WORD_PIO(PIO_REG(ha, flash_data));
} while (data != data2);
} else {
WRT_REG_WORD(&reg->flash_address, (uint16_t)addr);
@@ -1304,9 +1299,8 @@ 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) {
- reg = (struct device_reg_2xxx __iomem *)ha->pio_address;
- WRT_REG_WORD_PIO(&reg->flash_address, (uint16_t)addr);
- WRT_REG_WORD_PIO(&reg->flash_data, (uint16_t)data);
+ WRT_REG_WORD_PIO(PIO_REG(ha, flash_address), (uint16_t)addr);
+ WRT_REG_WORD_PIO(PIO_REG(ha, flash_data), (uint16_t)data);
} else {
WRT_REG_WORD(&reg->flash_address, (uint16_t)addr);
RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 2c2f6b4697c..c5742cc15ab 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.02.00-k7"
+#define QLA2XXX_VERSION "8.02.00-k8"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 2
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 49925f92555..10b3b9a620f 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -1306,6 +1306,7 @@ 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/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 2e2b9fedffc..c3c59d76303 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -63,8 +63,6 @@ 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);
/*
@@ -91,6 +89,8 @@ 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,8 +116,6 @@ 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,
};
@@ -128,48 +126,19 @@ 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;
- 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);
-}
-
-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;
+ if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
+ atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
- session = iscsi_dev_to_session(conn->dev.parent);
- ddb_entry = session->dd_data;
+ 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] 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);
+ 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_host_get_param(struct Scsi_Host *shost,
@@ -308,6 +277,9 @@ 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;
}
@@ -364,6 +336,7 @@ 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);
}
@@ -430,9 +403,21 @@ 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;
@@ -1323,7 +1308,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/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index b35d19472ca..fecba05b4e7 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -969,9 +969,10 @@ 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/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index f243fc30c90..135c1d05470 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -301,7 +301,6 @@ 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/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 0d7b4e79415..fac7534f3ec 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -30,10 +30,10 @@
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/iscsi_if.h>
-#define ISCSI_SESSION_ATTRS 18
-#define ISCSI_CONN_ATTRS 11
+#define ISCSI_SESSION_ATTRS 19
+#define ISCSI_CONN_ATTRS 13
#define ISCSI_HOST_ATTRS 4
-#define ISCSI_TRANSPORT_VERSION "2.0-867"
+#define ISCSI_TRANSPORT_VERSION "2.0-868"
struct iscsi_internal {
int daemon_pid;
@@ -127,12 +127,13 @@ 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->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d",
+ snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d",
shost->host_no);
- ihost->unbind_workq = create_singlethread_workqueue(
- ihost->unbind_workq_name);
- if (!ihost->unbind_workq)
+ ihost->scan_workq = create_singlethread_workqueue(
+ ihost->scan_workq_name);
+ if (!ihost->scan_workq)
return -ENOMEM;
return 0;
}
@@ -143,7 +144,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->unbind_workq);
+ destroy_workqueue(ihost->scan_workq);
return 0;
}
@@ -221,6 +222,54 @@ 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);
@@ -236,6 +285,25 @@ 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)
{
@@ -254,14 +322,50 @@ 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);
- dev_printk(KERN_INFO, &session->dev, "iscsi: 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);
if (session->transport->session_recovery_timedout)
session->transport->session_recovery_timedout(session);
@@ -269,16 +373,44 @@ 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);
@@ -311,7 +443,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->unbind_workq, &session->unbind_work);
+ return queue_work(ihost->scan_workq, &session->unbind_work);
}
struct iscsi_cls_session *
@@ -327,10 +459,13 @@ 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);
@@ -358,8 +493,8 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
session->sid);
err = device_add(&session->dev);
if (err) {
- dev_printk(KERN_ERR, &session->dev, "iscsi: could not "
- "register session's dev\n");
+ iscsi_cls_session_printk(KERN_ERR, session,
+ "could not register session's dev\n");
goto release_host;
}
transport_register_device(&session->dev);
@@ -444,22 +579,28 @@ 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.
*/
- iscsi_unblock_session(session);
- iscsi_unbind_session(session);
+ 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);
/*
* 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)
- dev_printk(KERN_ERR, &session->dev, "iscsi: Could not delete "
- "all connections for session. Error %d.\n", err);
+ iscsi_cls_session_printk(KERN_ERR, session,
+ "Could not delete all connections "
+ "for session. Error %d.\n", err);
transport_unregister_device(&session->dev);
device_del(&session->dev);
@@ -531,8 +672,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) {
- dev_printk(KERN_ERR, &conn->dev, "iscsi: could not register "
- "connection's dev\n");
+ iscsi_cls_session_printk(KERN_ERR, session, "could not "
+ "register connection's dev\n");
goto release_parent_ref;
}
transport_register_device(&conn->dev);
@@ -639,8 +780,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);
- dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver "
- "control PDU: OOM\n");
+ iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver "
+ "control PDU: OOM\n");
return -ENOMEM;
}
@@ -661,20 +802,27 @@ 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) {
- dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored "
- "conn error (%d)\n", error);
+ iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored "
+ "conn error (%d)\n", error);
return;
}
@@ -688,8 +836,8 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error)
iscsi_broadcast_skb(skb, GFP_ATOMIC);
- dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n",
- error);
+ iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n",
+ error);
}
EXPORT_SYMBOL_GPL(iscsi_conn_error);
@@ -744,8 +892,8 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
skbstat = alloc_skb(len, GFP_ATOMIC);
if (!skbstat) {
- dev_printk(KERN_ERR, &conn->dev, "iscsi: can not "
- "deliver stats: OOM\n");
+ iscsi_cls_conn_printk(KERN_ERR, conn, "can not "
+ "deliver stats: OOM\n");
return -ENOMEM;
}
@@ -801,8 +949,9 @@ int iscsi_session_event(struct iscsi_cls_session *session,
skb = alloc_skb(len, GFP_KERNEL);
if (!skb) {
- dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace "
- "of session event %u\n", event);
+ iscsi_cls_session_printk(KERN_ERR, session,
+ "Cannot notify userspace of session "
+ "event %u\n", event);
return -ENOMEM;
}
@@ -825,8 +974,8 @@ int iscsi_session_event(struct iscsi_cls_session *session,
ev->r.unbind_session.sid = session->sid;
break;
default:
- dev_printk(KERN_ERR, &session->dev, "Invalid event %u.\n",
- event);
+ iscsi_cls_session_printk(KERN_ERR, session, "Invalid event "
+ "%u.\n", event);
kfree_skb(skb);
return -EINVAL;
}
@@ -837,8 +986,10 @@ int iscsi_session_event(struct iscsi_cls_session *session,
*/
rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
if (rc < 0)
- dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace "
- "of session event %u. Check iscsi daemon\n", event);
+ iscsi_cls_session_printk(KERN_ERR, session,
+ "Cannot notify userspace of session "
+ "event %u. Check iscsi daemon\n",
+ event);
return rc;
}
EXPORT_SYMBOL_GPL(iscsi_session_event);
@@ -871,16 +1022,15 @@ 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) {
- printk(KERN_ERR "iscsi: couldn't create a new "
- "connection for session %d\n",
- session->sid);
+ iscsi_cls_session_printk(KERN_ERR, session,
+ "couldn't create a new connection.");
return -ENOMEM;
}
@@ -1246,6 +1396,15 @@ 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) \
@@ -1472,6 +1631,7 @@ 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/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 51a5557f42d..37df8bbe7f4 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -929,6 +929,7 @@ 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;
@@ -967,26 +968,23 @@ static int sd_done(struct scsi_cmnd *SCpnt)
goto out;
if (xfer_size <= SCpnt->device->sector_size)
goto out;
- switch (SCpnt->device->sector_size) {
- case 256:
+ if (SCpnt->device->sector_size < 512) {
+ /* only legitimate sector_size here is 256 */
start_lba <<= 1;
- 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;
+ 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
+ */
+ goto out;
+
/* This computation should always be done in terms of
* the resolution of the device's medium.
*/
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
new file mode 100644
index 00000000000..2a6e4f472ea
--- /dev/null
+++ b/drivers/scsi/ses.c
@@ -0,0 +1,689 @@
+/*
+ * SCSI Enclosure Services
+ *
+ * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com>
+ *
+**-----------------------------------------------------------------------------
+**
+** 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/enclosure.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_host.h>
+
+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/drivers/scsi/sg.c b/drivers/scsi/sg.c
index aba28f335b8..e5156aa6dd2 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1160,23 +1160,22 @@ sg_fasync(int fd, struct file *filp, int mode)
return (retval < 0) ? retval : 0;
}
-static struct page *
-sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type)
+static int
+sg_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
Sg_fd *sfp;
- struct page *page = NOPAGE_SIGBUS;
unsigned long offset, len, sa;
Sg_scatter_hold *rsv_schp;
struct scatterlist *sg;
int k;
if ((NULL == vma) || (!(sfp = (Sg_fd *) vma->vm_private_data)))
- return page;
+ return VM_FAULT_SIGBUS;
rsv_schp = &sfp->reserve;
- offset = addr - vma->vm_start;
+ offset = vmf->pgoff << PAGE_SHIFT;
if (offset >= rsv_schp->bufflen)
- return page;
- SCSI_LOG_TIMEOUT(3, printk("sg_vma_nopage: offset=%lu, scatg=%d\n",
+ return VM_FAULT_SIGBUS;
+ SCSI_LOG_TIMEOUT(3, printk("sg_vma_fault: offset=%lu, scatg=%d\n",
offset, rsv_schp->k_use_sg));
sg = rsv_schp->buffer;
sa = vma->vm_start;
@@ -1185,21 +1184,21 @@ sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type)
len = vma->vm_end - sa;
len = (len < sg->length) ? len : sg->length;
if (offset < len) {
+ struct page *page;
page = virt_to_page(page_address(sg_page(sg)) + offset);
get_page(page); /* increment page count */
- break;
+ vmf->page = page;
+ return 0; /* success */
}
sa += len;
offset -= len;
}
- if (type)
- *type = VM_FAULT_MINOR;
- return page;
+ return VM_FAULT_SIGBUS;
}
static struct vm_operations_struct sg_mmap_vm_ops = {
- .nopage = sg_vma_nopage,
+ .fault = sg_vma_fault,
};
static int
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 50ba4925020..208565bdbe8 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -163,6 +163,29 @@ 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,
@@ -185,8 +208,7 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
}
sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
- retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES,
- sshdr);
+ retval = sr_test_unit_ready(cd->device, sshdr);
if (retval || (scsi_sense_valid(sshdr) &&
/* 0x3a is medium not present */
sshdr->asc == 0x3a)) {
@@ -733,10 +755,8 @@ 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;
- unsigned int the_result;
- int retries, rc, n;
+ int rc, n;
static const char *loadmech[] =
{
@@ -758,23 +778,8 @@ static void get_capabilities(struct scsi_cd *cd)
return;
}
- /* 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)));
+ /* eat unit attentions */
+ sr_test_unit_ready(cd->device, &sshdr);
/* ask for mode page 0x2a */
rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128,
diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h
index 81fbc0b78a5..1e144dfdbd4 100644
--- a/drivers/scsi/sr.h
+++ b/drivers/scsi/sr.h
@@ -61,6 +61,7 @@ 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/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index d5cebff1d64..ae87d08df58 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -306,8 +306,7 @@ int sr_drive_status(struct cdrom_device_info *cdi, int slot)
/* we have no changer support */
return -EINVAL;
}
- if (0 == scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES,
- &sshdr))
+ if (0 == sr_test_unit_ready(cd->device, &sshdr))
return CDS_DISC_OK;
if (!cdrom_get_media_event(cdi, &med)) {
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index 1bc41907a03..06152c7fa68 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -1,392 +1,316 @@
-/* sun3x_esp.c: EnhancedScsiProcessor Sun3x SCSI driver code.
+/* sun3x_esp.c: ESP front-end for Sun3x systems.
*
- * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
- *
- * Based on David S. Miller's esp driver
+ * Copyright (C) 2007,2008 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
*/
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "NCR53C9x.h"
-
#include <asm/sun3x.h>
+#include <asm/io.h>
+#include <asm/dma.h>
#include <asm/dvma.h>
-#include <asm/irq.h>
-
-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;
- esp->esp_command = (volatile unsigned char *)dvma_malloc(DVMA_PAGE_SIZE);
- esp->esp_command_dvma = dvma_vtob((unsigned long)esp->esp_command);
-
- esp->irq = 2;
- if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
- "SUN3X SCSI", esp->ehost)) {
- esp_deallocate(esp);
- return 0;
- }
+/* 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->scsi_id = 7;
- esp->diff = 0;
+#include <scsi/scsi_host.h>
- esp_initialize(esp);
+#include "esp_scsi.h"
- /* 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;
+#define DRV_MODULE_NAME "sun3x_esp"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_VERSION "1.000"
+#define DRV_MODULE_RELDATE "Nov 1, 2007"
- 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;
+/*
+ * 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));
}
-static void dma_do_drain(struct NCR_ESP *esp)
+static u8 sun3x_esp_read8(struct esp *esp, unsigned long reg)
{
- 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);
- }
-
+ return readb(esp->regs + (reg * 4UL));
}
-
-static void dma_barrier(struct NCR_ESP *esp)
+
+static dma_addr_t sun3x_esp_map_single(struct esp *esp, void *buf,
+ size_t sz, int 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);
+ return dma_map_single(esp->dev, buf, sz, 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)
+static int sun3x_esp_map_sg(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir)
{
- struct sparc_dma_registers *dregs =
- (struct sparc_dma_registers *) esp->dregs;
-
- int rval = dregs->st_addr - esp->esp_command_dvma;
-
- return rval - fifo_count;
+ return dma_map_sg(esp->dev, sg, num_sg, dir);
}
-static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+static void sun3x_esp_unmap_single(struct esp *esp, dma_addr_t addr,
+ size_t sz, int dir)
{
- return sp->SCp.this_residual;
+ dma_unmap_single(esp->dev, addr, sz, dir);
}
-static void dma_drain(struct NCR_ESP *esp)
+static void sun3x_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir)
{
- 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);
- }
-
- }
+ dma_unmap_sg(esp->dev, sg, num_sg, dir);
}
-static void dma_invalidate(struct NCR_ESP *esp)
+static int sun3x_esp_irq_pending(struct esp *esp)
{
- struct sparc_dma_registers *dregs =
- (struct sparc_dma_registers *) esp->dregs;
-
- __u32 tmp;
- int count = 500000;
-
- while(((tmp = dregs->cond_reg) & DMA_PEND_READ) && (--count > 0))
- udelay(1);
+ if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
+ return 1;
+ return 0;
+}
- if(!count) {
- printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg);
- }
+static void sun3x_esp_reset_dma(struct esp *esp)
+{
+ u32 val;
- dregs->cond_reg = tmp | DMA_FIFO_INV;
- dregs->cond_reg &= ~DMA_FIFO_INV;
+ val = dma_read32(DMA_CSR);
+ dma_write32(val | DMA_RST_SCSI, DMA_CSR);
+ dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
+ /* Enable interrupts. */
+ val = dma_read32(DMA_CSR);
+ dma_write32(val | DMA_INT_ENAB, DMA_CSR);
}
-static void dma_dump_state(struct NCR_ESP *esp)
+static void sun3x_esp_dma_drain(struct esp *esp)
{
- struct sparc_dma_registers *dregs =
- (struct sparc_dma_registers *) esp->dregs;
+ u32 csr;
+ int lim;
- ESPLOG(("esp%d: dma -- cond_reg<%08lx> addr<%08lx>\n",
- esp->esp_id, dregs->cond_reg, dregs->st_addr));
-}
+ csr = dma_read32(DMA_CSR);
+ if (!(csr & DMA_FIFO_ISDRAIN))
+ return;
-static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length)
-{
- struct sparc_dma_registers *dregs =
- (struct sparc_dma_registers *) esp->dregs;
+ dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);
- dregs->st_addr = vaddress;
- dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE);
+ 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;
+ }
+ udelay(1);
+ }
}
-static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length)
+static void sun3x_esp_dma_invalidate(struct esp *esp)
{
- struct sparc_dma_registers *dregs =
- (struct sparc_dma_registers *) esp->dregs;
-
- /* Set up the DMA counters */
+ 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);
+ }
- dregs->st_addr = vaddress;
- dregs->cond_reg = ((dregs->cond_reg & ~(DMA_ST_WRITE)) | DMA_ENABLE);
+ 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);
}
-static void dma_ints_off(struct NCR_ESP *esp)
+static void sun3x_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
+ u32 dma_count, int write, u8 cmd)
{
- DMA_INTSOFF((struct sparc_dma_registers *) esp->dregs);
+ 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);
}
-static void dma_ints_on(struct NCR_ESP *esp)
+static int sun3x_esp_dma_error(struct esp *esp)
{
- DMA_INTSON((struct sparc_dma_registers *) esp->dregs);
-}
+ u32 csr = dma_read32(DMA_CSR);
-static int dma_irq_p(struct NCR_ESP *esp)
-{
- return DMA_IRQ_P((struct sparc_dma_registers *) esp->dregs);
+ if (csr & DMA_HNDL_ERROR)
+ return 1;
+
+ return 0;
}
-static void dma_poll(struct NCR_ESP *esp, unsigned char *vaddr)
+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)
{
- int count = 50;
- dma_do_drain(esp);
+ struct scsi_host_template *tpnt = &scsi_esp_template;
+ struct Scsi_Host *host;
+ struct esp *esp;
+ struct resource *res;
+ int err = -ENOMEM;
- /* Wait till the first bits settle. */
- while((*(volatile unsigned char *)vaddr == 0xff) && (--count > 0))
- udelay(1);
+ host = scsi_host_alloc(tpnt, sizeof(struct esp));
+ if (!host)
+ goto fail;
- 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);
- }
+ host->max_id = 8;
+ esp = shost_priv(host);
-}
+ esp->host = host;
+ esp->dev = dev;
+ esp->ops = &sun3x_esp_ops;
-static int dma_ports_p(struct NCR_ESP *esp)
-{
- return (((struct sparc_dma_registers *) esp->dregs)->cond_reg
- & DMA_INT_ENAB);
-}
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res && !res->start)
+ goto fail_unlink;
-/* 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;
+ esp->regs = ioremap_nocache(res->start, 0x20);
+ if (!esp->regs)
+ goto fail_unmap_regs;
- /* Punt the DVMA into a known state. */
- dregs->cond_reg |= DMA_RST_SCSI;
- dregs->cond_reg &= ~(DMA_RST_SCSI);
- DMA_INTSON(dregs);
-}
+ res = platform_get_resource(dev, IORESOURCE_MEM, 1);
+ if (!res && !res->start)
+ goto fail_unmap_regs;
-static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
-{
- struct sparc_dma_registers *dregs =
- (struct sparc_dma_registers *) esp->dregs;
- unsigned long nreg = dregs->cond_reg;
+ esp->dma_regs = ioremap_nocache(res->start, 0x10);
-// printk("dma_setup %c addr %08x cnt %08x\n",
-// write ? 'W' : 'R', addr, count);
+ esp->command_block = dma_alloc_coherent(esp->dev, 16,
+ &esp->command_block_dma,
+ GFP_KERNEL);
+ if (!esp->command_block)
+ goto fail_unmap_regs_dma;
- dma_do_drain(esp);
+ 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;
- if(write)
- nreg |= DMA_ST_WRITE;
- else {
- nreg &= ~(DMA_ST_WRITE);
- }
-
- nreg |= DMA_ENABLE;
- dregs->cond_reg = nreg;
- dregs->st_addr = addr;
-}
+ esp->scsi_id = 7;
+ esp->host->this_id = esp->scsi_id;
+ esp->scsi_id_mask = (1 << esp->scsi_id);
+ esp->cfreq = 20000000;
-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);
+ 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;
}
-static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
+static int __devexit esp_sun3x_remove(struct platform_device *dev)
{
- 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);
-}
+ struct esp *esp = dev_get_drvdata(&dev->dev);
+ unsigned int irq = esp->host->irq;
+ u32 val;
-static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
-{
- dvma_unmap((char *)sp->SCp.have_data_in);
-}
+ scsi_esp_unregister(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--;
- }
-}
+ /* Disable interrupts. */
+ val = dma_read32(DMA_CSR);
+ dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);
-static void dma_advance_sg (Scsi_Cmnd *sp)
-{
- sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dma_address);
-}
+ free_irq(irq, esp);
+ dma_free_coherent(esp->dev, 16,
+ esp->command_block,
+ esp->command_block_dma);
-static int sun3x_esp_release(struct Scsi_Host *instance)
-{
- /* this code does not support being compiled as a module */
- return 1;
+ scsi_host_put(esp->host);
+ return 0;
}
-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,
+static struct platform_driver esp_sun3x_driver = {
+ .probe = esp_sun3x_probe,
+ .remove = __devexit_p(esp_sun3x_remove),
+ .driver = {
+ .name = "sun3x_esp",
+ },
};
+static int __init sun3x_esp_init(void)
+{
+ return platform_driver_register(&esp_sun3x_driver);
+}
-#include "scsi_module.c"
+static void __exit sun3x_esp_exit(void)
+{
+ platform_driver_unregister(&esp_sun3x_driver);
+}
+MODULE_DESCRIPTION("Sun3x ESP SCSI driver");
+MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)");
MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(sun3x_esp_init);
+module_exit(sun3x_esp_exit);
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
index 254bdaeb35f..35142b5341b 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c
+++ b/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;
+ return cp->data_len - cp->odd_byte_adjustment;
}
/*
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 662c00451be..58d7eee4fe8 100644
--- a/drivers/scsi/u14-34f.c
+++ b/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_FROM_DEVICE) {
+ else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
cpp->xdir = DTD_OUT;
return;
}