diff --git a/[refs] b/[refs] index 57d5e41b2b19..f90688669610 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 0b61a2ba5dfd1620731e717d686e6ade657fd975 +refs/heads/master: 7fce084a0b3e2bb8caef919f8f36065953655bb5 diff --git a/trunk/Documentation/DocBook/scsi.tmpl b/trunk/Documentation/DocBook/scsi.tmpl index 10a150ae2a7e..f299ab182bbe 100644 --- a/trunk/Documentation/DocBook/scsi.tmpl +++ b/trunk/Documentation/DocBook/scsi.tmpl @@ -12,7 +12,7 @@ Bottomley
- James.Bottomley@hansenpartnership.com + James.Bottomley@steeleye.com
diff --git a/trunk/Documentation/scsi/ChangeLog.arcmsr b/trunk/Documentation/scsi/ChangeLog.arcmsr index de2bcacfa870..cd8403a33ee6 100644 --- a/trunk/Documentation/scsi/ChangeLog.arcmsr +++ b/trunk/Documentation/scsi/ChangeLog.arcmsr @@ -68,45 +68,4 @@ ** 2. modify the arcmsr_pci_slot_reset function ** 3. modify the arcmsr_pci_ers_disconnect_forepart function ** 4. modify the arcmsr_pci_ers_need_reset_forepart function -** 1.20.00.15 09/27/2007 Erich Chen & Nick Cheng -** 1. add arcmsr_enable_eoi_mode() on adapter Type B -** 2. add readl(reg->iop2drv_doorbell_reg) in arcmsr_handle_hbb_isr() -** in case of the doorbell interrupt clearance is cached -** 1.20.00.15 10/01/2007 Erich Chen & Nick Cheng -** 1. modify acb->devstate[i][j] -** as ARECA_RAID_GOOD instead of -** ARECA_RAID_GONE in arcmsr_alloc_ccb_pool -** 1.20.00.15 11/06/2007 Erich Chen & Nick Cheng -** 1. add conditional declaration for -** arcmsr_pci_error_detected() and -** arcmsr_pci_slot_reset -** 1.20.00.15 11/23/2007 Erich Chen & Nick Cheng -** 1.check if the sg list member number -** exceeds arcmsr default limit in arcmsr_build_ccb() -** 2.change the returned value type of arcmsr_build_ccb() -** from "void" to "int" -** 3.add the conditional check if arcmsr_build_ccb() -** returns FAILED -** 1.20.00.15 12/04/2007 Erich Chen & Nick Cheng -** 1. modify arcmsr_drain_donequeue() to ignore unknown -** command and let kernel process command timeout. -** This could handle IO request violating max. segments -** while Linux XFS over DM-CRYPT. -** Thanks to Milan Broz's comments -** 1.20.00.15 12/24/2007 Erich Chen & Nick Cheng -** 1.fix the portability problems -** 2.fix type B where we should _not_ iounmap() acb->pmu; -** it's not ioremapped. -** 3.add return -ENOMEM if ioremap() fails -** 4.transfer IS_SG64_ADDR w/ cpu_to_le32() -** in arcmsr_build_ccb -** 5. modify acb->devstate[i][j] as ARECA_RAID_GONE instead of -** ARECA_RAID_GOOD in arcmsr_alloc_ccb_pool() -** 6.fix arcmsr_cdb->Context as (unsigned long)arcmsr_cdb -** 7.add the checking state of -** (outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT) == 0 -** in arcmsr_handle_hba_isr -** 8.replace pci_alloc_consistent()/pci_free_consistent() with kmalloc()/kfree() in arcmsr_iop_message_xfer() -** 9. fix the release of dma memory for type B in arcmsr_free_ccb_pool() -** 10.fix the arcmsr_polling_hbb_ccbdone() ************************************************************************** diff --git a/trunk/Documentation/scsi/scsi_mid_low_api.txt b/trunk/Documentation/scsi/scsi_mid_low_api.txt index a6d5354639b2..6f70f2b9327e 100644 --- a/trunk/Documentation/scsi/scsi_mid_low_api.txt +++ b/trunk/Documentation/scsi/scsi_mid_low_api.txt @@ -1407,7 +1407,7 @@ Credits ======= The following people have contributed to this document: Mike Anderson - James Bottomley + James Bottomley Patrick Mansfield Christoph Hellwig Doug Ledford diff --git a/trunk/Documentation/vm/slabinfo.c b/trunk/Documentation/vm/slabinfo.c index 7123fee708ca..488c1f31b992 100644 --- a/trunk/Documentation/vm/slabinfo.c +++ b/trunk/Documentation/vm/slabinfo.c @@ -32,13 +32,6 @@ struct slabinfo { int sanity_checks, slab_size, store_user, trace; int order, poison, reclaim_account, red_zone; unsigned long partial, objects, slabs; - unsigned long alloc_fastpath, alloc_slowpath; - unsigned long free_fastpath, free_slowpath; - unsigned long free_frozen, free_add_partial, free_remove_partial; - unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill; - unsigned long cpuslab_flush, deactivate_full, deactivate_empty; - unsigned long deactivate_to_head, deactivate_to_tail; - unsigned long deactivate_remote_frees; int numa[MAX_NODES]; int numa_partial[MAX_NODES]; } slabinfo[MAX_SLABS]; @@ -71,10 +64,8 @@ int show_inverted = 0; int show_single_ref = 0; int show_totals = 0; int sort_size = 0; -int sort_active = 0; int set_debug = 0; int show_ops = 0; -int show_activity = 0; /* Debug options */ int sanity = 0; @@ -102,10 +93,8 @@ void usage(void) printf("slabinfo 5/7/2007. (c) 2007 sgi. clameter@sgi.com\n\n" "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n" "-a|--aliases Show aliases\n" - "-A|--activity Most active slabs first\n" "-d|--debug= Set/Clear Debug options\n" - "-D|--display-active Switch line format to activity\n" - "-e|--empty Show empty slabs\n" + "-e|--empty Show empty slabs\n" "-f|--first-alias Show first alias\n" "-h|--help Show usage information\n" "-i|--inverted Inverted list\n" @@ -292,11 +281,8 @@ int line = 0; void first_line(void) { - if (show_activity) - printf("Name Objects Alloc Free %%Fast\n"); - else - printf("Name Objects Objsize Space " - "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n"); + printf("Name Objects Objsize Space " + "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n"); } /* @@ -323,12 +309,6 @@ unsigned long slab_size(struct slabinfo *s) return s->slabs * (page_size << s->order); } -unsigned long slab_activity(struct slabinfo *s) -{ - return s->alloc_fastpath + s->free_fastpath + - s->alloc_slowpath + s->free_slowpath; -} - void slab_numa(struct slabinfo *s, int mode) { int node; @@ -412,71 +392,6 @@ const char *onoff(int x) return "Off"; } -void slab_stats(struct slabinfo *s) -{ - unsigned long total_alloc; - unsigned long total_free; - unsigned long total; - - if (!s->alloc_slab) - return; - - total_alloc = s->alloc_fastpath + s->alloc_slowpath; - total_free = s->free_fastpath + s->free_slowpath; - - if (!total_alloc) - return; - - printf("\n"); - printf("Slab Perf Counter Alloc Free %%Al %%Fr\n"); - printf("--------------------------------------------------\n"); - printf("Fastpath %8lu %8lu %3lu %3lu\n", - s->alloc_fastpath, s->free_fastpath, - s->alloc_fastpath * 100 / total_alloc, - s->free_fastpath * 100 / total_free); - printf("Slowpath %8lu %8lu %3lu %3lu\n", - total_alloc - s->alloc_fastpath, s->free_slowpath, - (total_alloc - s->alloc_fastpath) * 100 / total_alloc, - s->free_slowpath * 100 / total_free); - printf("Page Alloc %8lu %8lu %3lu %3lu\n", - s->alloc_slab, s->free_slab, - s->alloc_slab * 100 / total_alloc, - s->free_slab * 100 / total_free); - printf("Add partial %8lu %8lu %3lu %3lu\n", - s->deactivate_to_head + s->deactivate_to_tail, - s->free_add_partial, - (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc, - s->free_add_partial * 100 / total_free); - printf("Remove partial %8lu %8lu %3lu %3lu\n", - s->alloc_from_partial, s->free_remove_partial, - s->alloc_from_partial * 100 / total_alloc, - s->free_remove_partial * 100 / total_free); - - printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n", - s->deactivate_remote_frees, s->free_frozen, - s->deactivate_remote_frees * 100 / total_alloc, - s->free_frozen * 100 / total_free); - - printf("Total %8lu %8lu\n\n", total_alloc, total_free); - - if (s->cpuslab_flush) - printf("Flushes %8lu\n", s->cpuslab_flush); - - if (s->alloc_refill) - printf("Refill %8lu\n", s->alloc_refill); - - total = s->deactivate_full + s->deactivate_empty + - s->deactivate_to_head + s->deactivate_to_tail; - - if (total) - printf("Deactivate Full=%lu(%lu%%) Empty=%lu(%lu%%) " - "ToHead=%lu(%lu%%) ToTail=%lu(%lu%%)\n", - s->deactivate_full, (s->deactivate_full * 100) / total, - s->deactivate_empty, (s->deactivate_empty * 100) / total, - s->deactivate_to_head, (s->deactivate_to_head * 100) / total, - s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total); -} - void report(struct slabinfo *s) { if (strcmp(s->name, "*") == 0) @@ -515,7 +430,6 @@ void report(struct slabinfo *s) ops(s); show_tracking(s); slab_numa(s, 1); - slab_stats(s); } void slabcache(struct slabinfo *s) @@ -565,27 +479,13 @@ void slabcache(struct slabinfo *s) *p++ = 'T'; *p = 0; - if (show_activity) { - unsigned long total_alloc; - unsigned long total_free; - - total_alloc = s->alloc_fastpath + s->alloc_slowpath; - total_free = s->free_fastpath + s->free_slowpath; - - printf("%-21s %8ld %8ld %8ld %3ld %3ld \n", - s->name, s->objects, - total_alloc, total_free, - total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0, - total_free ? (s->free_fastpath * 100 / total_free) : 0); - } - else - printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n", - s->name, s->objects, s->object_size, size_str, dist_str, - s->objs_per_slab, s->order, - s->slabs ? (s->partial * 100) / s->slabs : 100, - s->slabs ? (s->objects * s->object_size * 100) / - (s->slabs * (page_size << s->order)) : 100, - flags); + printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n", + s->name, s->objects, s->object_size, size_str, dist_str, + s->objs_per_slab, s->order, + s->slabs ? (s->partial * 100) / s->slabs : 100, + s->slabs ? (s->objects * s->object_size * 100) / + (s->slabs * (page_size << s->order)) : 100, + flags); } /* @@ -992,8 +892,6 @@ void sort_slabs(void) if (sort_size) result = slab_size(s1) < slab_size(s2); - else if (sort_active) - result = slab_activity(s1) < slab_activity(s2); else result = strcasecmp(s1->name, s2->name); @@ -1176,23 +1074,6 @@ void read_slab_dir(void) free(t); slab->store_user = get_obj("store_user"); slab->trace = get_obj("trace"); - slab->alloc_fastpath = get_obj("alloc_fastpath"); - slab->alloc_slowpath = get_obj("alloc_slowpath"); - slab->free_fastpath = get_obj("free_fastpath"); - slab->free_slowpath = get_obj("free_slowpath"); - slab->free_frozen= get_obj("free_frozen"); - slab->free_add_partial = get_obj("free_add_partial"); - slab->free_remove_partial = get_obj("free_remove_partial"); - slab->alloc_from_partial = get_obj("alloc_from_partial"); - slab->alloc_slab = get_obj("alloc_slab"); - slab->alloc_refill = get_obj("alloc_refill"); - slab->free_slab = get_obj("free_slab"); - slab->cpuslab_flush = get_obj("cpuslab_flush"); - slab->deactivate_full = get_obj("deactivate_full"); - slab->deactivate_empty = get_obj("deactivate_empty"); - slab->deactivate_to_head = get_obj("deactivate_to_head"); - slab->deactivate_to_tail = get_obj("deactivate_to_tail"); - slab->deactivate_remote_frees = get_obj("deactivate_remote_frees"); chdir(".."); if (slab->name[0] == ':') alias_targets++; @@ -1243,9 +1124,7 @@ void output_slabs(void) struct option opts[] = { { "aliases", 0, NULL, 'a' }, - { "activity", 0, NULL, 'A' }, { "debug", 2, NULL, 'd' }, - { "display-activity", 0, NULL, 'D' }, { "empty", 0, NULL, 'e' }, { "first-alias", 0, NULL, 'f' }, { "help", 0, NULL, 'h' }, @@ -1270,7 +1149,7 @@ int main(int argc, char *argv[]) page_size = getpagesize(); - while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTS", + while ((c = getopt_long(argc, argv, "ad::efhil1noprstvzTS", opts, NULL)) != -1) switch (c) { case '1': @@ -1279,17 +1158,11 @@ int main(int argc, char *argv[]) case 'a': show_alias = 1; break; - case 'A': - sort_active = 1; - break; case 'd': set_debug = 1; if (!debug_opt_scan(optarg)) fatal("Invalid debug option '%s'\n", optarg); break; - case 'D': - show_activity = 1; - break; case 'e': show_empty = 1; break; diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 2cdb591ac080..aefd23f892ba 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -2150,14 +2150,6 @@ M: acme@ghostprotocols.net L: netdev@vger.kernel.org S: Maintained -IPWIRELES DRIVER -P: Jiri Kosina -M: jkosina@suse.cz -P: David Sterba -M: dsterba@suse.cz -S: Maintained -T: git://git.kernel.org/pub/scm/linux/kernel/git/jikos/ipwireless_cs.git - IRDA SUBSYSTEM P: Samuel Ortiz M: samuel@sortiz.org diff --git a/trunk/arch/m68k/kernel/process.c b/trunk/arch/m68k/kernel/process.c index f85b928ffac4..3ee918695215 100644 --- a/trunk/arch/m68k/kernel/process.c +++ b/trunk/arch/m68k/kernel/process.c @@ -335,7 +335,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump) if (dump->start_stack < TASK_SIZE) dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; - dump->u_ar0 = offsetof(struct user, regs); + dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump); sw = ((struct switch_stack *)regs) - 1; dump->regs.d1 = regs->d1; dump->regs.d2 = regs->d2; diff --git a/trunk/arch/powerpc/kernel/asm-offsets.c b/trunk/arch/powerpc/kernel/asm-offsets.c index 4b749c416464..e6e49289f788 100644 --- a/trunk/arch/powerpc/kernel/asm-offsets.c +++ b/trunk/arch/powerpc/kernel/asm-offsets.c @@ -313,7 +313,7 @@ int main(void) DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); DEFINE(NSEC_PER_SEC, NSEC_PER_SEC); - DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC); + DEFINE(CLOCK_REALTIME_RES, (KTIME_MONOTONIC_RES).tv64); #ifdef CONFIG_BUG DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry)); diff --git a/trunk/arch/x86/Kconfig b/trunk/arch/x86/Kconfig index 9d0acedf5f3f..c95482b6b6dd 100644 --- a/trunk/arch/x86/Kconfig +++ b/trunk/arch/x86/Kconfig @@ -52,10 +52,6 @@ config HAVE_LATENCYTOP_SUPPORT config SEMAPHORE_SLEEPERS def_bool y -config FAST_CMPXCHG_LOCAL - bool - default y - config MMU def_bool y diff --git a/trunk/drivers/char/pcmcia/Kconfig b/trunk/drivers/char/pcmcia/Kconfig index 00b8a84b0319..f25facd97bb4 100644 --- a/trunk/drivers/char/pcmcia/Kconfig +++ b/trunk/drivers/char/pcmcia/Kconfig @@ -43,14 +43,5 @@ config CARDMAN_4040 (http://www.omnikey.com/), or a current development version of OpenCT (http://www.opensc.org/). -config IPWIRELESS - tristate "IPWireless 3G UMTS PCMCIA card support" - depends on PCMCIA - select PPP - help - This is a driver for 3G UMTS PCMCIA card from IPWireless company. In - some countries (for example Czech Republic, T-Mobile ISP) this card - is shipped for service called UMTS 4G. - endmenu diff --git a/trunk/drivers/char/pcmcia/Makefile b/trunk/drivers/char/pcmcia/Makefile index be8f287aa398..0aae20985d57 100644 --- a/trunk/drivers/char/pcmcia/Makefile +++ b/trunk/drivers/char/pcmcia/Makefile @@ -4,8 +4,6 @@ # Makefile for the Linux PCMCIA char device drivers. # -obj-y += ipwireless/ - obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o obj-$(CONFIG_CARDMAN_4000) += cm4000_cs.o obj-$(CONFIG_CARDMAN_4040) += cm4040_cs.o diff --git a/trunk/drivers/char/pcmcia/ipwireless/Makefile b/trunk/drivers/char/pcmcia/ipwireless/Makefile deleted file mode 100644 index b71eb593643d..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# drivers/char/pcmcia/ipwireless/Makefile -# -# Makefile for the IPWireless driver -# - -obj-$(CONFIG_IPWIRELESS) += ipwireless.o - -ipwireless-objs := hardware.o main.o network.o tty.o - diff --git a/trunk/drivers/char/pcmcia/ipwireless/hardware.c b/trunk/drivers/char/pcmcia/ipwireless/hardware.c deleted file mode 100644 index 1f978ff87fa8..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/hardware.c +++ /dev/null @@ -1,1787 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#include -#include -#include -#include -#include -#include - -#include "hardware.h" -#include "setup_protocol.h" -#include "network.h" -#include "main.h" - -static void ipw_send_setup_packet(struct ipw_hardware *hw); -static void handle_received_SETUP_packet(struct ipw_hardware *ipw, - unsigned int address, - unsigned char *data, int len, - int is_last); -static void ipwireless_setup_timer(unsigned long data); -static void handle_received_CTRL_packet(struct ipw_hardware *hw, - unsigned int channel_idx, unsigned char *data, int len); - -/*#define TIMING_DIAGNOSTICS*/ - -#ifdef TIMING_DIAGNOSTICS - -static struct timing_stats { - unsigned long last_report_time; - unsigned long read_time; - unsigned long write_time; - unsigned long read_bytes; - unsigned long write_bytes; - unsigned long start_time; -}; - -static void start_timing(void) -{ - timing_stats.start_time = jiffies; -} - -static void end_read_timing(unsigned length) -{ - timing_stats.read_time += (jiffies - start_time); - timing_stats.read_bytes += length + 2; - report_timing(); -} - -static void end_write_timing(unsigned length) -{ - timing_stats.write_time += (jiffies - start_time); - timing_stats.write_bytes += length + 2; - report_timing(); -} - -static void report_timing(void) -{ - unsigned long since = jiffies - timing_stats.last_report_time; - - /* If it's been more than one second... */ - if (since >= HZ) { - int first = (timing_stats.last_report_time == 0); - - timing_stats.last_report_time = jiffies; - if (!first) - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": %u us elapsed - read %lu bytes in %u us, " - "wrote %lu bytes in %u us\n", - jiffies_to_usecs(since), - timing_stats.read_bytes, - jiffies_to_usecs(timing_stats.read_time), - timing_stats.write_bytes, - jiffies_to_usecs(timing_stats.write_time)); - - timing_stats.read_time = 0; - timing_stats.write_time = 0; - timing_stats.read_bytes = 0; - timing_stats.write_bytes = 0; - } -} -#else -static void start_timing(void) { } -static void end_read_timing(unsigned length) { } -static void end_write_timing(unsigned length) { } -#endif - -/* Imported IPW definitions */ - -#define LL_MTU_V1 318 -#define LL_MTU_V2 250 -#define LL_MTU_MAX (LL_MTU_V1 > LL_MTU_V2 ? LL_MTU_V1 : LL_MTU_V2) - -#define PRIO_DATA 2 -#define PRIO_CTRL 1 -#define PRIO_SETUP 0 - -/* Addresses */ -#define ADDR_SETUP_PROT 0 - -/* Protocol ids */ -enum { - /* Identifier for the Com Data protocol */ - TL_PROTOCOLID_COM_DATA = 0, - - /* Identifier for the Com Control protocol */ - TL_PROTOCOLID_COM_CTRL = 1, - - /* Identifier for the Setup protocol */ - TL_PROTOCOLID_SETUP = 2 -}; - -/* Number of bytes in NL packet header (cannot do - * sizeof(nl_packet_header) since it's a bitfield) */ -#define NL_FIRST_PACKET_HEADER_SIZE 3 - -/* Number of bytes in NL packet header (cannot do - * sizeof(nl_packet_header) since it's a bitfield) */ -#define NL_FOLLOWING_PACKET_HEADER_SIZE 1 - -struct nl_first_packet_header { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char packet_rank:2; - unsigned char address:3; - unsigned char protocol:3; -#else - unsigned char protocol:3; - unsigned char address:3; - unsigned char packet_rank:2; -#endif - unsigned char length_lsb; - unsigned char length_msb; -}; - -struct nl_packet_header { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char packet_rank:2; - unsigned char address:3; - unsigned char protocol:3; -#else - unsigned char protocol:3; - unsigned char address:3; - unsigned char packet_rank:2; -#endif -}; - -/* Value of 'packet_rank' above */ -#define NL_INTERMEDIATE_PACKET 0x0 -#define NL_LAST_PACKET 0x1 -#define NL_FIRST_PACKET 0x2 - -union nl_packet { - /* Network packet header of the first packet (a special case) */ - struct nl_first_packet_header hdr_first; - /* Network packet header of the following packets (if any) */ - struct nl_packet_header hdr; - /* Complete network packet (header + data) */ - unsigned char rawpkt[LL_MTU_MAX]; -} __attribute__ ((__packed__)); - -#define HW_VERSION_UNKNOWN -1 -#define HW_VERSION_1 1 -#define HW_VERSION_2 2 - -/* IPW I/O ports */ -#define IOIER 0x00 /* Interrupt Enable Register */ -#define IOIR 0x02 /* Interrupt Source/ACK register */ -#define IODCR 0x04 /* Data Control Register */ -#define IODRR 0x06 /* Data Read Register */ -#define IODWR 0x08 /* Data Write Register */ -#define IOESR 0x0A /* Embedded Driver Status Register */ -#define IORXR 0x0C /* Rx Fifo Register (Host to Embedded) */ -#define IOTXR 0x0E /* Tx Fifo Register (Embedded to Host) */ - -/* I/O ports and bit definitions for version 1 of the hardware */ - -/* IER bits*/ -#define IER_RXENABLED 0x1 -#define IER_TXENABLED 0x2 - -/* ISR bits */ -#define IR_RXINTR 0x1 -#define IR_TXINTR 0x2 - -/* DCR bits */ -#define DCR_RXDONE 0x1 -#define DCR_TXDONE 0x2 -#define DCR_RXRESET 0x4 -#define DCR_TXRESET 0x8 - -/* I/O ports and bit definitions for version 2 of the hardware */ - -struct MEMCCR { - unsigned short reg_config_option; /* PCCOR: Configuration Option Register */ - unsigned short reg_config_and_status; /* PCCSR: Configuration and Status Register */ - unsigned short reg_pin_replacement; /* PCPRR: Pin Replacemant Register */ - unsigned short reg_socket_and_copy; /* PCSCR: Socket and Copy Register */ - unsigned short reg_ext_status; /* PCESR: Extendend Status Register */ - unsigned short reg_io_base; /* PCIOB: I/O Base Register */ -}; - -struct MEMINFREG { - unsigned short memreg_tx_old; /* TX Register (R/W) */ - unsigned short pad1; - unsigned short memreg_rx_done; /* RXDone Register (R/W) */ - unsigned short pad2; - unsigned short memreg_rx; /* RX Register (R/W) */ - unsigned short pad3; - unsigned short memreg_pc_interrupt_ack; /* PC intr Ack Register (W) */ - unsigned short pad4; - unsigned long memreg_card_present;/* Mask for Host to check (R) for - * CARD_PRESENT_VALUE */ - unsigned short memreg_tx_new; /* TX2 (new) Register (R/W) */ -}; - -#define IODMADPR 0x00 /* DMA Data Port Register (R/W) */ - -#define CARD_PRESENT_VALUE (0xBEEFCAFEUL) - -#define MEMTX_TX 0x0001 -#define MEMRX_RX 0x0001 -#define MEMRX_RX_DONE 0x0001 -#define MEMRX_PCINTACKK 0x0001 -#define MEMRX_MEMSPURIOUSINT 0x0001 - -#define NL_NUM_OF_PRIORITIES 3 -#define NL_NUM_OF_PROTOCOLS 3 -#define NL_NUM_OF_ADDRESSES NO_OF_IPW_CHANNELS - -struct ipw_hardware { - unsigned int base_port; - short hw_version; - unsigned short ll_mtu; - spinlock_t spinlock; - - int initializing; - int init_loops; - struct timer_list setup_timer; - - int tx_ready; - struct list_head tx_queue[NL_NUM_OF_PRIORITIES]; - /* True if any packets are queued for transmission */ - int tx_queued; - - int rx_bytes_queued; - struct list_head rx_queue; - /* Pool of rx_packet structures that are not currently used. */ - struct list_head rx_pool; - int rx_pool_size; - /* True if reception of data is blocked while userspace processes it. */ - int blocking_rx; - /* True if there is RX data ready on the hardware. */ - int rx_ready; - unsigned short last_memtx_serial; - /* - * Newer versions of the V2 card firmware send serial numbers in the - * MemTX register. 'serial_number_detected' is set true when we detect - * a non-zero serial number (indicating the new firmware). Thereafter, - * the driver can safely ignore the Timer Recovery re-sends to avoid - * out-of-sync problems. - */ - int serial_number_detected; - struct work_struct work_rx; - - /* True if we are to send the set-up data to the hardware. */ - int to_setup; - - /* Card has been removed */ - int removed; - /* Saved irq value when we disable the interrupt. */ - int irq; - /* True if this driver is shutting down. */ - int shutting_down; - /* Modem control lines */ - unsigned int control_lines[NL_NUM_OF_ADDRESSES]; - struct ipw_rx_packet *packet_assembler[NL_NUM_OF_ADDRESSES]; - - struct tasklet_struct tasklet; - - /* The handle for the network layer, for the sending of events to it. */ - struct ipw_network *network; - struct MEMINFREG __iomem *memory_info_regs; - struct MEMCCR __iomem *memregs_CCR; - void (*reboot_callback) (void *data); - void *reboot_callback_data; - - unsigned short __iomem *memreg_tx; -}; - -/* - * Packet info structure for tx packets. - * Note: not all the fields defined here are required for all protocols - */ -struct ipw_tx_packet { - struct list_head queue; - /* channel idx + 1 */ - unsigned char dest_addr; - /* SETUP, CTRL or DATA */ - unsigned char protocol; - /* Length of data block, which starts at the end of this structure */ - unsigned short length; - /* Sending state */ - /* Offset of where we've sent up to so far */ - unsigned long offset; - /* Count of packet fragments, starting at 0 */ - int fragment_count; - - /* Called after packet is sent and before is freed */ - void (*packet_callback) (void *cb_data, unsigned int packet_length); - void *callback_data; -}; - -/* Signals from DTE */ -#define COMCTRL_RTS 0 -#define COMCTRL_DTR 1 - -/* Signals from DCE */ -#define COMCTRL_CTS 2 -#define COMCTRL_DCD 3 -#define COMCTRL_DSR 4 -#define COMCTRL_RI 5 - -struct ipw_control_packet_body { - /* DTE signal or DCE signal */ - unsigned char sig_no; - /* 0: set signal, 1: clear signal */ - unsigned char value; -} __attribute__ ((__packed__)); - -struct ipw_control_packet { - struct ipw_tx_packet header; - struct ipw_control_packet_body body; -}; - -struct ipw_rx_packet { - struct list_head queue; - unsigned int capacity; - unsigned int length; - unsigned int protocol; - unsigned int channel_idx; -}; - -#ifdef IPWIRELESS_STATE_DEBUG -int ipwireless_dump_hardware_state(char *p, size_t limit, - struct ipw_hardware *hw) -{ - return snprintf(p, limit, - "debug: initializing=%d\n" - "debug: tx_ready=%d\n" - "debug: tx_queued=%d\n" - "debug: rx_ready=%d\n" - "debug: rx_bytes_queued=%d\n" - "debug: blocking_rx=%d\n" - "debug: removed=%d\n" - "debug: hardware.shutting_down=%d\n" - "debug: to_setup=%d\n", - hw->initializing, - hw->tx_ready, - hw->tx_queued, - hw->rx_ready, - hw->rx_bytes_queued, - hw->blocking_rx, - hw->removed, - hw->shutting_down, - hw->to_setup); -} -#endif - -static char *data_type(const unsigned char *buf, unsigned length) -{ - struct nl_packet_header *hdr = (struct nl_packet_header *) buf; - - if (length == 0) - return " "; - - if (hdr->packet_rank & NL_FIRST_PACKET) { - switch (hdr->protocol) { - case TL_PROTOCOLID_COM_DATA: return "DATA "; - case TL_PROTOCOLID_COM_CTRL: return "CTRL "; - case TL_PROTOCOLID_SETUP: return "SETUP"; - default: return "???? "; - } - } else - return " "; -} - -#define DUMP_MAX_BYTES 64 - -static void dump_data_bytes(const char *type, const unsigned char *data, - unsigned length) -{ - char prefix[56]; - - sprintf(prefix, IPWIRELESS_PCCARD_NAME ": %s %s ", - type, data_type(data, length)); - print_hex_dump_bytes(prefix, 0, (void *)data, - length < DUMP_MAX_BYTES ? length : DUMP_MAX_BYTES); -} - -static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data, - unsigned length) -{ - int i; - unsigned long flags; - - start_timing(); - - if (length == 0) - return 0; - - if (length > hw->ll_mtu) - return -1; - - if (ipwireless_debug) - dump_data_bytes("send", data, length); - - spin_lock_irqsave(&hw->spinlock, flags); - - if (hw->hw_version == HW_VERSION_1) { - outw((unsigned short) length, hw->base_port + IODWR); - - for (i = 0; i < length; i += 2) { - unsigned short d = data[i]; - __le16 raw_data; - - if (likely(i + 1 < length)) - d |= data[i + 1] << 8; - raw_data = cpu_to_le16(d); - outw(raw_data, hw->base_port + IODWR); - } - - outw(DCR_TXDONE, hw->base_port + IODCR); - } else if (hw->hw_version == HW_VERSION_2) { - outw((unsigned short) length, hw->base_port + IODMADPR); - - for (i = 0; i < length; i += 2) { - unsigned short d = data[i]; - __le16 raw_data; - - if ((i + 1 < length)) - d |= data[i + 1] << 8; - raw_data = cpu_to_le16(d); - outw(raw_data, hw->base_port + IODMADPR); - } - while ((i & 3) != 2) { - outw((unsigned short) 0xDEAD, hw->base_port + IODMADPR); - i += 2; - } - writew(MEMRX_RX, &hw->memory_info_regs->memreg_rx); - } - - spin_unlock_irqrestore(&hw->spinlock, flags); - - end_write_timing(length); - - return 0; -} - -static int do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet) -{ - unsigned short fragment_data_len; - unsigned short data_left = packet->length - packet->offset; - unsigned short header_size; - union nl_packet pkt; - - header_size = - (packet->fragment_count == 0) - ? NL_FIRST_PACKET_HEADER_SIZE - : NL_FOLLOWING_PACKET_HEADER_SIZE; - fragment_data_len = hw->ll_mtu - header_size; - if (data_left < fragment_data_len) - fragment_data_len = data_left; - - pkt.hdr_first.protocol = packet->protocol; - pkt.hdr_first.address = packet->dest_addr; - pkt.hdr_first.packet_rank = 0; - - /* First packet? */ - if (packet->fragment_count == 0) { - pkt.hdr_first.packet_rank |= NL_FIRST_PACKET; - pkt.hdr_first.length_lsb = (unsigned char) packet->length; - pkt.hdr_first.length_msb = - (unsigned char) (packet->length >> 8); - } - - memcpy(pkt.rawpkt + header_size, - ((unsigned char *) packet) + sizeof(struct ipw_tx_packet) + - packet->offset, fragment_data_len); - packet->offset += fragment_data_len; - packet->fragment_count++; - - /* Last packet? (May also be first packet.) */ - if (packet->offset == packet->length) - pkt.hdr_first.packet_rank |= NL_LAST_PACKET; - do_send_fragment(hw, pkt.rawpkt, header_size + fragment_data_len); - - /* If this packet has unsent data, then re-queue it. */ - if (packet->offset < packet->length) { - /* - * Re-queue it at the head of the highest priority queue so - * it goes before all other packets - */ - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - list_add(&packet->queue, &hw->tx_queue[0]); - spin_unlock_irqrestore(&hw->spinlock, flags); - } else { - if (packet->packet_callback) - packet->packet_callback(packet->callback_data, - packet->length); - kfree(packet); - } - - return 0; -} - -static void ipw_setup_hardware(struct ipw_hardware *hw) -{ - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - if (hw->hw_version == HW_VERSION_1) { - /* Reset RX FIFO */ - outw(DCR_RXRESET, hw->base_port + IODCR); - /* SB: Reset TX FIFO */ - outw(DCR_TXRESET, hw->base_port + IODCR); - - /* Enable TX and RX interrupts. */ - outw(IER_TXENABLED | IER_RXENABLED, hw->base_port + IOIER); - } else { - /* - * Set INTRACK bit (bit 0), which means we must explicitly - * acknowledge interrupts by clearing bit 2 of reg_config_and_status. - */ - unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status); - - csr |= 1; - writew(csr, &hw->memregs_CCR->reg_config_and_status); - } - spin_unlock_irqrestore(&hw->spinlock, flags); -} - -/* - * If 'packet' is NULL, then this function allocates a new packet, setting its - * length to 0 and ensuring it has the specified minimum amount of free space. - * - * If 'packet' is not NULL, then this function enlarges it if it doesn't - * have the specified minimum amount of free space. - * - */ -static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw, - struct ipw_rx_packet *packet, - int minimum_free_space) -{ - - if (!packet) { - unsigned long flags; - - /* - * If this is the first fragment, then we will need to fetch a - * packet to put it in. - */ - spin_lock_irqsave(&hw->spinlock, flags); - /* If we have one in our pool, then pull it out. */ - if (!list_empty(&hw->rx_pool)) { - packet = list_first_entry(&hw->rx_pool, - struct ipw_rx_packet, queue); - list_del(&packet->queue); - hw->rx_pool_size--; - spin_unlock_irqrestore(&hw->spinlock, flags); - } else { - /* Otherwise allocate a new one. */ - static int min_capacity = 256; - int new_capacity; - - spin_unlock_irqrestore(&hw->spinlock, flags); - new_capacity = - minimum_free_space > min_capacity - ? minimum_free_space - : min_capacity; - packet = kmalloc(sizeof(struct ipw_rx_packet) - + new_capacity, GFP_ATOMIC); - if (!packet) - return NULL; - packet->capacity = new_capacity; - } - packet->length = 0; - } - - /* - * If this packet does not have sufficient capacity for the data we - * want to add, then make it bigger. - */ - if (packet->length + minimum_free_space > packet->capacity) { - struct ipw_rx_packet *old_packet = packet; - - packet = kmalloc(sizeof(struct ipw_rx_packet) + - old_packet->length + minimum_free_space, - GFP_ATOMIC); - if (!packet) - return NULL; - memcpy(packet, old_packet, - sizeof(struct ipw_rx_packet) - + old_packet->length); - packet->capacity = old_packet->length + minimum_free_space; - kfree(old_packet); - } - - return packet; -} - -static void pool_free(struct ipw_hardware *hw, struct ipw_rx_packet *packet) -{ - if (hw->rx_pool_size > 6) - kfree(packet); - else { - hw->rx_pool_size++; - list_add_tail(&packet->queue, &hw->rx_pool); - } -} - -static void queue_received_packet(struct ipw_hardware *hw, - unsigned int protocol, unsigned int address, - unsigned char *data, int length, int is_last) -{ - unsigned int channel_idx = address - 1; - struct ipw_rx_packet *packet = NULL; - unsigned long flags; - - /* Discard packet if channel index is out of range. */ - if (channel_idx >= NL_NUM_OF_ADDRESSES) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": data packet has bad address %u\n", address); - return; - } - - /* - * ->packet_assembler is safe to touch unlocked, this is the only place - */ - if (protocol == TL_PROTOCOLID_COM_DATA) { - struct ipw_rx_packet **assem = - &hw->packet_assembler[channel_idx]; - - /* - * Create a new packet, or assembler already contains one - * enlarge it by 'length' bytes. - */ - (*assem) = pool_allocate(hw, *assem, length); - if (!(*assem)) { - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": no memory for incomming data packet, dropped!\n"); - return; - } - (*assem)->protocol = protocol; - (*assem)->channel_idx = channel_idx; - - /* Append this packet data onto existing data. */ - memcpy((unsigned char *)(*assem) + - sizeof(struct ipw_rx_packet) - + (*assem)->length, data, length); - (*assem)->length += length; - if (is_last) { - packet = *assem; - *assem = NULL; - /* Count queued DATA bytes only */ - spin_lock_irqsave(&hw->spinlock, flags); - hw->rx_bytes_queued += packet->length; - spin_unlock_irqrestore(&hw->spinlock, flags); - } - } else { - /* If it's a CTRL packet, don't assemble, just queue it. */ - packet = pool_allocate(hw, NULL, length); - if (!packet) { - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": no memory for incomming ctrl packet, dropped!\n"); - return; - } - packet->protocol = protocol; - packet->channel_idx = channel_idx; - memcpy((unsigned char *)packet + sizeof(struct ipw_rx_packet), - data, length); - packet->length = length; - } - - /* - * If this is the last packet, then send the assembled packet on to the - * network layer. - */ - if (packet) { - spin_lock_irqsave(&hw->spinlock, flags); - list_add_tail(&packet->queue, &hw->rx_queue); - /* Block reception of incoming packets if queue is full. */ - hw->blocking_rx = - hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE; - - spin_unlock_irqrestore(&hw->spinlock, flags); - schedule_work(&hw->work_rx); - } -} - -/* - * Workqueue callback - */ -static void ipw_receive_data_work(struct work_struct *work_rx) -{ - struct ipw_hardware *hw = - container_of(work_rx, struct ipw_hardware, work_rx); - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - while (!list_empty(&hw->rx_queue)) { - struct ipw_rx_packet *packet = - list_first_entry(&hw->rx_queue, - struct ipw_rx_packet, queue); - - if (hw->shutting_down) - break; - list_del(&packet->queue); - - /* - * Note: ipwireless_network_packet_received must be called in a - * process context (i.e. via schedule_work) because the tty - * output code can sleep in the tty_flip_buffer_push call. - */ - if (packet->protocol == TL_PROTOCOLID_COM_DATA) { - if (hw->network != NULL) { - /* If the network hasn't been disconnected. */ - spin_unlock_irqrestore(&hw->spinlock, flags); - /* - * This must run unlocked due to tty processing - * and mutex locking - */ - ipwireless_network_packet_received( - hw->network, - packet->channel_idx, - (unsigned char *)packet - + sizeof(struct ipw_rx_packet), - packet->length); - spin_lock_irqsave(&hw->spinlock, flags); - } - /* Count queued DATA bytes only */ - hw->rx_bytes_queued -= packet->length; - } else { - /* - * This is safe to be called locked, callchain does - * not block - */ - handle_received_CTRL_packet(hw, packet->channel_idx, - (unsigned char *)packet - + sizeof(struct ipw_rx_packet), - packet->length); - } - pool_free(hw, packet); - /* - * Unblock reception of incoming packets if queue is no longer - * full. - */ - hw->blocking_rx = - hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE; - if (hw->shutting_down) - break; - } - spin_unlock_irqrestore(&hw->spinlock, flags); -} - -static void handle_received_CTRL_packet(struct ipw_hardware *hw, - unsigned int channel_idx, - unsigned char *data, int len) -{ - struct ipw_control_packet_body *body = - (struct ipw_control_packet_body *) data; - unsigned int changed_mask; - - if (len != sizeof(struct ipw_control_packet_body)) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": control packet was %d bytes - wrong size!\n", - len); - return; - } - - switch (body->sig_no) { - case COMCTRL_CTS: - changed_mask = IPW_CONTROL_LINE_CTS; - break; - case COMCTRL_DCD: - changed_mask = IPW_CONTROL_LINE_DCD; - break; - case COMCTRL_DSR: - changed_mask = IPW_CONTROL_LINE_DSR; - break; - case COMCTRL_RI: - changed_mask = IPW_CONTROL_LINE_RI; - break; - default: - changed_mask = 0; - } - - if (changed_mask != 0) { - if (body->value) - hw->control_lines[channel_idx] |= changed_mask; - else - hw->control_lines[channel_idx] &= ~changed_mask; - if (hw->network) - ipwireless_network_notify_control_line_change( - hw->network, - channel_idx, - hw->control_lines[channel_idx], - changed_mask); - } -} - -static void handle_received_packet(struct ipw_hardware *hw, - union nl_packet *packet, - unsigned short len) -{ - unsigned int protocol = packet->hdr.protocol; - unsigned int address = packet->hdr.address; - unsigned int header_length; - unsigned char *data; - unsigned int data_len; - int is_last = packet->hdr.packet_rank & NL_LAST_PACKET; - - if (packet->hdr.packet_rank & NL_FIRST_PACKET) - header_length = NL_FIRST_PACKET_HEADER_SIZE; - else - header_length = NL_FOLLOWING_PACKET_HEADER_SIZE; - - data = packet->rawpkt + header_length; - data_len = len - header_length; - switch (protocol) { - case TL_PROTOCOLID_COM_DATA: - case TL_PROTOCOLID_COM_CTRL: - queue_received_packet(hw, protocol, address, data, data_len, - is_last); - break; - case TL_PROTOCOLID_SETUP: - handle_received_SETUP_packet(hw, address, data, data_len, - is_last); - break; - } -} - -static void acknowledge_data_read(struct ipw_hardware *hw) -{ - if (hw->hw_version == HW_VERSION_1) - outw(DCR_RXDONE, hw->base_port + IODCR); - else - writew(MEMRX_PCINTACKK, - &hw->memory_info_regs->memreg_pc_interrupt_ack); -} - -/* - * Retrieve a packet from the IPW hardware. - */ -static void do_receive_packet(struct ipw_hardware *hw) -{ - unsigned len; - unsigned int i; - unsigned char pkt[LL_MTU_MAX]; - - start_timing(); - - if (hw->hw_version == HW_VERSION_1) { - len = inw(hw->base_port + IODRR); - if (len > hw->ll_mtu) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": received a packet of %u bytes - " - "longer than the MTU!\n", len); - outw(DCR_RXDONE | DCR_RXRESET, hw->base_port + IODCR); - return; - } - - for (i = 0; i < len; i += 2) { - __le16 raw_data = inw(hw->base_port + IODRR); - unsigned short data = le16_to_cpu(raw_data); - - pkt[i] = (unsigned char) data; - pkt[i + 1] = (unsigned char) (data >> 8); - } - } else { - len = inw(hw->base_port + IODMADPR); - if (len > hw->ll_mtu) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": received a packet of %u bytes - " - "longer than the MTU!\n", len); - writew(MEMRX_PCINTACKK, - &hw->memory_info_regs->memreg_pc_interrupt_ack); - return; - } - - for (i = 0; i < len; i += 2) { - __le16 raw_data = inw(hw->base_port + IODMADPR); - unsigned short data = le16_to_cpu(raw_data); - - pkt[i] = (unsigned char) data; - pkt[i + 1] = (unsigned char) (data >> 8); - } - - while ((i & 3) != 2) { - inw(hw->base_port + IODMADPR); - i += 2; - } - } - - acknowledge_data_read(hw); - - if (ipwireless_debug) - dump_data_bytes("recv", pkt, len); - - handle_received_packet(hw, (union nl_packet *) pkt, len); - - end_read_timing(len); -} - -static int get_current_packet_priority(struct ipw_hardware *hw) -{ - /* - * If we're initializing, don't send anything of higher priority than - * PRIO_SETUP. The network layer therefore need not care about - * hardware initialization - any of its stuff will simply be queued - * until setup is complete. - */ - return (hw->to_setup || hw->initializing - ? PRIO_SETUP + 1 : - NL_NUM_OF_PRIORITIES); -} - -/* - * return 1 if something has been received from hw - */ -static int get_packets_from_hw(struct ipw_hardware *hw) -{ - int received = 0; - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - while (hw->rx_ready && !hw->blocking_rx) { - received = 1; - hw->rx_ready--; - spin_unlock_irqrestore(&hw->spinlock, flags); - - do_receive_packet(hw); - - spin_lock_irqsave(&hw->spinlock, flags); - } - spin_unlock_irqrestore(&hw->spinlock, flags); - - return received; -} - -/* - * Send pending packet up to given priority, prioritize SETUP data until - * hardware is fully setup. - * - * return 1 if more packets can be sent - */ -static int send_pending_packet(struct ipw_hardware *hw, int priority_limit) -{ - int more_to_send = 0; - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - if (hw->tx_queued && hw->tx_ready != 0) { - int priority; - struct ipw_tx_packet *packet = NULL; - - hw->tx_ready--; - - /* Pick a packet */ - for (priority = 0; priority < priority_limit; priority++) { - if (!list_empty(&hw->tx_queue[priority])) { - packet = list_first_entry( - &hw->tx_queue[priority], - struct ipw_tx_packet, - queue); - - list_del(&packet->queue); - - break; - } - } - if (!packet) { - hw->tx_queued = 0; - spin_unlock_irqrestore(&hw->spinlock, flags); - return 0; - } - spin_unlock_irqrestore(&hw->spinlock, flags); - - /* Send */ - do_send_packet(hw, packet); - - /* Check if more to send */ - spin_lock_irqsave(&hw->spinlock, flags); - for (priority = 0; priority < priority_limit; priority++) - if (!list_empty(&hw->tx_queue[priority])) { - more_to_send = 1; - break; - } - - if (!more_to_send) - hw->tx_queued = 0; - } - spin_unlock_irqrestore(&hw->spinlock, flags); - - return more_to_send; -} - -/* - * Send and receive all queued packets. - */ -static void ipwireless_do_tasklet(unsigned long hw_) -{ - struct ipw_hardware *hw = (struct ipw_hardware *) hw_; - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - if (hw->shutting_down) { - spin_unlock_irqrestore(&hw->spinlock, flags); - return; - } - - if (hw->to_setup == 1) { - /* - * Initial setup data sent to hardware - */ - hw->to_setup = 2; - spin_unlock_irqrestore(&hw->spinlock, flags); - - ipw_setup_hardware(hw); - ipw_send_setup_packet(hw); - - send_pending_packet(hw, PRIO_SETUP + 1); - get_packets_from_hw(hw); - } else { - int priority_limit = get_current_packet_priority(hw); - int again; - - spin_unlock_irqrestore(&hw->spinlock, flags); - - do { - again = send_pending_packet(hw, priority_limit); - again |= get_packets_from_hw(hw); - } while (again); - } -} - -/* - * return true if the card is physically present. - */ -static int is_card_present(struct ipw_hardware *hw) -{ - if (hw->hw_version == HW_VERSION_1) - return inw(hw->base_port + IOIR) != 0xFFFF; - else - return readl(&hw->memory_info_regs->memreg_card_present) == - CARD_PRESENT_VALUE; -} - -static irqreturn_t ipwireless_handle_v1_interrupt(int irq, - struct ipw_hardware *hw) -{ - unsigned short irqn; - - irqn = inw(hw->base_port + IOIR); - - /* Check if card is present */ - if (irqn == 0xFFFF) - return IRQ_NONE; - else if (irqn != 0) { - unsigned short ack = 0; - unsigned long flags; - - /* Transmit complete. */ - if (irqn & IR_TXINTR) { - ack |= IR_TXINTR; - spin_lock_irqsave(&hw->spinlock, flags); - hw->tx_ready++; - spin_unlock_irqrestore(&hw->spinlock, flags); - } - /* Received data */ - if (irqn & IR_RXINTR) { - ack |= IR_RXINTR; - spin_lock_irqsave(&hw->spinlock, flags); - hw->rx_ready++; - spin_unlock_irqrestore(&hw->spinlock, flags); - } - if (ack != 0) { - outw(ack, hw->base_port + IOIR); - tasklet_schedule(&hw->tasklet); - } - return IRQ_HANDLED; - } - return IRQ_NONE; -} - -static void acknowledge_pcmcia_interrupt(struct ipw_hardware *hw) -{ - unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status); - - csr &= 0xfffd; - writew(csr, &hw->memregs_CCR->reg_config_and_status); -} - -static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq, - struct ipw_hardware *hw) -{ - int tx = 0; - int rx = 0; - int rx_repeat = 0; - int try_mem_tx_old; - unsigned long flags; - - do { - - unsigned short memtx = readw(hw->memreg_tx); - unsigned short memtx_serial; - unsigned short memrxdone = - readw(&hw->memory_info_regs->memreg_rx_done); - - try_mem_tx_old = 0; - - /* check whether the interrupt was generated by ipwireless card */ - if (!(memtx & MEMTX_TX) && !(memrxdone & MEMRX_RX_DONE)) { - - /* check if the card uses memreg_tx_old register */ - if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { - memtx = readw(&hw->memory_info_regs->memreg_tx_old); - if (memtx & MEMTX_TX) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": Using memreg_tx_old\n"); - hw->memreg_tx = - &hw->memory_info_regs->memreg_tx_old; - } else { - return IRQ_NONE; - } - } else { - return IRQ_NONE; - } - } - - /* - * See if the card is physically present. Note that while it is - * powering up, it appears not to be present. - */ - if (!is_card_present(hw)) { - acknowledge_pcmcia_interrupt(hw); - return IRQ_HANDLED; - } - - memtx_serial = memtx & (unsigned short) 0xff00; - if (memtx & MEMTX_TX) { - writew(memtx_serial, hw->memreg_tx); - - if (hw->serial_number_detected) { - if (memtx_serial != hw->last_memtx_serial) { - hw->last_memtx_serial = memtx_serial; - spin_lock_irqsave(&hw->spinlock, flags); - hw->rx_ready++; - spin_unlock_irqrestore(&hw->spinlock, flags); - rx = 1; - } else - /* Ignore 'Timer Recovery' duplicates. */ - rx_repeat = 1; - } else { - /* - * If a non-zero serial number is seen, then enable - * serial number checking. - */ - if (memtx_serial != 0) { - hw->serial_number_detected = 1; - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME - ": memreg_tx serial num detected\n"); - - spin_lock_irqsave(&hw->spinlock, flags); - hw->rx_ready++; - spin_unlock_irqrestore(&hw->spinlock, flags); - } - rx = 1; - } - } - if (memrxdone & MEMRX_RX_DONE) { - writew(0, &hw->memory_info_regs->memreg_rx_done); - spin_lock_irqsave(&hw->spinlock, flags); - hw->tx_ready++; - spin_unlock_irqrestore(&hw->spinlock, flags); - tx = 1; - } - if (tx) - writew(MEMRX_PCINTACKK, - &hw->memory_info_regs->memreg_pc_interrupt_ack); - - acknowledge_pcmcia_interrupt(hw); - - if (tx || rx) - tasklet_schedule(&hw->tasklet); - else if (!rx_repeat) { - if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { - if (hw->serial_number_detected) - printk(KERN_WARNING IPWIRELESS_PCCARD_NAME - ": spurious interrupt - new_tx mode\n"); - else { - printk(KERN_WARNING IPWIRELESS_PCCARD_NAME - ": no valid memreg_tx value - " - "switching to the old memreg_tx\n"); - hw->memreg_tx = - &hw->memory_info_regs->memreg_tx_old; - try_mem_tx_old = 1; - } - } else - printk(KERN_WARNING IPWIRELESS_PCCARD_NAME - ": spurious interrupt - old_tx mode\n"); - } - - } while (try_mem_tx_old == 1); - - return IRQ_HANDLED; -} - -irqreturn_t ipwireless_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct ipw_hardware *hw = dev_id; - - if (hw->hw_version == HW_VERSION_1) - return ipwireless_handle_v1_interrupt(irq, hw); - else - return ipwireless_handle_v2_v3_interrupt(irq, hw); -} - -static void flush_packets_to_hw(struct ipw_hardware *hw) -{ - int priority_limit; - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - priority_limit = get_current_packet_priority(hw); - spin_unlock_irqrestore(&hw->spinlock, flags); - - while (send_pending_packet(hw, priority_limit)); -} - -static void send_packet(struct ipw_hardware *hw, int priority, - struct ipw_tx_packet *packet) -{ - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - list_add_tail(&packet->queue, &hw->tx_queue[priority]); - hw->tx_queued = 1; - spin_unlock_irqrestore(&hw->spinlock, flags); - - flush_packets_to_hw(hw); -} - -/* Create data packet, non-atomic allocation */ -static void *alloc_data_packet(int data_size, - unsigned char dest_addr, - unsigned char protocol) -{ - struct ipw_tx_packet *packet = kzalloc( - sizeof(struct ipw_tx_packet) + data_size, - GFP_ATOMIC); - - if (!packet) - return NULL; - - INIT_LIST_HEAD(&packet->queue); - packet->dest_addr = dest_addr; - packet->protocol = protocol; - packet->length = data_size; - - return packet; -} - -static void *alloc_ctrl_packet(int header_size, - unsigned char dest_addr, - unsigned char protocol, - unsigned char sig_no) -{ - /* - * sig_no is located right after ipw_tx_packet struct in every - * CTRL or SETUP packets, we can use ipw_control_packet as a - * common struct - */ - struct ipw_control_packet *packet = kzalloc(header_size, GFP_ATOMIC); - - if (!packet) - return NULL; - - INIT_LIST_HEAD(&packet->header.queue); - packet->header.dest_addr = dest_addr; - packet->header.protocol = protocol; - packet->header.length = header_size - sizeof(struct ipw_tx_packet); - packet->body.sig_no = sig_no; - - return packet; -} - -int ipwireless_send_packet(struct ipw_hardware *hw, unsigned int channel_idx, - unsigned char *data, unsigned int length, - void (*callback) (void *cb, unsigned int length), - void *callback_data) -{ - struct ipw_tx_packet *packet; - - packet = alloc_data_packet(length, - (unsigned char) (channel_idx + 1), - TL_PROTOCOLID_COM_DATA); - if (!packet) - return -ENOMEM; - packet->packet_callback = callback; - packet->callback_data = callback_data; - memcpy((unsigned char *) packet + - sizeof(struct ipw_tx_packet), data, length); - - send_packet(hw, PRIO_DATA, packet); - return 0; -} - -static int set_control_line(struct ipw_hardware *hw, int prio, - unsigned int channel_idx, int line, int state) -{ - struct ipw_control_packet *packet; - int protocolid = TL_PROTOCOLID_COM_CTRL; - - if (prio == PRIO_SETUP) - protocolid = TL_PROTOCOLID_SETUP; - - packet = alloc_ctrl_packet(sizeof(struct ipw_control_packet), - (unsigned char) (channel_idx + 1), - protocolid, line); - if (!packet) - return -ENOMEM; - packet->header.length = sizeof(struct ipw_control_packet_body); - packet->body.value = (unsigned char) (state == 0 ? 0 : 1); - send_packet(hw, prio, &packet->header); - return 0; -} - - -static int set_DTR(struct ipw_hardware *hw, int priority, - unsigned int channel_idx, int state) -{ - if (state != 0) - hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_DTR; - else - hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_DTR; - - return set_control_line(hw, priority, channel_idx, COMCTRL_DTR, state); -} - -static int set_RTS(struct ipw_hardware *hw, int priority, - unsigned int channel_idx, int state) -{ - if (state != 0) - hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_RTS; - else - hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_RTS; - - return set_control_line(hw, priority, channel_idx, COMCTRL_RTS, state); -} - -int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx, - int state) -{ - return set_DTR(hw, PRIO_CTRL, channel_idx, state); -} - -int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx, - int state) -{ - return set_RTS(hw, PRIO_CTRL, channel_idx, state); -} - -struct ipw_setup_get_version_query_packet { - struct ipw_tx_packet header; - struct tl_setup_get_version_qry body; -}; - -struct ipw_setup_config_packet { - struct ipw_tx_packet header; - struct tl_setup_config_msg body; -}; - -struct ipw_setup_config_done_packet { - struct ipw_tx_packet header; - struct tl_setup_config_done_msg body; -}; - -struct ipw_setup_open_packet { - struct ipw_tx_packet header; - struct tl_setup_open_msg body; -}; - -struct ipw_setup_info_packet { - struct ipw_tx_packet header; - struct tl_setup_info_msg body; -}; - -struct ipw_setup_reboot_msg_ack { - struct ipw_tx_packet header; - struct TlSetupRebootMsgAck body; -}; - -/* This handles the actual initialization of the card */ -static void __handle_setup_get_version_rsp(struct ipw_hardware *hw) -{ - struct ipw_setup_config_packet *config_packet; - struct ipw_setup_config_done_packet *config_done_packet; - struct ipw_setup_open_packet *open_packet; - struct ipw_setup_info_packet *info_packet; - int port; - unsigned int channel_idx; - - /* generate config packet */ - for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) { - config_packet = alloc_ctrl_packet( - sizeof(struct ipw_setup_config_packet), - ADDR_SETUP_PROT, - TL_PROTOCOLID_SETUP, - TL_SETUP_SIGNO_CONFIG_MSG); - if (!config_packet) - goto exit_nomem; - config_packet->header.length = sizeof(struct tl_setup_config_msg); - config_packet->body.port_no = port; - config_packet->body.prio_data = PRIO_DATA; - config_packet->body.prio_ctrl = PRIO_CTRL; - send_packet(hw, PRIO_SETUP, &config_packet->header); - } - config_done_packet = alloc_ctrl_packet( - sizeof(struct ipw_setup_config_done_packet), - ADDR_SETUP_PROT, - TL_PROTOCOLID_SETUP, - TL_SETUP_SIGNO_CONFIG_DONE_MSG); - if (!config_done_packet) - goto exit_nomem; - config_done_packet->header.length = sizeof(struct tl_setup_config_done_msg); - send_packet(hw, PRIO_SETUP, &config_done_packet->header); - - /* generate open packet */ - for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) { - open_packet = alloc_ctrl_packet( - sizeof(struct ipw_setup_open_packet), - ADDR_SETUP_PROT, - TL_PROTOCOLID_SETUP, - TL_SETUP_SIGNO_OPEN_MSG); - if (!open_packet) - goto exit_nomem; - open_packet->header.length = sizeof(struct tl_setup_open_msg); - open_packet->body.port_no = port; - send_packet(hw, PRIO_SETUP, &open_packet->header); - } - for (channel_idx = 0; - channel_idx < NL_NUM_OF_ADDRESSES; channel_idx++) { - int ret; - - ret = set_DTR(hw, PRIO_SETUP, channel_idx, - (hw->control_lines[channel_idx] & - IPW_CONTROL_LINE_DTR) != 0); - if (ret) { - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": error setting DTR (%d)\n", ret); - return; - } - - set_RTS(hw, PRIO_SETUP, channel_idx, - (hw->control_lines [channel_idx] & - IPW_CONTROL_LINE_RTS) != 0); - if (ret) { - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": error setting RTS (%d)\n", ret); - return; - } - } - /* - * For NDIS we assume that we are using sync PPP frames, for COM async. - * This driver uses NDIS mode too. We don't bother with translation - * from async -> sync PPP. - */ - info_packet = alloc_ctrl_packet(sizeof(struct ipw_setup_info_packet), - ADDR_SETUP_PROT, - TL_PROTOCOLID_SETUP, - TL_SETUP_SIGNO_INFO_MSG); - if (!info_packet) - goto exit_nomem; - info_packet->header.length = sizeof(struct tl_setup_info_msg); - info_packet->body.driver_type = NDISWAN_DRIVER; - info_packet->body.major_version = NDISWAN_DRIVER_MAJOR_VERSION; - info_packet->body.minor_version = NDISWAN_DRIVER_MINOR_VERSION; - send_packet(hw, PRIO_SETUP, &info_packet->header); - - /* Initialization is now complete, so we clear the 'to_setup' flag */ - hw->to_setup = 0; - - return; - -exit_nomem: - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": not enough memory to alloc control packet\n"); - hw->to_setup = -1; -} - -static void handle_setup_get_version_rsp(struct ipw_hardware *hw, - unsigned char vers_no) -{ - del_timer(&hw->setup_timer); - hw->initializing = 0; - printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": card is ready.\n"); - - if (vers_no == TL_SETUP_VERSION) - __handle_setup_get_version_rsp(hw); - else - printk(KERN_ERR - IPWIRELESS_PCCARD_NAME - ": invalid hardware version no %u\n", - (unsigned int) vers_no); -} - -static void ipw_send_setup_packet(struct ipw_hardware *hw) -{ - struct ipw_setup_get_version_query_packet *ver_packet; - - ver_packet = alloc_ctrl_packet( - sizeof(struct ipw_setup_get_version_query_packet), - ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, - TL_SETUP_SIGNO_GET_VERSION_QRY); - ver_packet->header.length = sizeof(struct tl_setup_get_version_qry); - - /* - * Response is handled in handle_received_SETUP_packet - */ - send_packet(hw, PRIO_SETUP, &ver_packet->header); -} - -static void handle_received_SETUP_packet(struct ipw_hardware *hw, - unsigned int address, - unsigned char *data, int len, - int is_last) -{ - union ipw_setup_rx_msg *rx_msg = (union ipw_setup_rx_msg *) data; - - if (address != ADDR_SETUP_PROT) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": setup packet has bad address %d\n", address); - return; - } - - switch (rx_msg->sig_no) { - case TL_SETUP_SIGNO_GET_VERSION_RSP: - if (hw->to_setup) - handle_setup_get_version_rsp(hw, - rx_msg->version_rsp_msg.version); - break; - - case TL_SETUP_SIGNO_OPEN_MSG: - if (ipwireless_debug) { - unsigned int channel_idx = rx_msg->open_msg.port_no - 1; - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": OPEN_MSG [channel %u] reply received\n", - channel_idx); - } - break; - - case TL_SETUP_SIGNO_INFO_MSG_ACK: - if (ipwireless_debug) - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME - ": card successfully configured as NDISWAN\n"); - break; - - case TL_SETUP_SIGNO_REBOOT_MSG: - if (hw->to_setup) - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME - ": Setup not completed - ignoring reboot msg\n"); - else { - struct ipw_setup_reboot_msg_ack *packet; - - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME - ": Acknowledging REBOOT message\n"); - packet = alloc_ctrl_packet( - sizeof(struct ipw_setup_reboot_msg_ack), - ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, - TL_SETUP_SIGNO_REBOOT_MSG_ACK); - packet->header.length = - sizeof(struct TlSetupRebootMsgAck); - send_packet(hw, PRIO_SETUP, &packet->header); - if (hw->reboot_callback) - hw->reboot_callback(hw->reboot_callback_data); - } - break; - - default: - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": unknown setup message %u received\n", - (unsigned int) rx_msg->sig_no); - } -} - -static void do_close_hardware(struct ipw_hardware *hw) -{ - unsigned int irqn; - - if (hw->hw_version == HW_VERSION_1) { - /* Disable TX and RX interrupts. */ - outw(0, hw->base_port + IOIER); - - /* Acknowledge any outstanding interrupt requests */ - irqn = inw(hw->base_port + IOIR); - if (irqn & IR_TXINTR) - outw(IR_TXINTR, hw->base_port + IOIR); - if (irqn & IR_RXINTR) - outw(IR_RXINTR, hw->base_port + IOIR); - - synchronize_irq(hw->irq); - } -} - -struct ipw_hardware *ipwireless_hardware_create(void) -{ - int i; - struct ipw_hardware *hw = - kzalloc(sizeof(struct ipw_hardware), GFP_KERNEL); - - if (!hw) - return NULL; - - hw->irq = -1; - hw->initializing = 1; - hw->tx_ready = 1; - hw->rx_bytes_queued = 0; - hw->rx_pool_size = 0; - hw->last_memtx_serial = (unsigned short) 0xffff; - for (i = 0; i < NL_NUM_OF_PRIORITIES; i++) - INIT_LIST_HEAD(&hw->tx_queue[i]); - - INIT_LIST_HEAD(&hw->rx_queue); - INIT_LIST_HEAD(&hw->rx_pool); - spin_lock_init(&hw->spinlock); - tasklet_init(&hw->tasklet, ipwireless_do_tasklet, (unsigned long) hw); - INIT_WORK(&hw->work_rx, ipw_receive_data_work); - setup_timer(&hw->setup_timer, ipwireless_setup_timer, - (unsigned long) hw); - - return hw; -} - -void ipwireless_init_hardware_v1(struct ipw_hardware *hw, - unsigned int base_port, - void __iomem *attr_memory, - void __iomem *common_memory, - int is_v2_card, - void (*reboot_callback) (void *data), - void *reboot_callback_data) -{ - if (hw->removed) { - hw->removed = 0; - enable_irq(hw->irq); - } - hw->base_port = base_port; - hw->hw_version = is_v2_card ? HW_VERSION_2 : HW_VERSION_1; - hw->ll_mtu = hw->hw_version == HW_VERSION_1 ? LL_MTU_V1 : LL_MTU_V2; - hw->memregs_CCR = (struct MEMCCR __iomem *) - ((unsigned short __iomem *) attr_memory + 0x200); - hw->memory_info_regs = (struct MEMINFREG __iomem *) common_memory; - hw->memreg_tx = &hw->memory_info_regs->memreg_tx_new; - hw->reboot_callback = reboot_callback; - hw->reboot_callback_data = reboot_callback_data; -} - -void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw) -{ - hw->initializing = 1; - hw->init_loops = 0; - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": waiting for card to start up...\n"); - ipwireless_setup_timer((unsigned long) hw); -} - -static void ipwireless_setup_timer(unsigned long data) -{ - struct ipw_hardware *hw = (struct ipw_hardware *) data; - - hw->init_loops++; - - if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY && - hw->hw_version == HW_VERSION_2 && - hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": failed to startup using TX2, trying TX\n"); - - hw->memreg_tx = &hw->memory_info_regs->memreg_tx_old; - hw->init_loops = 0; - } - /* Give up after a certain number of retries */ - if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY) { - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": card failed to start up!\n"); - hw->initializing = 0; - } else { - /* Do not attempt to write to the board if it is not present. */ - if (is_card_present(hw)) { - unsigned long flags; - - spin_lock_irqsave(&hw->spinlock, flags); - hw->to_setup = 1; - hw->tx_ready = 1; - spin_unlock_irqrestore(&hw->spinlock, flags); - tasklet_schedule(&hw->tasklet); - } - - mod_timer(&hw->setup_timer, - jiffies + msecs_to_jiffies(TL_SETUP_VERSION_QRY_TMO)); - } -} - -/* - * Stop any interrupts from executing so that, once this function returns, - * other layers of the driver can be sure they won't get any more callbacks. - * Thus must be called on a proper process context. - */ -void ipwireless_stop_interrupts(struct ipw_hardware *hw) -{ - if (!hw->shutting_down) { - /* Tell everyone we are going down. */ - hw->shutting_down = 1; - del_timer(&hw->setup_timer); - - /* Prevent the hardware from sending any more interrupts */ - do_close_hardware(hw); - } -} - -void ipwireless_hardware_free(struct ipw_hardware *hw) -{ - int i; - struct ipw_rx_packet *rp, *rq; - struct ipw_tx_packet *tp, *tq; - - ipwireless_stop_interrupts(hw); - - flush_scheduled_work(); - - for (i = 0; i < NL_NUM_OF_ADDRESSES; i++) - if (hw->packet_assembler[i] != NULL) - kfree(hw->packet_assembler[i]); - - for (i = 0; i < NL_NUM_OF_PRIORITIES; i++) - list_for_each_entry_safe(tp, tq, &hw->tx_queue[i], queue) { - list_del(&tp->queue); - kfree(tp); - } - - list_for_each_entry_safe(rp, rq, &hw->rx_queue, queue) { - list_del(&rp->queue); - kfree(rp); - } - - list_for_each_entry_safe(rp, rq, &hw->rx_pool, queue) { - list_del(&rp->queue); - kfree(rp); - } - kfree(hw); -} - -/* - * Associate the specified network with this hardware, so it will receive events - * from it. - */ -void ipwireless_associate_network(struct ipw_hardware *hw, - struct ipw_network *network) -{ - hw->network = network; -} diff --git a/trunk/drivers/char/pcmcia/ipwireless/hardware.h b/trunk/drivers/char/pcmcia/ipwireless/hardware.h deleted file mode 100644 index c83190ffb0e7..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/hardware.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#ifndef _IPWIRELESS_CS_HARDWARE_H_ -#define _IPWIRELESS_CS_HARDWARE_H_ - -#include -#include -#include - -#define IPW_CONTROL_LINE_CTS 0x0001 -#define IPW_CONTROL_LINE_DCD 0x0002 -#define IPW_CONTROL_LINE_DSR 0x0004 -#define IPW_CONTROL_LINE_RI 0x0008 -#define IPW_CONTROL_LINE_DTR 0x0010 -#define IPW_CONTROL_LINE_RTS 0x0020 - -struct ipw_hardware; -struct ipw_network; - -struct ipw_hardware *ipwireless_hardware_create(void); -void ipwireless_hardware_free(struct ipw_hardware *hw); -irqreturn_t ipwireless_interrupt(int irq, void *dev_id, struct pt_regs *regs); -int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx, - int state); -int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx, - int state); -int ipwireless_send_packet(struct ipw_hardware *hw, - unsigned int channel_idx, - unsigned char *data, - unsigned int length, - void (*packet_sent_callback) (void *cb, - unsigned int length), - void *sent_cb_data); -void ipwireless_associate_network(struct ipw_hardware *hw, - struct ipw_network *net); -void ipwireless_stop_interrupts(struct ipw_hardware *hw); -void ipwireless_init_hardware_v1(struct ipw_hardware *hw, - unsigned int base_port, - void __iomem *attr_memory, - void __iomem *common_memory, - int is_v2_card, - void (*reboot_cb) (void *data), - void *reboot_cb_data); -void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw); -void ipwireless_sleep(unsigned int tenths); -int ipwireless_dump_hardware_state(char *p, size_t limit, - struct ipw_hardware *hw); - -#endif diff --git a/trunk/drivers/char/pcmcia/ipwireless/main.c b/trunk/drivers/char/pcmcia/ipwireless/main.c deleted file mode 100644 index 00c7f8407e3e..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/main.c +++ /dev/null @@ -1,501 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#include "hardware.h" -#include "network.h" -#include "main.h" -#include "tty.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -static struct pcmcia_device_id ipw_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100), - PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, ipw_ids); - -static void ipwireless_detach(struct pcmcia_device *link); - -/* - * Module params - */ -/* Debug mode: more verbose, print sent/recv bytes */ -int ipwireless_debug; -int ipwireless_loopback; -int ipwireless_out_queue = 1; - -module_param_named(debug, ipwireless_debug, int, 0); -module_param_named(loopback, ipwireless_loopback, int, 0); -module_param_named(out_queue, ipwireless_out_queue, int, 0); -MODULE_PARM_DESC(debug, "switch on debug messages [0]"); -MODULE_PARM_DESC(loopback, - "debug: enable ras_raw channel [0]"); -MODULE_PARM_DESC(out_queue, "debug: set size of outgoing queue [1]"); - -/* Executes in process context. */ -static void signalled_reboot_work(struct work_struct *work_reboot) -{ - struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev, - work_reboot); - struct pcmcia_device *link = ipw->link; - int ret = pccard_reset_card(link->socket); - - if (ret != CS_SUCCESS) - cs_error(link, ResetCard, ret); -} - -static void signalled_reboot_callback(void *callback_data) -{ - struct ipw_dev *ipw = (struct ipw_dev *) callback_data; - - /* Delegate to process context. */ - schedule_work(&ipw->work_reboot); -} - -static int config_ipwireless(struct ipw_dev *ipw) -{ - struct pcmcia_device *link = ipw->link; - int ret; - config_info_t conf; - tuple_t tuple; - unsigned short buf[64]; - cisparse_t parse; - unsigned short cor_value; - win_req_t request_attr_memory; - win_req_t request_common_memory; - memreq_t memreq_attr_memory; - memreq_t memreq_common_memory; - - ipw->is_v2_card = 0; - - tuple.Attributes = 0; - tuple.TupleData = (cisdata_t *) buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - - tuple.DesiredTuple = RETURN_FIRST_TUPLE; - - ret = pcmcia_get_first_tuple(link, &tuple); - - while (ret == 0) { - ret = pcmcia_get_tuple_data(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetTupleData, ret); - goto exit0; - } - ret = pcmcia_get_next_tuple(link, &tuple); - } - - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - - ret = pcmcia_get_first_tuple(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetFirstTuple, ret); - goto exit0; - } - - ret = pcmcia_get_tuple_data(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetTupleData, ret); - goto exit0; - } - - ret = pcmcia_parse_tuple(link, &tuple, &parse); - - if (ret != CS_SUCCESS) { - cs_error(link, ParseTuple, ret); - goto exit0; - } - - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - link->io.BasePort1 = parse.cftable_entry.io.win[0].base; - link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; - link->io.IOAddrLines = 16; - - link->irq.IRQInfo1 = parse.cftable_entry.irq.IRQInfo1; - - /* 0x40 causes it to generate level mode interrupts. */ - /* 0x04 enables IREQ pin. */ - cor_value = parse.cftable_entry.index | 0x44; - link->conf.ConfigIndex = cor_value; - - /* IRQ and I/O settings */ - tuple.DesiredTuple = CISTPL_CONFIG; - - ret = pcmcia_get_first_tuple(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetFirstTuple, ret); - goto exit0; - } - - ret = pcmcia_get_tuple_data(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetTupleData, ret); - goto exit0; - } - - ret = pcmcia_parse_tuple(link, &tuple, &parse); - - if (ret != CS_SUCCESS) { - cs_error(link, GetTupleData, ret); - goto exit0; - } - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - link->conf.IntType = INT_MEMORY_AND_IO; - - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - link->irq.Handler = ipwireless_interrupt; - link->irq.Instance = ipw->hardware; - - ret = pcmcia_request_io(link, &link->io); - - if (ret != CS_SUCCESS) { - cs_error(link, RequestIO, ret); - goto exit0; - } - - /* memory settings */ - - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - - ret = pcmcia_get_first_tuple(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetFirstTuple, ret); - goto exit1; - } - - ret = pcmcia_get_tuple_data(link, &tuple); - - if (ret != CS_SUCCESS) { - cs_error(link, GetTupleData, ret); - goto exit1; - } - - ret = pcmcia_parse_tuple(link, &tuple, &parse); - - if (ret != CS_SUCCESS) { - cs_error(link, ParseTuple, ret); - goto exit1; - } - - if (parse.cftable_entry.mem.nwin > 0) { - request_common_memory.Attributes = - WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; - request_common_memory.Base = - parse.cftable_entry.mem.win[0].host_addr; - request_common_memory.Size = parse.cftable_entry.mem.win[0].len; - if (request_common_memory.Size < 0x1000) - request_common_memory.Size = 0x1000; - request_common_memory.AccessSpeed = 0; - - ret = pcmcia_request_window(&link, &request_common_memory, - &ipw->handle_common_memory); - - if (ret != CS_SUCCESS) { - cs_error(link, RequestWindow, ret); - goto exit1; - } - - memreq_common_memory.CardOffset = - parse.cftable_entry.mem.win[0].card_addr; - memreq_common_memory.Page = 0; - - ret = pcmcia_map_mem_page(ipw->handle_common_memory, - &memreq_common_memory); - - if (ret != CS_SUCCESS) { - cs_error(link, MapMemPage, ret); - goto exit1; - } - - ipw->is_v2_card = - parse.cftable_entry.mem.win[0].len == 0x100; - - ipw->common_memory = ioremap(request_common_memory.Base, - request_common_memory.Size); - - request_attr_memory.Attributes = - WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE; - request_attr_memory.Base = 0; - request_attr_memory.Size = 0; /* this used to be 0x1000 */ - request_attr_memory.AccessSpeed = 0; - - ret = pcmcia_request_window(&link, &request_attr_memory, - &ipw->handle_attr_memory); - - if (ret != CS_SUCCESS) { - cs_error(link, RequestWindow, ret); - goto exit2; - } - - memreq_attr_memory.CardOffset = 0; - memreq_attr_memory.Page = 0; - - ret = pcmcia_map_mem_page(ipw->handle_attr_memory, - &memreq_attr_memory); - - if (ret != CS_SUCCESS) { - cs_error(link, MapMemPage, ret); - goto exit2; - } - - ipw->attr_memory = ioremap(request_attr_memory.Base, - request_attr_memory.Size); - } - - INIT_WORK(&ipw->work_reboot, signalled_reboot_work); - - ipwireless_init_hardware_v1(ipw->hardware, link->io.BasePort1, - ipw->attr_memory, ipw->common_memory, - ipw->is_v2_card, signalled_reboot_callback, - ipw); - - ret = pcmcia_request_irq(link, &link->irq); - - if (ret != CS_SUCCESS) { - cs_error(link, RequestIRQ, ret); - goto exit3; - } - - /* Look up current Vcc */ - - ret = pcmcia_get_configuration_info(link, &conf); - - if (ret != CS_SUCCESS) { - cs_error(link, GetConfigurationInfo, ret); - goto exit4; - } - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n", - ipw->is_v2_card ? "V2/V3" : "V1"); - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": I/O ports 0x%04x-0x%04x, irq %d\n", - (unsigned int) link->io.BasePort1, - (unsigned int) (link->io.BasePort1 + - link->io.NumPorts1 - 1), - (unsigned int) link->irq.AssignedIRQ); - if (ipw->attr_memory && ipw->common_memory) - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": attr memory 0x%08lx-0x%08lx, " - "common memory 0x%08lx-0x%08lx\n", - request_attr_memory.Base, - request_attr_memory.Base - + request_attr_memory.Size - 1, - request_common_memory.Base, - request_common_memory.Base - + request_common_memory.Size - 1); - - ipw->network = ipwireless_network_create(ipw->hardware); - if (!ipw->network) - goto exit3; - - ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network, - ipw->nodes); - if (!ipw->tty) - goto exit3; - - ipwireless_init_hardware_v2_v3(ipw->hardware); - - /* - * Do the RequestConfiguration last, because it enables interrupts. - * Then we don't get any interrupts before we're ready for them. - */ - ret = pcmcia_request_configuration(link, &link->conf); - - if (ret != CS_SUCCESS) { - cs_error(link, RequestConfiguration, ret); - goto exit4; - } - - link->dev_node = &ipw->nodes[0]; - - return 0; - -exit4: - pcmcia_disable_device(link); -exit3: - if (ipw->attr_memory) { - iounmap(ipw->attr_memory); - pcmcia_release_window(ipw->handle_attr_memory); - pcmcia_disable_device(link); - } -exit2: - if (ipw->common_memory) { - iounmap(ipw->common_memory); - pcmcia_release_window(ipw->handle_common_memory); - } -exit1: - pcmcia_disable_device(link); -exit0: - return -1; -} - -static void release_ipwireless(struct ipw_dev *ipw) -{ - struct pcmcia_device *link = ipw->link; - - pcmcia_disable_device(link); - - if (ipw->common_memory) - iounmap(ipw->common_memory); - if (ipw->attr_memory) - iounmap(ipw->attr_memory); - if (ipw->common_memory) - pcmcia_release_window(ipw->handle_common_memory); - if (ipw->attr_memory) - pcmcia_release_window(ipw->handle_attr_memory); - pcmcia_disable_device(link); -} - -/* - * ipwireless_attach() creates an "instance" of the driver, allocating - * local data structures for one device (one interface). The device - * is registered with Card Services. - * - * The pcmcia_device structure is initialized, but we don't actually - * configure the card at this point -- we wait until we receive a - * card insertion event. - */ -static int ipwireless_attach(struct pcmcia_device *link) -{ - struct ipw_dev *ipw; - int ret; - - ipw = kzalloc(sizeof(struct ipw_dev), GFP_KERNEL); - if (!ipw) - return -ENOMEM; - - ipw->link = link; - link->priv = ipw; - link->irq.Instance = ipw; - - /* Link this device into our device list. */ - link->dev_node = &ipw->nodes[0]; - - ipw->hardware = ipwireless_hardware_create(); - if (!ipw->hardware) { - kfree(ipw); - return -ENOMEM; - } - /* RegisterClient will call config_ipwireless */ - - ret = config_ipwireless(ipw); - - if (ret != 0) { - cs_error(link, RegisterClient, ret); - ipwireless_detach(link); - return ret; - } - - return 0; -} - -/* - * This deletes a driver "instance". The device is de-registered with - * Card Services. If it has been released, all local data structures - * are freed. Otherwise, the structures will be freed when the device - * is released. - */ -static void ipwireless_detach(struct pcmcia_device *link) -{ - struct ipw_dev *ipw = link->priv; - - release_ipwireless(ipw); - - /* Break the link with Card Services */ - if (link) - pcmcia_disable_device(link); - - if (ipw->tty != NULL) - ipwireless_tty_free(ipw->tty); - if (ipw->network != NULL) - ipwireless_network_free(ipw->network); - if (ipw->hardware != NULL) - ipwireless_hardware_free(ipw->hardware); - kfree(ipw); -} - -static struct pcmcia_driver me = { - .owner = THIS_MODULE, - .probe = ipwireless_attach, - .remove = ipwireless_detach, - .drv = { .name = IPWIRELESS_PCCARD_NAME }, - .id_table = ipw_ids -}; - -/* - * Module insertion : initialisation of the module. - * Register the card with cardmgr... - */ -static int __init init_ipwireless(void) -{ - int ret; - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME " " - IPWIRELESS_PCMCIA_VERSION " by " IPWIRELESS_PCMCIA_AUTHOR "\n"); - - ret = ipwireless_tty_init(); - if (ret != 0) - return ret; - - ret = pcmcia_register_driver(&me); - if (ret != 0) - ipwireless_tty_release(); - - return ret; -} - -/* - * Module removal - */ -static void __exit exit_ipwireless(void) -{ - printk(KERN_INFO IPWIRELESS_PCCARD_NAME " " - IPWIRELESS_PCMCIA_VERSION " removed\n"); - - pcmcia_unregister_driver(&me); - ipwireless_tty_release(); -} - -module_init(init_ipwireless); -module_exit(exit_ipwireless); - -MODULE_AUTHOR(IPWIRELESS_PCMCIA_AUTHOR); -MODULE_DESCRIPTION(IPWIRELESS_PCCARD_NAME " " IPWIRELESS_PCMCIA_VERSION); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/char/pcmcia/ipwireless/main.h b/trunk/drivers/char/pcmcia/ipwireless/main.h deleted file mode 100644 index 1bfdcc8d47d6..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/main.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#ifndef _IPWIRELESS_CS_H_ -#define _IPWIRELESS_CS_H_ - -#include -#include - -#include -#include -#include -#include - -#include "hardware.h" - -#define IPWIRELESS_PCCARD_NAME "ipwireless" -#define IPWIRELESS_PCMCIA_VERSION "1.1" -#define IPWIRELESS_PCMCIA_AUTHOR \ - "Stephen Blackheath, Ben Martel, Jiri Kosina and David Sterba" - -#define IPWIRELESS_TX_QUEUE_SIZE 262144 -#define IPWIRELESS_RX_QUEUE_SIZE 262144 - -#define IPWIRELESS_STATE_DEBUG - -struct ipw_hardware; -struct ipw_network; -struct ipw_tty; - -struct ipw_dev { - struct pcmcia_device *link; - int is_v2_card; - window_handle_t handle_attr_memory; - void __iomem *attr_memory; - window_handle_t handle_common_memory; - void __iomem *common_memory; - dev_node_t nodes[2]; - /* Reference to attribute memory, containing CIS data */ - void *attribute_memory; - - /* Hardware context */ - struct ipw_hardware *hardware; - /* Network layer context */ - struct ipw_network *network; - /* TTY device context */ - struct ipw_tty *tty; - struct work_struct work_reboot; -}; - -/* Module parametres */ -extern int ipwireless_debug; -extern int ipwireless_loopback; -extern int ipwireless_out_queue; - -#endif diff --git a/trunk/drivers/char/pcmcia/ipwireless/network.c b/trunk/drivers/char/pcmcia/ipwireless/network.c deleted file mode 100644 index ff35230058d3..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/network.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "network.h" -#include "hardware.h" -#include "main.h" -#include "tty.h" - -#define MAX_OUTGOING_PACKETS_QUEUED ipwireless_out_queue -#define MAX_ASSOCIATED_TTYS 2 - -#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) - -struct ipw_network { - /* Hardware context, used for calls to hardware layer. */ - struct ipw_hardware *hardware; - /* Context for kernel 'generic_ppp' functionality */ - struct ppp_channel *ppp_channel; - /* tty context connected with IPW console */ - struct ipw_tty *associated_ttys[NO_OF_IPW_CHANNELS][MAX_ASSOCIATED_TTYS]; - /* True if ppp needs waking up once we're ready to xmit */ - int ppp_blocked; - /* Number of packets queued up in hardware module. */ - int outgoing_packets_queued; - /* Spinlock to avoid interrupts during shutdown */ - spinlock_t spinlock; - struct mutex close_lock; - - /* PPP ioctl data, not actually used anywere */ - unsigned int flags; - unsigned int rbits; - u32 xaccm[8]; - u32 raccm; - int mru; - - int shutting_down; - unsigned int ras_control_lines; - - struct work_struct work_go_online; - struct work_struct work_go_offline; -}; - - -#ifdef IPWIRELESS_STATE_DEBUG -int ipwireless_dump_network_state(char *p, size_t limit, - struct ipw_network *network) -{ - return snprintf(p, limit, - "debug: ppp_blocked=%d\n" - "debug: outgoing_packets_queued=%d\n" - "debug: network.shutting_down=%d\n", - network->ppp_blocked, - network->outgoing_packets_queued, - network->shutting_down); -} -#endif - -static void notify_packet_sent(void *callback_data, unsigned int packet_length) -{ - struct ipw_network *network = callback_data; - unsigned long flags; - - spin_lock_irqsave(&network->spinlock, flags); - network->outgoing_packets_queued--; - if (network->ppp_channel != NULL) { - if (network->ppp_blocked) { - network->ppp_blocked = 0; - spin_unlock_irqrestore(&network->spinlock, flags); - ppp_output_wakeup(network->ppp_channel); - if (ipwireless_debug) - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": ppp unblocked\n"); - } else - spin_unlock_irqrestore(&network->spinlock, flags); - } else - spin_unlock_irqrestore(&network->spinlock, flags); -} - -/* - * Called by the ppp system when it has a packet to send to the hardware. - */ -static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel, - struct sk_buff *skb) -{ - struct ipw_network *network = ppp_channel->private; - unsigned long flags; - - spin_lock_irqsave(&network->spinlock, flags); - if (network->outgoing_packets_queued < MAX_OUTGOING_PACKETS_QUEUED) { - unsigned char *buf; - static unsigned char header[] = { - PPP_ALLSTATIONS, /* 0xff */ - PPP_UI, /* 0x03 */ - }; - int ret; - - network->outgoing_packets_queued++; - spin_unlock_irqrestore(&network->spinlock, flags); - - /* - * If we have the requested amount of headroom in the skb we - * were handed, then we can add the header efficiently. - */ - if (skb_headroom(skb) >= 2) { - memcpy(skb_push(skb, 2), header, 2); - ret = ipwireless_send_packet(network->hardware, - IPW_CHANNEL_RAS, skb->data, - skb->len, - notify_packet_sent, - network); - if (ret == -1) { - skb_pull(skb, 2); - return 0; - } - } else { - /* Otherwise (rarely) we do it inefficiently. */ - buf = kmalloc(skb->len + 2, GFP_ATOMIC); - if (!buf) - return 0; - memcpy(buf + 2, skb->data, skb->len); - memcpy(buf, header, 2); - ret = ipwireless_send_packet(network->hardware, - IPW_CHANNEL_RAS, buf, - skb->len + 2, - notify_packet_sent, - network); - kfree(buf); - if (ret == -1) - return 0; - } - kfree_skb(skb); - return 1; - } else { - /* - * Otherwise reject the packet, and flag that the ppp system - * needs to be unblocked once we are ready to send. - */ - network->ppp_blocked = 1; - spin_unlock_irqrestore(&network->spinlock, flags); - return 0; - } -} - -/* Handle an ioctl call that has come in via ppp. (copy of ppp_async_ioctl() */ -static int ipwireless_ppp_ioctl(struct ppp_channel *ppp_channel, - unsigned int cmd, unsigned long arg) -{ - struct ipw_network *network = ppp_channel->private; - int err, val; - u32 accm[8]; - int __user *user_arg = (int __user *) arg; - - err = -EFAULT; - switch (cmd) { - case PPPIOCGFLAGS: - val = network->flags | network->rbits; - if (put_user(val, user_arg)) - break; - err = 0; - break; - - case PPPIOCSFLAGS: - if (get_user(val, user_arg)) - break; - network->flags = val & ~SC_RCV_BITS; - network->rbits = val & SC_RCV_BITS; - err = 0; - break; - - case PPPIOCGASYNCMAP: - if (put_user(network->xaccm[0], user_arg)) - break; - err = 0; - break; - - case PPPIOCSASYNCMAP: - if (get_user(network->xaccm[0], user_arg)) - break; - err = 0; - break; - - case PPPIOCGRASYNCMAP: - if (put_user(network->raccm, user_arg)) - break; - err = 0; - break; - - case PPPIOCSRASYNCMAP: - if (get_user(network->raccm, user_arg)) - break; - err = 0; - break; - - case PPPIOCGXASYNCMAP: - if (copy_to_user((void __user *) arg, network->xaccm, - sizeof(network->xaccm))) - break; - err = 0; - break; - - case PPPIOCSXASYNCMAP: - if (copy_from_user(accm, (void __user *) arg, sizeof(accm))) - break; - accm[2] &= ~0x40000000U; /* can't escape 0x5e */ - accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */ - memcpy(network->xaccm, accm, sizeof(network->xaccm)); - err = 0; - break; - - case PPPIOCGMRU: - if (put_user(network->mru, user_arg)) - break; - err = 0; - break; - - case PPPIOCSMRU: - if (get_user(val, user_arg)) - break; - if (val < PPP_MRU) - val = PPP_MRU; - network->mru = val; - err = 0; - break; - - default: - err = -ENOTTY; - } - - return err; -} - -static struct ppp_channel_ops ipwireless_ppp_channel_ops = { - .start_xmit = ipwireless_ppp_start_xmit, - .ioctl = ipwireless_ppp_ioctl -}; - -static void do_go_online(struct work_struct *work_go_online) -{ - struct ipw_network *network = - container_of(work_go_online, struct ipw_network, - work_go_online); - unsigned long flags; - - spin_lock_irqsave(&network->spinlock, flags); - if (!network->ppp_channel) { - struct ppp_channel *channel; - - spin_unlock_irqrestore(&network->spinlock, flags); - channel = kzalloc(sizeof(struct ppp_channel), GFP_KERNEL); - if (!channel) { - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": unable to allocate PPP channel\n"); - return; - } - channel->private = network; - channel->mtu = 16384; /* Wild guess */ - channel->hdrlen = 2; - channel->ops = &ipwireless_ppp_channel_ops; - - network->flags = 0; - network->rbits = 0; - network->mru = PPP_MRU; - memset(network->xaccm, 0, sizeof(network->xaccm)); - network->xaccm[0] = ~0U; - network->xaccm[3] = 0x60000000U; - network->raccm = ~0U; - ppp_register_channel(channel); - spin_lock_irqsave(&network->spinlock, flags); - network->ppp_channel = channel; - } - spin_unlock_irqrestore(&network->spinlock, flags); -} - -static void do_go_offline(struct work_struct *work_go_offline) -{ - struct ipw_network *network = - container_of(work_go_offline, struct ipw_network, - work_go_offline); - unsigned long flags; - - mutex_lock(&network->close_lock); - spin_lock_irqsave(&network->spinlock, flags); - if (network->ppp_channel != NULL) { - struct ppp_channel *channel = network->ppp_channel; - - network->ppp_channel = NULL; - spin_unlock_irqrestore(&network->spinlock, flags); - mutex_unlock(&network->close_lock); - ppp_unregister_channel(channel); - } else { - spin_unlock_irqrestore(&network->spinlock, flags); - mutex_unlock(&network->close_lock); - } -} - -void ipwireless_network_notify_control_line_change(struct ipw_network *network, - unsigned int channel_idx, - unsigned int control_lines, - unsigned int changed_mask) -{ - int i; - - if (channel_idx == IPW_CHANNEL_RAS) - network->ras_control_lines = control_lines; - - for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) { - struct ipw_tty *tty = - network->associated_ttys[channel_idx][i]; - - /* - * If it's associated with a tty (other than the RAS channel - * when we're online), then send the data to that tty. The RAS - * channel's data is handled above - it always goes through - * ppp_generic. - */ - if (tty) - ipwireless_tty_notify_control_line_change(tty, - channel_idx, - control_lines, - changed_mask); - } -} - -/* - * Some versions of firmware stuff packets with 0xff 0x03 (PPP: ALLSTATIONS, UI) - * bytes, which are required on sent packet, but not always present on received - * packets - */ -static struct sk_buff *ipw_packet_received_skb(unsigned char *data, - unsigned int length) -{ - struct sk_buff *skb; - - if (length > 2 && data[0] == PPP_ALLSTATIONS && data[1] == PPP_UI) { - length -= 2; - data += 2; - } - - skb = dev_alloc_skb(length + 4); - skb_reserve(skb, 2); - memcpy(skb_put(skb, length), data, length); - - return skb; -} - -void ipwireless_network_packet_received(struct ipw_network *network, - unsigned int channel_idx, - unsigned char *data, - unsigned int length) -{ - int i; - unsigned long flags; - - for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) { - struct ipw_tty *tty = network->associated_ttys[channel_idx][i]; - - /* - * If it's associated with a tty (other than the RAS channel - * when we're online), then send the data to that tty. The RAS - * channel's data is handled above - it always goes through - * ppp_generic. - */ - if (tty && channel_idx == IPW_CHANNEL_RAS - && (network->ras_control_lines & - IPW_CONTROL_LINE_DCD) != 0 - && ipwireless_tty_is_modem(tty)) { - /* - * If data came in on the RAS channel and this tty is - * the modem tty, and we are online, then we send it to - * the PPP layer. - */ - mutex_lock(&network->close_lock); - spin_lock_irqsave(&network->spinlock, flags); - if (network->ppp_channel != NULL) { - struct sk_buff *skb; - - spin_unlock_irqrestore(&network->spinlock, - flags); - - /* Send the data to the ppp_generic module. */ - skb = ipw_packet_received_skb(data, length); - ppp_input(network->ppp_channel, skb); - } else - spin_unlock_irqrestore(&network->spinlock, - flags); - mutex_unlock(&network->close_lock); - } - /* Otherwise we send it out the tty. */ - else - ipwireless_tty_received(tty, data, length); - } -} - -struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw) -{ - struct ipw_network *network = - kzalloc(sizeof(struct ipw_network), GFP_ATOMIC); - - if (!network) - return NULL; - - spin_lock_init(&network->spinlock); - mutex_init(&network->close_lock); - - network->hardware = hw; - - INIT_WORK(&network->work_go_online, do_go_online); - INIT_WORK(&network->work_go_offline, do_go_offline); - - ipwireless_associate_network(hw, network); - - return network; -} - -void ipwireless_network_free(struct ipw_network *network) -{ - network->shutting_down = 1; - - ipwireless_ppp_close(network); - flush_scheduled_work(); - - ipwireless_stop_interrupts(network->hardware); - ipwireless_associate_network(network->hardware, NULL); - - kfree(network); -} - -void ipwireless_associate_network_tty(struct ipw_network *network, - unsigned int channel_idx, - struct ipw_tty *tty) -{ - int i; - - for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) - if (network->associated_ttys[channel_idx][i] == NULL) { - network->associated_ttys[channel_idx][i] = tty; - break; - } -} - -void ipwireless_disassociate_network_ttys(struct ipw_network *network, - unsigned int channel_idx) -{ - int i; - - for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) - network->associated_ttys[channel_idx][i] = NULL; -} - -void ipwireless_ppp_open(struct ipw_network *network) -{ - if (ipwireless_debug) - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": online\n"); - schedule_work(&network->work_go_online); -} - -void ipwireless_ppp_close(struct ipw_network *network) -{ - /* Disconnect from the wireless network. */ - if (ipwireless_debug) - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": offline\n"); - schedule_work(&network->work_go_offline); -} - -int ipwireless_ppp_channel_index(struct ipw_network *network) -{ - int ret = -1; - unsigned long flags; - - spin_lock_irqsave(&network->spinlock, flags); - if (network->ppp_channel != NULL) - ret = ppp_channel_index(network->ppp_channel); - spin_unlock_irqrestore(&network->spinlock, flags); - - return ret; -} - -int ipwireless_ppp_unit_number(struct ipw_network *network) -{ - int ret = -1; - unsigned long flags; - - spin_lock_irqsave(&network->spinlock, flags); - if (network->ppp_channel != NULL) - ret = ppp_unit_number(network->ppp_channel); - spin_unlock_irqrestore(&network->spinlock, flags); - - return ret; -} diff --git a/trunk/drivers/char/pcmcia/ipwireless/network.h b/trunk/drivers/char/pcmcia/ipwireless/network.h deleted file mode 100644 index b0e1e952fd14..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/network.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#ifndef _IPWIRELESS_CS_NETWORK_H_ -#define _IPWIRELESS_CS_NETWORK_H_ - -#include - -struct ipw_network; -struct ipw_tty; -struct ipw_hardware; - -/* Definitions of the different channels on the PCMCIA UE */ -#define IPW_CHANNEL_RAS 0 -#define IPW_CHANNEL_DIALLER 1 -#define IPW_CHANNEL_CONSOLE 2 -#define NO_OF_IPW_CHANNELS 5 - -void ipwireless_network_notify_control_line_change(struct ipw_network *net, - unsigned int channel_idx, unsigned int control_lines, - unsigned int control_mask); -void ipwireless_network_packet_received(struct ipw_network *net, - unsigned int channel_idx, unsigned char *data, - unsigned int length); -struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw); -void ipwireless_network_free(struct ipw_network *net); -void ipwireless_associate_network_tty(struct ipw_network *net, - unsigned int channel_idx, struct ipw_tty *tty); -void ipwireless_disassociate_network_ttys(struct ipw_network *net, - unsigned int channel_idx); - -void ipwireless_ppp_open(struct ipw_network *net); - -void ipwireless_ppp_close(struct ipw_network *net); -int ipwireless_ppp_channel_index(struct ipw_network *net); -int ipwireless_ppp_unit_number(struct ipw_network *net); - -int ipwireless_dump_network_state(char *p, size_t limit, - struct ipw_network *net); - -#endif diff --git a/trunk/drivers/char/pcmcia/ipwireless/setup_protocol.h b/trunk/drivers/char/pcmcia/ipwireless/setup_protocol.h deleted file mode 100644 index 9d6bcc77c73c..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/setup_protocol.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#ifndef _IPWIRELESS_CS_SETUP_PROTOCOL_H_ -#define _IPWIRELESS_CS_SETUP_PROTOCOL_H_ - -/* Version of the setup protocol and transport protocols */ -#define TL_SETUP_VERSION 1 - -#define TL_SETUP_VERSION_QRY_TMO 1000 -#define TL_SETUP_MAX_VERSION_QRY 30 - -/* Message numbers 0-9 are obsoleted and must not be reused! */ -#define TL_SETUP_SIGNO_GET_VERSION_QRY 10 -#define TL_SETUP_SIGNO_GET_VERSION_RSP 11 -#define TL_SETUP_SIGNO_CONFIG_MSG 12 -#define TL_SETUP_SIGNO_CONFIG_DONE_MSG 13 -#define TL_SETUP_SIGNO_OPEN_MSG 14 -#define TL_SETUP_SIGNO_CLOSE_MSG 15 - -#define TL_SETUP_SIGNO_INFO_MSG 20 -#define TL_SETUP_SIGNO_INFO_MSG_ACK 21 - -#define TL_SETUP_SIGNO_REBOOT_MSG 22 -#define TL_SETUP_SIGNO_REBOOT_MSG_ACK 23 - -/* Synchronous start-messages */ -struct tl_setup_get_version_qry { - unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_QRY */ -} __attribute__ ((__packed__)); - -struct tl_setup_get_version_rsp { - unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_RSP */ - unsigned char version; /* TL_SETUP_VERSION */ -} __attribute__ ((__packed__)); - -struct tl_setup_config_msg { - unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_MSG */ - unsigned char port_no; - unsigned char prio_data; - unsigned char prio_ctrl; -} __attribute__ ((__packed__)); - -struct tl_setup_config_done_msg { - unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_DONE_MSG */ -} __attribute__ ((__packed__)); - -/* Asyncronous messages */ -struct tl_setup_open_msg { - unsigned char sig_no; /* TL_SETUP_SIGNO_OPEN_MSG */ - unsigned char port_no; -} __attribute__ ((__packed__)); - -struct tl_setup_close_msg { - unsigned char sig_no; /* TL_SETUP_SIGNO_CLOSE_MSG */ - unsigned char port_no; -} __attribute__ ((__packed__)); - -/* Driver type - for use in tl_setup_info_msg.driver_type */ -#define COMM_DRIVER 0 -#define NDISWAN_DRIVER 1 -#define NDISWAN_DRIVER_MAJOR_VERSION 2 -#define NDISWAN_DRIVER_MINOR_VERSION 0 - -/* - * It should not matter when this message comes over as we just store the - * results and send the ACK. - */ -struct tl_setup_info_msg { - unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG */ - unsigned char driver_type; - unsigned char major_version; - unsigned char minor_version; -} __attribute__ ((__packed__)); - -struct tl_setup_info_msgAck { - unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG_ACK */ -} __attribute__ ((__packed__)); - -struct TlSetupRebootMsgAck { - unsigned char sig_no; /* TL_SETUP_SIGNO_REBOOT_MSG_ACK */ -} __attribute__ ((__packed__)); - -/* Define a union of all the msgs that the driver can receive from the card.*/ -union ipw_setup_rx_msg { - unsigned char sig_no; - struct tl_setup_get_version_rsp version_rsp_msg; - struct tl_setup_open_msg open_msg; - struct tl_setup_close_msg close_msg; - struct tl_setup_info_msg InfoMsg; - struct tl_setup_info_msgAck info_msg_ack; -} __attribute__ ((__packed__)); - -#endif /* _IPWIRELESS_CS_SETUP_PROTOCOL_H_ */ diff --git a/trunk/drivers/char/pcmcia/ipwireless/tty.c b/trunk/drivers/char/pcmcia/ipwireless/tty.c deleted file mode 100644 index 42f3815c5ce3..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/tty.c +++ /dev/null @@ -1,688 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tty.h" -#include "network.h" -#include "hardware.h" -#include "main.h" - -#define IPWIRELESS_PCMCIA_START (0) -#define IPWIRELESS_PCMCIA_MINORS (24) -#define IPWIRELESS_PCMCIA_MINOR_RANGE (8) - -#define TTYTYPE_MODEM (0) -#define TTYTYPE_MONITOR (1) -#define TTYTYPE_RAS_RAW (2) - -struct ipw_tty { - int index; - struct ipw_hardware *hardware; - unsigned int channel_idx; - unsigned int secondary_channel_idx; - int tty_type; - struct ipw_network *network; - struct tty_struct *linux_tty; - int open_count; - unsigned int control_lines; - struct mutex ipw_tty_mutex; - int tx_bytes_queued; - int closing; -}; - -static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS]; - -static struct tty_driver *ipw_tty_driver; - -static char *tty_type_name(int tty_type) -{ - static char *channel_names[] = { - "modem", - "monitor", - "RAS-raw" - }; - - return channel_names[tty_type]; -} - -static void report_registering(struct ipw_tty *tty) -{ - char *iftype = tty_type_name(tty->tty_type); - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": registering %s device ttyIPWp%d\n", iftype, tty->index); -} - -static void report_deregistering(struct ipw_tty *tty) -{ - char *iftype = tty_type_name(tty->tty_type); - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": deregistering %s device ttyIPWp%d\n", iftype, - tty->index); -} - -static struct ipw_tty *get_tty(int minor) -{ - if (minor < ipw_tty_driver->minor_start - || minor >= ipw_tty_driver->minor_start + - IPWIRELESS_PCMCIA_MINORS) - return NULL; - else { - int minor_offset = minor - ipw_tty_driver->minor_start; - - /* - * The 'ras_raw' channel is only available when 'loopback' mode - * is enabled. - * Number of minor starts with 16 (_RANGE * _RAS_RAW). - */ - if (!ipwireless_loopback && - minor_offset >= - IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW) - return NULL; - - return ttys[minor_offset]; - } -} - -static int ipw_open(struct tty_struct *linux_tty, struct file *filp) -{ - int minor = linux_tty->index; - struct ipw_tty *tty = get_tty(minor); - - if (!tty) - return -ENODEV; - - mutex_lock(&tty->ipw_tty_mutex); - - if (tty->closing) { - mutex_unlock(&tty->ipw_tty_mutex); - return -ENODEV; - } - if (tty->open_count == 0) - tty->tx_bytes_queued = 0; - - tty->open_count++; - - tty->linux_tty = linux_tty; - linux_tty->driver_data = tty; - linux_tty->low_latency = 1; - - if (tty->tty_type == TTYTYPE_MODEM) - ipwireless_ppp_open(tty->network); - - mutex_unlock(&tty->ipw_tty_mutex); - - return 0; -} - -static void do_ipw_close(struct ipw_tty *tty) -{ - tty->open_count--; - - if (tty->open_count == 0) { - struct tty_struct *linux_tty = tty->linux_tty; - - if (linux_tty != NULL) { - tty->linux_tty = NULL; - linux_tty->driver_data = NULL; - - if (tty->tty_type == TTYTYPE_MODEM) - ipwireless_ppp_close(tty->network); - } - } -} - -static void ipw_hangup(struct tty_struct *linux_tty) -{ - struct ipw_tty *tty = linux_tty->driver_data; - - if (!tty) - return; - - mutex_lock(&tty->ipw_tty_mutex); - if (tty->open_count == 0) { - mutex_unlock(&tty->ipw_tty_mutex); - return; - } - - do_ipw_close(tty); - - mutex_unlock(&tty->ipw_tty_mutex); -} - -static void ipw_close(struct tty_struct *linux_tty, struct file *filp) -{ - ipw_hangup(linux_tty); -} - -/* Take data received from hardware, and send it out the tty */ -void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, - unsigned int length) -{ - struct tty_struct *linux_tty; - int work = 0; - - mutex_lock(&tty->ipw_tty_mutex); - linux_tty = tty->linux_tty; - if (linux_tty == NULL) { - mutex_unlock(&tty->ipw_tty_mutex); - return; - } - - if (!tty->open_count) { - mutex_unlock(&tty->ipw_tty_mutex); - return; - } - mutex_unlock(&tty->ipw_tty_mutex); - - work = tty_insert_flip_string(linux_tty, data, length); - - if (work != length) - printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME - ": %d chars not inserted to flip buffer!\n", - length - work); - - /* - * This may sleep if ->low_latency is set - */ - if (work) - tty_flip_buffer_push(linux_tty); -} - -static void ipw_write_packet_sent_callback(void *callback_data, - unsigned int packet_length) -{ - struct ipw_tty *tty = callback_data; - - /* - * Packet has been sent, so we subtract the number of bytes from our - * tally of outstanding TX bytes. - */ - tty->tx_bytes_queued -= packet_length; -} - -static int ipw_write(struct tty_struct *linux_tty, - const unsigned char *buf, int count) -{ - struct ipw_tty *tty = linux_tty->driver_data; - int room, ret; - - if (!tty) - return -ENODEV; - - mutex_lock(&tty->ipw_tty_mutex); - if (!tty->open_count) { - mutex_unlock(&tty->ipw_tty_mutex); - return -EINVAL; - } - - room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; - if (room < 0) - room = 0; - /* Don't allow caller to write any more than we have room for */ - if (count > room) - count = room; - - if (count == 0) { - mutex_unlock(&tty->ipw_tty_mutex); - return 0; - } - - ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS, - (unsigned char *) buf, count, - ipw_write_packet_sent_callback, tty); - if (ret == -1) { - mutex_unlock(&tty->ipw_tty_mutex); - return 0; - } - - tty->tx_bytes_queued += count; - mutex_unlock(&tty->ipw_tty_mutex); - - return count; -} - -static int ipw_write_room(struct tty_struct *linux_tty) -{ - struct ipw_tty *tty = linux_tty->driver_data; - int room; - - if (!tty) - return -ENODEV; - - if (!tty->open_count) - return -EINVAL; - - room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; - if (room < 0) - room = 0; - - return room; -} - -static int ipwireless_get_serial_info(struct ipw_tty *tty, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return (-EFAULT); - - memset(&tmp, 0, sizeof(tmp)); - tmp.type = PORT_UNKNOWN; - tmp.line = tty->index; - tmp.port = 0; - tmp.irq = 0; - tmp.flags = 0; - tmp.baud_base = 115200; - tmp.close_delay = 0; - tmp.closing_wait = 0; - tmp.custom_divisor = 0; - tmp.hub6 = 0; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - - return 0; -} - -static int ipw_chars_in_buffer(struct tty_struct *linux_tty) -{ - struct ipw_tty *tty = linux_tty->driver_data; - - if (!tty) - return -ENODEV; - - if (!tty->open_count) - return -EINVAL; - - return tty->tx_bytes_queued; -} - -static int get_control_lines(struct ipw_tty *tty) -{ - unsigned int my = tty->control_lines; - unsigned int out = 0; - - if (my & IPW_CONTROL_LINE_RTS) - out |= TIOCM_RTS; - if (my & IPW_CONTROL_LINE_DTR) - out |= TIOCM_DTR; - if (my & IPW_CONTROL_LINE_CTS) - out |= TIOCM_CTS; - if (my & IPW_CONTROL_LINE_DSR) - out |= TIOCM_DSR; - if (my & IPW_CONTROL_LINE_DCD) - out |= TIOCM_CD; - - return out; -} - -static int set_control_lines(struct ipw_tty *tty, unsigned int set, - unsigned int clear) -{ - int ret; - - if (set & TIOCM_RTS) { - ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 1); - if (ret) - return ret; - if (tty->secondary_channel_idx != -1) { - ret = ipwireless_set_RTS(tty->hardware, - tty->secondary_channel_idx, 1); - if (ret) - return ret; - } - } - if (set & TIOCM_DTR) { - ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 1); - if (ret) - return ret; - if (tty->secondary_channel_idx != -1) { - ret = ipwireless_set_DTR(tty->hardware, - tty->secondary_channel_idx, 1); - if (ret) - return ret; - } - } - if (clear & TIOCM_RTS) { - ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 0); - if (tty->secondary_channel_idx != -1) { - ret = ipwireless_set_RTS(tty->hardware, - tty->secondary_channel_idx, 0); - if (ret) - return ret; - } - } - if (clear & TIOCM_DTR) { - ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 0); - if (tty->secondary_channel_idx != -1) { - ret = ipwireless_set_DTR(tty->hardware, - tty->secondary_channel_idx, 0); - if (ret) - return ret; - } - } - return 0; -} - -static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file) -{ - struct ipw_tty *tty = linux_tty->driver_data; - - if (!tty) - return -ENODEV; - - if (!tty->open_count) - return -EINVAL; - - return get_control_lines(tty); -} - -static int -ipw_tiocmset(struct tty_struct *linux_tty, struct file *file, - unsigned int set, unsigned int clear) -{ - struct ipw_tty *tty = linux_tty->driver_data; - - if (!tty) - return -ENODEV; - - if (!tty->open_count) - return -EINVAL; - - return set_control_lines(tty, set, clear); -} - -static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct ipw_tty *tty = linux_tty->driver_data; - - if (!tty) - return -ENODEV; - - if (!tty->open_count) - return -EINVAL; - - switch (cmd) { - case TIOCGSERIAL: - return ipwireless_get_serial_info(tty, (void __user *) arg); - - case TIOCSSERIAL: - return 0; /* Keeps the PCMCIA scripts happy. */ - } - - if (tty->tty_type == TTYTYPE_MODEM) { - switch (cmd) { - case PPPIOCGCHAN: - { - int chan = ipwireless_ppp_channel_index( - tty->network); - - if (chan < 0) - return -ENODEV; - if (put_user(chan, (int __user *) arg)) - return -EFAULT; - } - return 0; - - case PPPIOCGUNIT: - { - int unit = ipwireless_ppp_unit_number( - tty->network); - - if (unit < 0) - return -ENODEV; - if (put_user(unit, (int __user *) arg)) - return -EFAULT; - } - return 0; - - case TCGETS: - case TCGETA: - return n_tty_ioctl(linux_tty, file, cmd, arg); - - case TCFLSH: - return n_tty_ioctl(linux_tty, file, cmd, arg); - - case FIONREAD: - { - int val = 0; - - if (put_user(val, (int __user *) arg)) - return -EFAULT; - } - return 0; - } - } - - return -ENOIOCTLCMD; -} - -static int add_tty(dev_node_t *nodesp, int j, - struct ipw_hardware *hardware, - struct ipw_network *network, int channel_idx, - int secondary_channel_idx, int tty_type) -{ - ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL); - if (!ttys[j]) - return -ENOMEM; - ttys[j]->index = j; - ttys[j]->hardware = hardware; - ttys[j]->channel_idx = channel_idx; - ttys[j]->secondary_channel_idx = secondary_channel_idx; - ttys[j]->network = network; - ttys[j]->tty_type = tty_type; - mutex_init(&ttys[j]->ipw_tty_mutex); - - tty_register_device(ipw_tty_driver, j, NULL); - ipwireless_associate_network_tty(network, channel_idx, ttys[j]); - - if (secondary_channel_idx != -1) - ipwireless_associate_network_tty(network, - secondary_channel_idx, - ttys[j]); - if (nodesp != NULL) { - sprintf(nodesp->dev_name, "ttyIPWp%d", j); - nodesp->major = ipw_tty_driver->major; - nodesp->minor = j + ipw_tty_driver->minor_start; - } - if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j]) - report_registering(ttys[j]); - return 0; -} - -struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hardware, - struct ipw_network *network, - dev_node_t *nodes) -{ - int i, j; - - for (i = 0; i < IPWIRELESS_PCMCIA_MINOR_RANGE; i++) { - int allfree = 1; - - for (j = i; j < IPWIRELESS_PCMCIA_MINORS; - j += IPWIRELESS_PCMCIA_MINOR_RANGE) - if (ttys[j] != NULL) { - allfree = 0; - break; - } - - if (allfree) { - j = i; - - if (add_tty(&nodes[0], j, hardware, network, - IPW_CHANNEL_DIALLER, IPW_CHANNEL_RAS, - TTYTYPE_MODEM)) - return NULL; - - j += IPWIRELESS_PCMCIA_MINOR_RANGE; - if (add_tty(&nodes[1], j, hardware, network, - IPW_CHANNEL_DIALLER, -1, - TTYTYPE_MONITOR)) - return NULL; - - j += IPWIRELESS_PCMCIA_MINOR_RANGE; - if (add_tty(NULL, j, hardware, network, - IPW_CHANNEL_RAS, -1, - TTYTYPE_RAS_RAW)) - return NULL; - - nodes[0].next = &nodes[1]; - nodes[1].next = NULL; - - return ttys[i]; - } - } - return NULL; -} - -/* - * Must be called before ipwireless_network_free(). - */ -void ipwireless_tty_free(struct ipw_tty *tty) -{ - int j; - struct ipw_network *network = ttys[tty->index]->network; - - for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS; - j += IPWIRELESS_PCMCIA_MINOR_RANGE) { - struct ipw_tty *ttyj = ttys[j]; - - if (ttyj) { - mutex_lock(&ttyj->ipw_tty_mutex); - if (get_tty(j + ipw_tty_driver->minor_start) == ttyj) - report_deregistering(ttyj); - ttyj->closing = 1; - if (ttyj->linux_tty != NULL) { - mutex_unlock(&ttyj->ipw_tty_mutex); - tty_hangup(ttyj->linux_tty); - /* Wait till the tty_hangup has completed */ - flush_scheduled_work(); - mutex_lock(&ttyj->ipw_tty_mutex); - } - while (ttyj->open_count) - do_ipw_close(ttyj); - ipwireless_disassociate_network_ttys(network, - ttyj->channel_idx); - tty_unregister_device(ipw_tty_driver, j); - ttys[j] = NULL; - mutex_unlock(&ttyj->ipw_tty_mutex); - kfree(ttyj); - } - } -} - -static struct tty_operations tty_ops = { - .open = ipw_open, - .close = ipw_close, - .hangup = ipw_hangup, - .write = ipw_write, - .write_room = ipw_write_room, - .ioctl = ipw_ioctl, - .chars_in_buffer = ipw_chars_in_buffer, - .tiocmget = ipw_tiocmget, - .tiocmset = ipw_tiocmset, -}; - -int ipwireless_tty_init(void) -{ - int result; - - ipw_tty_driver = alloc_tty_driver(IPWIRELESS_PCMCIA_MINORS); - if (!ipw_tty_driver) - return -ENOMEM; - - ipw_tty_driver->owner = THIS_MODULE; - ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME; - ipw_tty_driver->name = "ttyIPWp"; - ipw_tty_driver->major = 0; - ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START; - ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL; - ipw_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - ipw_tty_driver->init_termios = tty_std_termios; - ipw_tty_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - ipw_tty_driver->init_termios.c_ispeed = 9600; - ipw_tty_driver->init_termios.c_ospeed = 9600; - tty_set_operations(ipw_tty_driver, &tty_ops); - result = tty_register_driver(ipw_tty_driver); - if (result) { - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": failed to register tty driver\n"); - put_tty_driver(ipw_tty_driver); - return result; - } - - return 0; -} - -void ipwireless_tty_release(void) -{ - int ret; - - ret = tty_unregister_driver(ipw_tty_driver); - put_tty_driver(ipw_tty_driver); - if (ret != 0) - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": tty_unregister_driver failed with code %d\n", ret); -} - -int ipwireless_tty_is_modem(struct ipw_tty *tty) -{ - return tty->tty_type == TTYTYPE_MODEM; -} - -void -ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, - unsigned int channel_idx, - unsigned int control_lines, - unsigned int changed_mask) -{ - unsigned int old_control_lines = tty->control_lines; - - tty->control_lines = (tty->control_lines & ~changed_mask) - | (control_lines & changed_mask); - - /* - * If DCD is de-asserted, we close the tty so pppd can tell that we - * have gone offline. - */ - if ((old_control_lines & IPW_CONTROL_LINE_DCD) - && !(tty->control_lines & IPW_CONTROL_LINE_DCD) - && tty->linux_tty) { - tty_hangup(tty->linux_tty); - } -} - diff --git a/trunk/drivers/char/pcmcia/ipwireless/tty.h b/trunk/drivers/char/pcmcia/ipwireless/tty.h deleted file mode 100644 index b0deb9168b6b..000000000000 --- a/trunk/drivers/char/pcmcia/ipwireless/tty.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * IPWireless 3G PCMCIA Network Driver - * - * Original code - * by Stephen Blackheath , - * Ben Martel - * - * Copyrighted as follows: - * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) - * - * Various driver changes and rewrites, port to new kernels - * Copyright (C) 2006-2007 Jiri Kosina - * - * Misc code cleanups and updates - * Copyright (C) 2007 David Sterba - */ - -#ifndef _IPWIRELESS_CS_TTY_H_ -#define _IPWIRELESS_CS_TTY_H_ - -#include -#include - -#include -#include -#include -#include - -struct ipw_tty; -struct ipw_network; -struct ipw_hardware; - -int ipwireless_tty_init(void); -void ipwireless_tty_release(void); - -struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hw, - struct ipw_network *net, - dev_node_t *nodes); -void ipwireless_tty_free(struct ipw_tty *tty); -void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, - unsigned int length); -int ipwireless_tty_is_modem(struct ipw_tty *tty); -void ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, - unsigned int channel_idx, - unsigned int control_lines, - unsigned int changed_mask); - -#endif diff --git a/trunk/drivers/firmware/dmi_scan.c b/trunk/drivers/firmware/dmi_scan.c index e0bade732376..1412d7bcdbd1 100644 --- a/trunk/drivers/firmware/dmi_scan.c +++ b/trunk/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/trunk/drivers/misc/Kconfig b/trunk/drivers/misc/Kconfig index 7b5220ca7d7f..78cd33861766 100644 --- a/trunk/drivers/misc/Kconfig +++ b/trunk/drivers/misc/Kconfig @@ -285,13 +285,4 @@ config INTEL_MENLOW If unsure, say N. -config ENCLOSURE_SERVICES - tristate "Enclosure Services" - default n - help - Provides support for intelligent enclosures (bays which - contain storage devices). You also need either a host - driver (SCSI/ATA) which supports enclosures - or a SCSI enclosure device (SES) to use these services. - endif # MISC_DEVICES diff --git a/trunk/drivers/misc/Makefile b/trunk/drivers/misc/Makefile index 7f13549cc87e..1f41654aae4d 100644 --- a/trunk/drivers/misc/Makefile +++ b/trunk/drivers/misc/Makefile @@ -20,4 +20,3 @@ obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o -obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o diff --git a/trunk/drivers/misc/enclosure.c b/trunk/drivers/misc/enclosure.c deleted file mode 100644 index 6fcb0e96adf4..000000000000 --- a/trunk/drivers/misc/enclosure.c +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Enclosure Services - * - * Copyright (C) 2008 James Bottomley - * -**----------------------------------------------------------------------------- -** -** This program is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License -** version 2 as published by the Free Software Foundation. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -**----------------------------------------------------------------------------- -*/ -#include -#include -#include -#include -#include -#include -#include - -static LIST_HEAD(container_list); -static DEFINE_MUTEX(container_list_lock); -static struct class enclosure_class; -static struct class enclosure_component_class; - -/** - * enclosure_find - find an enclosure given a device - * @dev: the device to find for - * - * Looks through the list of registered enclosures to see - * if it can find a match for a device. Returns NULL if no - * enclosure is found. Obtains a reference to the enclosure class - * device which must be released with class_device_put(). - */ -struct enclosure_device *enclosure_find(struct device *dev) -{ - struct enclosure_device *edev = NULL; - - mutex_lock(&container_list_lock); - list_for_each_entry(edev, &container_list, node) { - if (edev->cdev.dev == dev) { - class_device_get(&edev->cdev); - mutex_unlock(&container_list_lock); - return edev; - } - } - mutex_unlock(&container_list_lock); - - return NULL; -} -EXPORT_SYMBOL_GPL(enclosure_find); - -/** - * enclosure_for_each_device - calls a function for each enclosure - * @fn: the function to call - * @data: the data to pass to each call - * - * Loops over all the enclosures calling the function. - * - * Note, this function uses a mutex which will be held across calls to - * @fn, so it must have non atomic context, and @fn may (although it - * should not) sleep or otherwise cause the mutex to be held for - * indefinite periods - */ -int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *), - void *data) -{ - int error = 0; - struct enclosure_device *edev; - - mutex_lock(&container_list_lock); - list_for_each_entry(edev, &container_list, node) { - error = fn(edev, data); - if (error) - break; - } - mutex_unlock(&container_list_lock); - - return error; -} -EXPORT_SYMBOL_GPL(enclosure_for_each_device); - -/** - * enclosure_register - register device as an enclosure - * - * @dev: device containing the enclosure - * @components: number of components in the enclosure - * - * This sets up the device for being an enclosure. Note that @dev does - * not have to be a dedicated enclosure device. It may be some other type - * of device that additionally responds to enclosure services - */ -struct enclosure_device * -enclosure_register(struct device *dev, const char *name, int components, - struct enclosure_component_callbacks *cb) -{ - struct enclosure_device *edev = - kzalloc(sizeof(struct enclosure_device) + - sizeof(struct enclosure_component)*components, - GFP_KERNEL); - int err, i; - - BUG_ON(!cb); - - if (!edev) - return ERR_PTR(-ENOMEM); - - edev->components = components; - - edev->cdev.class = &enclosure_class; - edev->cdev.dev = get_device(dev); - edev->cb = cb; - snprintf(edev->cdev.class_id, BUS_ID_SIZE, "%s", name); - err = class_device_register(&edev->cdev); - if (err) - goto err; - - for (i = 0; i < components; i++) - edev->component[i].number = -1; - - mutex_lock(&container_list_lock); - list_add_tail(&edev->node, &container_list); - mutex_unlock(&container_list_lock); - - return edev; - - err: - put_device(edev->cdev.dev); - kfree(edev); - return ERR_PTR(err); -} -EXPORT_SYMBOL_GPL(enclosure_register); - -static struct enclosure_component_callbacks enclosure_null_callbacks; - -/** - * enclosure_unregister - remove an enclosure - * - * @edev: the registered enclosure to remove; - */ -void enclosure_unregister(struct enclosure_device *edev) -{ - int i; - - mutex_lock(&container_list_lock); - list_del(&edev->node); - mutex_unlock(&container_list_lock); - - for (i = 0; i < edev->components; i++) - if (edev->component[i].number != -1) - class_device_unregister(&edev->component[i].cdev); - - /* prevent any callbacks into service user */ - edev->cb = &enclosure_null_callbacks; - class_device_unregister(&edev->cdev); -} -EXPORT_SYMBOL_GPL(enclosure_unregister); - -static void enclosure_release(struct class_device *cdev) -{ - struct enclosure_device *edev = to_enclosure_device(cdev); - - put_device(cdev->dev); - kfree(edev); -} - -static void enclosure_component_release(struct class_device *cdev) -{ - if (cdev->dev) - put_device(cdev->dev); - class_device_put(cdev->parent); -} - -/** - * enclosure_component_register - add a particular component to an enclosure - * @edev: the enclosure to add the component - * @num: the device number - * @type: the type of component being added - * @name: an optional name to appear in sysfs (leave NULL if none) - * - * Registers the component. The name is optional for enclosures that - * give their components a unique name. If not, leave the field NULL - * and a name will be assigned. - * - * Returns a pointer to the enclosure component or an error. - */ -struct enclosure_component * -enclosure_component_register(struct enclosure_device *edev, - unsigned int number, - enum enclosure_component_type type, - const char *name) -{ - struct enclosure_component *ecomp; - struct class_device *cdev; - int err; - - if (number >= edev->components) - return ERR_PTR(-EINVAL); - - ecomp = &edev->component[number]; - - if (ecomp->number != -1) - return ERR_PTR(-EINVAL); - - ecomp->type = type; - ecomp->number = number; - cdev = &ecomp->cdev; - cdev->parent = class_device_get(&edev->cdev); - cdev->class = &enclosure_component_class; - if (name) - snprintf(cdev->class_id, BUS_ID_SIZE, "%s", name); - else - snprintf(cdev->class_id, BUS_ID_SIZE, "%u", number); - - err = class_device_register(cdev); - if (err) - ERR_PTR(err); - - return ecomp; -} -EXPORT_SYMBOL_GPL(enclosure_component_register); - -/** - * enclosure_add_device - add a device as being part of an enclosure - * @edev: the enclosure device being added to. - * @num: the number of the component - * @dev: the device being added - * - * Declares a real device to reside in slot (or identifier) @num of an - * enclosure. This will cause the relevant sysfs links to appear. - * This function may also be used to change a device associated with - * an enclosure without having to call enclosure_remove_device() in - * between. - * - * Returns zero on success or an error. - */ -int enclosure_add_device(struct enclosure_device *edev, int component, - struct device *dev) -{ - struct class_device *cdev; - - if (!edev || component >= edev->components) - return -EINVAL; - - cdev = &edev->component[component].cdev; - - class_device_del(cdev); - if (cdev->dev) - put_device(cdev->dev); - cdev->dev = get_device(dev); - return class_device_add(cdev); -} -EXPORT_SYMBOL_GPL(enclosure_add_device); - -/** - * enclosure_remove_device - remove a device from an enclosure - * @edev: the enclosure device - * @num: the number of the component to remove - * - * Returns zero on success or an error. - * - */ -int enclosure_remove_device(struct enclosure_device *edev, int component) -{ - struct class_device *cdev; - - if (!edev || component >= edev->components) - return -EINVAL; - - cdev = &edev->component[component].cdev; - - class_device_del(cdev); - if (cdev->dev) - put_device(cdev->dev); - cdev->dev = NULL; - return class_device_add(cdev); -} -EXPORT_SYMBOL_GPL(enclosure_remove_device); - -/* - * sysfs pieces below - */ - -static ssize_t enclosure_show_components(struct class_device *cdev, char *buf) -{ - struct enclosure_device *edev = to_enclosure_device(cdev); - - return snprintf(buf, 40, "%d\n", edev->components); -} - -static struct class_device_attribute enclosure_attrs[] = { - __ATTR(components, S_IRUGO, enclosure_show_components, NULL), - __ATTR_NULL -}; - -static struct class enclosure_class = { - .name = "enclosure", - .owner = THIS_MODULE, - .release = enclosure_release, - .class_dev_attrs = enclosure_attrs, -}; - -static const char *const enclosure_status [] = { - [ENCLOSURE_STATUS_UNSUPPORTED] = "unsupported", - [ENCLOSURE_STATUS_OK] = "OK", - [ENCLOSURE_STATUS_CRITICAL] = "critical", - [ENCLOSURE_STATUS_NON_CRITICAL] = "non-critical", - [ENCLOSURE_STATUS_UNRECOVERABLE] = "unrecoverable", - [ENCLOSURE_STATUS_NOT_INSTALLED] = "not installed", - [ENCLOSURE_STATUS_UNKNOWN] = "unknown", - [ENCLOSURE_STATUS_UNAVAILABLE] = "unavailable", -}; - -static const char *const enclosure_type [] = { - [ENCLOSURE_COMPONENT_DEVICE] = "device", - [ENCLOSURE_COMPONENT_ARRAY_DEVICE] = "array device", -}; - -static ssize_t get_component_fault(struct class_device *cdev, char *buf) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - - if (edev->cb->get_fault) - edev->cb->get_fault(edev, ecomp); - return snprintf(buf, 40, "%d\n", ecomp->fault); -} - -static ssize_t set_component_fault(struct class_device *cdev, const char *buf, - size_t count) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - int val = simple_strtoul(buf, NULL, 0); - - if (edev->cb->set_fault) - edev->cb->set_fault(edev, ecomp, val); - return count; -} - -static ssize_t get_component_status(struct class_device *cdev, char *buf) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - - if (edev->cb->get_status) - edev->cb->get_status(edev, ecomp); - return snprintf(buf, 40, "%s\n", enclosure_status[ecomp->status]); -} - -static ssize_t set_component_status(struct class_device *cdev, const char *buf, - size_t count) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - int i; - - for (i = 0; enclosure_status[i]; i++) { - if (strncmp(buf, enclosure_status[i], - strlen(enclosure_status[i])) == 0 && - (buf[strlen(enclosure_status[i])] == '\n' || - buf[strlen(enclosure_status[i])] == '\0')) - break; - } - - if (enclosure_status[i] && edev->cb->set_status) { - edev->cb->set_status(edev, ecomp, i); - return count; - } else - return -EINVAL; -} - -static ssize_t get_component_active(struct class_device *cdev, char *buf) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - - if (edev->cb->get_active) - edev->cb->get_active(edev, ecomp); - return snprintf(buf, 40, "%d\n", ecomp->active); -} - -static ssize_t set_component_active(struct class_device *cdev, const char *buf, - size_t count) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - int val = simple_strtoul(buf, NULL, 0); - - if (edev->cb->set_active) - edev->cb->set_active(edev, ecomp, val); - return count; -} - -static ssize_t get_component_locate(struct class_device *cdev, char *buf) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - - if (edev->cb->get_locate) - edev->cb->get_locate(edev, ecomp); - return snprintf(buf, 40, "%d\n", ecomp->locate); -} - -static ssize_t set_component_locate(struct class_device *cdev, const char *buf, - size_t count) -{ - struct enclosure_device *edev = to_enclosure_device(cdev->parent); - struct enclosure_component *ecomp = to_enclosure_component(cdev); - int val = simple_strtoul(buf, NULL, 0); - - if (edev->cb->set_locate) - edev->cb->set_locate(edev, ecomp, val); - return count; -} - -static ssize_t get_component_type(struct class_device *cdev, char *buf) -{ - struct enclosure_component *ecomp = to_enclosure_component(cdev); - - return snprintf(buf, 40, "%s\n", enclosure_type[ecomp->type]); -} - - -static struct class_device_attribute enclosure_component_attrs[] = { - __ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault, - set_component_fault), - __ATTR(status, S_IRUGO | S_IWUSR, get_component_status, - set_component_status), - __ATTR(active, S_IRUGO | S_IWUSR, get_component_active, - set_component_active), - __ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate, - set_component_locate), - __ATTR(type, S_IRUGO, get_component_type, NULL), - __ATTR_NULL -}; - -static struct class enclosure_component_class = { - .name = "enclosure_component", - .owner = THIS_MODULE, - .class_dev_attrs = enclosure_component_attrs, - .release = enclosure_component_release, -}; - -static int __init enclosure_init(void) -{ - int err; - - err = class_register(&enclosure_class); - if (err) - return err; - err = class_register(&enclosure_component_class); - if (err) - goto err_out; - - return 0; - err_out: - class_unregister(&enclosure_class); - - return err; -} - -static void __exit enclosure_exit(void) -{ - class_unregister(&enclosure_component_class); - class_unregister(&enclosure_class); -} - -module_init(enclosure_init); -module_exit(enclosure_exit); - -MODULE_AUTHOR("James Bottomley"); -MODULE_DESCRIPTION("Enclosure Services"); -MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/scsi/Kconfig b/trunk/drivers/scsi/Kconfig index a5f0aaaf0dd4..14fc7f39e83e 100644 --- a/trunk/drivers/scsi/Kconfig +++ b/trunk/drivers/scsi/Kconfig @@ -179,15 +179,7 @@ config CHR_DEV_SCH say M here and read and . The module will be called ch.o. If unsure, say N. - -config SCSI_ENCLOSURE - tristate "SCSI Enclosure Support" - depends on SCSI && ENCLOSURE_SERVICES - help - Enclosures are devices sitting on or in SCSI backplanes that - manage devices. If you have a disk cage, the chances are that - it has an enclosure device. Selecting this option will just allow - certain enclosure conditions to be reported and is not required. + comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" depends on SCSI @@ -358,6 +350,17 @@ config SGIWD93_SCSI If you have a Western Digital WD93 SCSI controller on an SGI MIPS system, say Y. Otherwise, say N. +config SCSI_DECNCR + tristate "DEC NCR53C94 Scsi Driver" + depends on MACH_DECSTATION && SCSI && TC + help + Say Y here to support the NCR53C94 SCSI controller chips on IOASIC + based TURBOchannel DECstations and TURBOchannel PMAZ-A cards. + +config SCSI_DECSII + tristate "DEC SII Scsi Driver" + depends on MACH_DECSTATION && SCSI && 32BIT + config BLK_DEV_3W_XXXX_RAID tristate "3ware 5/6/7/8xxx ATA-RAID support" depends on PCI && SCSI @@ -1260,6 +1263,17 @@ config SCSI_NCR53C8XX_NO_DISCONNECT not allow targets to disconnect is not reasonable if there is more than 1 device on a SCSI bus. The normal answer therefore is N. +config SCSI_MCA_53C9X + tristate "NCR MCA 53C9x SCSI support" + depends on MCA_LEGACY && SCSI && BROKEN_ON_SMP + help + Some MicroChannel machines, notably the NCR 35xx line, use a SCSI + controller based on the NCR 53C94. This driver will allow use of + the controller on the 3550, and very possibly others. + + To compile this driver as a module, choose M here: the + module will be called mca_53c9x. + config SCSI_PAS16 tristate "PAS16 SCSI support" depends on ISA && SCSI @@ -1586,6 +1600,45 @@ config GVP11_SCSI To compile this driver as a module, choose M here: the module will be called gvp11. +config CYBERSTORM_SCSI + tristate "CyberStorm SCSI support" + depends on ZORRO && SCSI + help + If you have an Amiga with an original (MkI) Phase5 Cyberstorm + accelerator board and the optional Cyberstorm SCSI controller, + answer Y. Otherwise, say N. + +config CYBERSTORMII_SCSI + tristate "CyberStorm Mk II SCSI support" + depends on ZORRO && SCSI + help + If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board + and the optional Cyberstorm SCSI controller, say Y. Otherwise, + answer N. + +config BLZ2060_SCSI + tristate "Blizzard 2060 SCSI support" + depends on ZORRO && SCSI + help + If you have an Amiga with a Phase5 Blizzard 2060 accelerator board + and want to use the onboard SCSI controller, say Y. Otherwise, + answer N. + +config BLZ1230_SCSI + tristate "Blizzard 1230IV/1260 SCSI support" + depends on ZORRO && SCSI + help + If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard + 1260 accelerator, and the optional SCSI module, say Y. Otherwise, + say N. + +config FASTLANE_SCSI + tristate "Fastlane SCSI support" + depends on ZORRO && SCSI + help + If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use + one in the near future, say Y to this question. Otherwise, say N. + config SCSI_A4000T tristate "A4000T NCR53c710 SCSI support (EXPERIMENTAL)" depends on AMIGA && SCSI && EXPERIMENTAL @@ -1613,6 +1666,15 @@ config SCSI_ZORRO7XX accelerator card for the Amiga 1200, - the SCSI controller on the GVP Turbo 040/060 accelerator. +config OKTAGON_SCSI + tristate "BSC Oktagon SCSI support (EXPERIMENTAL)" + depends on ZORRO && SCSI && EXPERIMENTAL + help + If you have the BSC Oktagon SCSI disk controller for the Amiga, say + Y to this question. If you're in doubt about whether you have one, + see the picture at + . + config ATARI_SCSI tristate "Atari native SCSI support" depends on ATARI && SCSI @@ -1665,6 +1727,18 @@ config MAC_SCSI SCSI-HOWTO, available from . +config SCSI_MAC_ESP + tristate "Macintosh NCR53c9[46] SCSI" + depends on MAC && SCSI + help + This is the NCR 53c9x SCSI controller found on most of the 68040 + based Macintoshes. If you have one of these say Y and read the + SCSI-HOWTO, available from + . + + To compile this driver as a module, choose M here: the + module will be called mac_esp. + config MVME147_SCSI bool "WD33C93 SCSI driver for MVME147" depends on MVME147 && SCSI=y @@ -1705,7 +1779,6 @@ config SUN3_SCSI config SUN3X_ESP bool "Sun3x ESP SCSI" depends on SUN3X && SCSI=y - select SCSI_SPI_ATTRS help The ESP was an on-board SCSI controller used on Sun 3/80 machines. Say Y here to compile in support for it. diff --git a/trunk/drivers/scsi/Makefile b/trunk/drivers/scsi/Makefile index 925c26b4fff9..93e1428d03fc 100644 --- a/trunk/drivers/scsi/Makefile +++ b/trunk/drivers/scsi/Makefile @@ -44,8 +44,15 @@ obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o obj-$(CONFIG_MVME147_SCSI) += mvme147.o wd33c93.o obj-$(CONFIG_SGIWD93_SCSI) += sgiwd93.o wd33c93.o +obj-$(CONFIG_CYBERSTORM_SCSI) += NCR53C9x.o cyberstorm.o +obj-$(CONFIG_CYBERSTORMII_SCSI) += NCR53C9x.o cyberstormII.o +obj-$(CONFIG_BLZ2060_SCSI) += NCR53C9x.o blz2060.o +obj-$(CONFIG_BLZ1230_SCSI) += NCR53C9x.o blz1230.o +obj-$(CONFIG_FASTLANE_SCSI) += NCR53C9x.o fastlane.o +obj-$(CONFIG_OKTAGON_SCSI) += NCR53C9x.o oktagon_esp_mod.o obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o obj-$(CONFIG_MAC_SCSI) += mac_scsi.o +obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o obj-$(CONFIG_MVME16x_SCSI) += 53c700.o mvme16x_scsi.o obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o @@ -88,6 +95,7 @@ obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/ obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o obj-$(CONFIG_SCSI_7000FASST) += wd7000.o +obj-$(CONFIG_SCSI_MCA_53C9X) += NCR53C9x.o mca_53c9x.o obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o obj-$(CONFIG_SCSI_EATA) += eata.o obj-$(CONFIG_SCSI_DC395x) += dc395x.o @@ -104,12 +112,13 @@ obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o obj-$(CONFIG_BLK_DEV_IDESCSI) += ide-scsi.o obj-$(CONFIG_SCSI_MESH) += mesh.o obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o +obj-$(CONFIG_SCSI_DECNCR) += NCR53C9x.o dec_esp.o obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o obj-$(CONFIG_SCSI_PPA) += ppa.o obj-$(CONFIG_SCSI_IMM) += imm.o obj-$(CONFIG_JAZZ_ESP) += esp_scsi.o jazz_esp.o -obj-$(CONFIG_SUN3X_ESP) += esp_scsi.o sun3x_esp.o +obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o obj-$(CONFIG_SCSI_SNI_53C710) += 53c700.o sni_53c710.o obj-$(CONFIG_SCSI_NSP32) += nsp32.o @@ -129,7 +138,6 @@ obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o obj-$(CONFIG_CHR_DEV_SCH) += ch.o -obj-$(CONFIG_SCSI_ENCLOSURE) += ses.o # This goes last, so that "real" scsi devices probe earlier obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o diff --git a/trunk/drivers/scsi/NCR53C9x.c b/trunk/drivers/scsi/NCR53C9x.c new file mode 100644 index 000000000000..5b0efc903918 --- /dev/null +++ b/trunk/drivers/scsi/NCR53C9x.c @@ -0,0 +1,3654 @@ +/* NCR53C9x.c: Generic SCSI driver code for NCR53C9x chips. + * + * Originally esp.c : EnhancedScsiProcessor Sun SCSI driver code. + * + * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu) + * + * Most DMA dependencies put in driver specific files by + * Jesper Skov (jskov@cygnus.co.uk) + * + * Set up to use esp_read/esp_write (preprocessor macros in NCR53c9x.h) by + * Tymm Twillman (tymm@coe.missouri.edu) + */ + +/* TODO: + * + * 1) Maybe disable parity checking in config register one for SCSI1 + * targets. (Gilmore says parity error on the SBus can lock up + * old sun4c's) + * 2) Add support for DMA2 pipelining. + * 3) Add tagged queueing. + * 4) Maybe change use of "esp" to something more "NCR"'ish. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include +#include + +/* Command phase enumeration. */ +enum { + not_issued = 0x00, /* Still in the issue_SC queue. */ + + /* Various forms of selecting a target. */ +#define in_slct_mask 0x10 + in_slct_norm = 0x10, /* ESP is arbitrating, normal selection */ + in_slct_stop = 0x11, /* ESP will select, then stop with IRQ */ + in_slct_msg = 0x12, /* select, then send a message */ + in_slct_tag = 0x13, /* select and send tagged queue msg */ + in_slct_sneg = 0x14, /* select and acquire sync capabilities */ + + /* Any post selection activity. */ +#define in_phases_mask 0x20 + in_datain = 0x20, /* Data is transferring from the bus */ + in_dataout = 0x21, /* Data is transferring to the bus */ + in_data_done = 0x22, /* Last DMA data operation done (maybe) */ + in_msgin = 0x23, /* Eating message from target */ + in_msgincont = 0x24, /* Eating more msg bytes from target */ + in_msgindone = 0x25, /* Decide what to do with what we got */ + in_msgout = 0x26, /* Sending message to target */ + in_msgoutdone = 0x27, /* Done sending msg out */ + in_cmdbegin = 0x28, /* Sending cmd after abnormal selection */ + in_cmdend = 0x29, /* Done sending slow cmd */ + in_status = 0x2a, /* Was in status phase, finishing cmd */ + in_freeing = 0x2b, /* freeing the bus for cmd cmplt or disc */ + in_the_dark = 0x2c, /* Don't know what bus phase we are in */ + + /* Special states, ie. not normal bus transitions... */ +#define in_spec_mask 0x80 + in_abortone = 0x80, /* Aborting one command currently */ + in_abortall = 0x81, /* Blowing away all commands we have */ + in_resetdev = 0x82, /* SCSI target reset in progress */ + in_resetbus = 0x83, /* SCSI bus reset in progress */ + in_tgterror = 0x84, /* Target did something stupid */ +}; + +enum { + /* Zero has special meaning, see skipahead[12]. */ +/*0*/ do_never, + +/*1*/ do_phase_determine, +/*2*/ do_reset_bus, +/*3*/ do_reset_complete, +/*4*/ do_work_bus, +/*5*/ do_intr_end +}; + +/* The master ring of all esp hosts we are managing in this driver. */ +static struct NCR_ESP *espchain; +int nesps = 0, esps_in_use = 0, esps_running = 0; +EXPORT_SYMBOL(nesps); +EXPORT_SYMBOL(esps_running); + +irqreturn_t esp_intr(int irq, void *dev_id); + +/* Debugging routines */ +static struct esp_cmdstrings { + unchar cmdchar; + char *text; +} esp_cmd_strings[] = { + /* Miscellaneous */ + { ESP_CMD_NULL, "ESP_NOP", }, + { ESP_CMD_FLUSH, "FIFO_FLUSH", }, + { ESP_CMD_RC, "RSTESP", }, + { ESP_CMD_RS, "RSTSCSI", }, + /* Disconnected State Group */ + { ESP_CMD_RSEL, "RESLCTSEQ", }, + { ESP_CMD_SEL, "SLCTNATN", }, + { ESP_CMD_SELA, "SLCTATN", }, + { ESP_CMD_SELAS, "SLCTATNSTOP", }, + { ESP_CMD_ESEL, "ENSLCTRESEL", }, + { ESP_CMD_DSEL, "DISSELRESEL", }, + { ESP_CMD_SA3, "SLCTATN3", }, + { ESP_CMD_RSEL3, "RESLCTSEQ", }, + /* Target State Group */ + { ESP_CMD_SMSG, "SNDMSG", }, + { ESP_CMD_SSTAT, "SNDSTATUS", }, + { ESP_CMD_SDATA, "SNDDATA", }, + { ESP_CMD_DSEQ, "DISCSEQ", }, + { ESP_CMD_TSEQ, "TERMSEQ", }, + { ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", }, + { ESP_CMD_DCNCT, "DISC", }, + { ESP_CMD_RMSG, "RCVMSG", }, + { ESP_CMD_RCMD, "RCVCMD", }, + { ESP_CMD_RDATA, "RCVDATA", }, + { ESP_CMD_RCSEQ, "RCVCMDSEQ", }, + /* Initiator State Group */ + { ESP_CMD_TI, "TRANSINFO", }, + { ESP_CMD_ICCSEQ, "INICMDSEQCOMP", }, + { ESP_CMD_MOK, "MSGACCEPTED", }, + { ESP_CMD_TPAD, "TPAD", }, + { ESP_CMD_SATN, "SATN", }, + { ESP_CMD_RATN, "RATN", }, +}; +#define NUM_ESP_COMMANDS ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings))) + +/* Print textual representation of an ESP command */ +static inline void esp_print_cmd(unchar espcmd) +{ + unchar dma_bit = espcmd & ESP_CMD_DMA; + int i; + + espcmd &= ~dma_bit; + for(i=0; i"); +} + +/* Print the interrupt register's value */ +static inline void esp_print_ireg(unchar intreg) +{ + printk("INTREG< "); + if(intreg & ESP_INTR_S) + printk("SLCT_NATN "); + if(intreg & ESP_INTR_SATN) + printk("SLCT_ATN "); + if(intreg & ESP_INTR_RSEL) + printk("RSLCT "); + if(intreg & ESP_INTR_FDONE) + printk("FDONE "); + if(intreg & ESP_INTR_BSERV) + printk("BSERV "); + if(intreg & ESP_INTR_DC) + printk("DISCNCT "); + if(intreg & ESP_INTR_IC) + printk("ILL_CMD "); + if(intreg & ESP_INTR_SR) + printk("SCSI_BUS_RESET "); + printk(">"); +} + +/* Print the sequence step registers contents */ +static inline void esp_print_seqreg(unchar stepreg) +{ + stepreg &= ESP_STEP_VBITS; + printk("STEP<%s>", + (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" : + (stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" : + (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" : + (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" : + (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" : + "UNKNOWN")))))); +} + +static char *phase_string(int phase) +{ + switch(phase) { + case not_issued: + return "UNISSUED"; + case in_slct_norm: + return "SLCTNORM"; + case in_slct_stop: + return "SLCTSTOP"; + case in_slct_msg: + return "SLCTMSG"; + case in_slct_tag: + return "SLCTTAG"; + case in_slct_sneg: + return "SLCTSNEG"; + case in_datain: + return "DATAIN"; + case in_dataout: + return "DATAOUT"; + case in_data_done: + return "DATADONE"; + case in_msgin: + return "MSGIN"; + case in_msgincont: + return "MSGINCONT"; + case in_msgindone: + return "MSGINDONE"; + case in_msgout: + return "MSGOUT"; + case in_msgoutdone: + return "MSGOUTDONE"; + case in_cmdbegin: + return "CMDBEGIN"; + case in_cmdend: + return "CMDEND"; + case in_status: + return "STATUS"; + case in_freeing: + return "FREEING"; + case in_the_dark: + return "CLUELESS"; + case in_abortone: + return "ABORTONE"; + case in_abortall: + return "ABORTALL"; + case in_resetdev: + return "RESETDEV"; + case in_resetbus: + return "RESETBUS"; + case in_tgterror: + return "TGTERROR"; + default: + return "UNKNOWN"; + }; +} + +#ifdef DEBUG_STATE_MACHINE +static inline void esp_advance_phase(Scsi_Cmnd *s, int newphase) +{ + ESPLOG(("<%s>", phase_string(newphase))); + s->SCp.sent_command = s->SCp.phase; + s->SCp.phase = newphase; +} +#else +#define esp_advance_phase(__s, __newphase) \ + (__s)->SCp.sent_command = (__s)->SCp.phase; \ + (__s)->SCp.phase = (__newphase); +#endif + +#ifdef DEBUG_ESP_CMDS +static inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs, + unchar cmd) +{ + esp->espcmdlog[esp->espcmdent] = cmd; + esp->espcmdent = (esp->espcmdent + 1) & 31; + esp_write(eregs->esp_cmnd, cmd); +} +#else +#define esp_cmd(__esp, __eregs, __cmd) esp_write((__eregs)->esp_cmnd, (__cmd)) +#endif + +/* How we use the various Linux SCSI data structures for operation. + * + * struct scsi_cmnd: + * + * We keep track of the syncronous capabilities of a target + * in the device member, using sync_min_period and + * sync_max_offset. These are the values we directly write + * into the ESP registers while running a command. If offset + * is zero the ESP will use asynchronous transfers. + * If the borken flag is set we assume we shouldn't even bother + * trying to negotiate for synchronous transfer as this target + * is really stupid. If we notice the target is dropping the + * bus, and we have been allowing it to disconnect, we clear + * the disconnect flag. + */ + +/* Manipulation of the ESP command queues. Thanks to the aha152x driver + * and its author, Juergen E. Fischer, for the methods used here. + * Note that these are per-ESP queues, not global queues like + * the aha152x driver uses. + */ +static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC) +{ + Scsi_Cmnd *end; + + new_SC->host_scribble = (unsigned char *) NULL; + if(!*SC) + *SC = new_SC; + else { + for(end=*SC;end->host_scribble;end=(Scsi_Cmnd *)end->host_scribble) + ; + end->host_scribble = (unsigned char *) new_SC; + } +} + +static inline void prepend_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC) +{ + new_SC->host_scribble = (unsigned char *) *SC; + *SC = new_SC; +} + +static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC) +{ + Scsi_Cmnd *ptr; + + ptr = *SC; + if(ptr) + *SC = (Scsi_Cmnd *) (*SC)->host_scribble; + return ptr; +} + +static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun) +{ + Scsi_Cmnd *ptr, *prev; + + for(ptr = *SC, prev = NULL; + ptr && ((ptr->device->id != target) || (ptr->device->lun != lun)); + prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble) + ; + if(ptr) { + if(prev) + prev->host_scribble=ptr->host_scribble; + else + *SC=(Scsi_Cmnd *)ptr->host_scribble; + } + return ptr; +} + +/* Resetting various pieces of the ESP scsi driver chipset */ + +/* Reset the ESP chip, _not_ the SCSI bus. */ +static void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + int family_code, version, i; + volatile int trash; + + /* Now reset the ESP chip */ + esp_cmd(esp, eregs, ESP_CMD_RC); + esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA); + if(esp->erev == fast) + esp_write(eregs->esp_cfg2, ESP_CONFIG2_FENAB); + esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA); + + /* This is the only point at which it is reliable to read + * the ID-code for a fast ESP chip variant. + */ + esp->max_period = ((35 * esp->ccycle) / 1000); + if(esp->erev == fast) { + char *erev2string[] = { + "Emulex FAS236", + "Emulex FPESP100A", + "fast", + "QLogic FAS366", + "Emulex FAS216", + "Symbios Logic 53CF9x-2", + "unknown!" + }; + + version = esp_read(eregs->esp_uid); + family_code = (version & 0xf8) >> 3; + if(family_code == 0x02) { + if ((version & 7) == 2) + esp->erev = fas216; + else + esp->erev = fas236; + } else if(family_code == 0x0a) + esp->erev = fas366; /* Version is usually '5'. */ + else if(family_code == 0x00) { + if ((version & 7) == 2) + esp->erev = fas100a; /* NCR53C9X */ + else + esp->erev = espunknown; + } else if(family_code == 0x14) { + if ((version & 7) == 2) + esp->erev = fsc; + else + esp->erev = espunknown; + } else if(family_code == 0x00) { + if ((version & 7) == 2) + esp->erev = fas100a; /* NCR53C9X */ + else + esp->erev = espunknown; + } else + esp->erev = espunknown; + ESPLOG(("esp%d: FAST chip is %s (family=%d, version=%d)\n", + esp->esp_id, erev2string[esp->erev - fas236], + family_code, (version & 7))); + + esp->min_period = ((4 * esp->ccycle) / 1000); + } else { + esp->min_period = ((5 * esp->ccycle) / 1000); + } + + /* Reload the configuration registers */ + esp_write(eregs->esp_cfact, esp->cfact); + esp->prev_stp = 0; + esp_write(eregs->esp_stp, 0); + esp->prev_soff = 0; + esp_write(eregs->esp_soff, 0); + esp_write(eregs->esp_timeo, esp->neg_defp); + esp->max_period = (esp->max_period + 3)>>2; + esp->min_period = (esp->min_period + 3)>>2; + + esp_write(eregs->esp_cfg1, esp->config1); + switch(esp->erev) { + case esp100: + /* nothing to do */ + break; + case esp100a: + esp_write(eregs->esp_cfg2, esp->config2); + break; + case esp236: + /* Slow 236 */ + esp_write(eregs->esp_cfg2, esp->config2); + esp->prev_cfg3 = esp->config3[0]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + break; + case fas366: + panic("esp: FAS366 support not present, please notify " + "jongk@cs.utwente.nl"); + break; + case fas216: + case fas236: + case fsc: + /* Fast ESP variants */ + esp_write(eregs->esp_cfg2, esp->config2); + for(i=0; i<8; i++) + esp->config3[i] |= ESP_CONFIG3_FCLK; + esp->prev_cfg3 = esp->config3[0]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + if(esp->diff) + esp->radelay = 0; + else + esp->radelay = 16; + /* Different timeout constant for these chips */ + esp->neg_defp = + FSC_NEG_DEFP(esp->cfreq, + (esp->cfact == ESP_CCF_F0 ? + ESP_CCF_F7 + 1 : esp->cfact)); + esp_write(eregs->esp_timeo, esp->neg_defp); + /* Enable Active Negotiation if possible */ + if((esp->erev == fsc) && !esp->diff) + esp_write(eregs->esp_cfg4, ESP_CONFIG4_EAN); + break; + case fas100a: + /* Fast 100a */ + esp_write(eregs->esp_cfg2, esp->config2); + for(i=0; i<8; i++) + esp->config3[i] |= ESP_CONFIG3_FCLOCK; + esp->prev_cfg3 = esp->config3[0]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + esp->radelay = 32; + break; + default: + panic("esp: what could it be... I wonder..."); + break; + }; + + /* Eat any bitrot in the chip */ + trash = esp_read(eregs->esp_intrpt); + udelay(100); +} + +/* This places the ESP into a known state at boot time. */ +void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + volatile unchar trash; + + /* Reset the DMA */ + if(esp->dma_reset) + esp->dma_reset(esp); + + /* Reset the ESP */ + esp_reset_esp(esp, eregs); + + /* Reset the SCSI bus, but tell ESP not to generate an irq */ + esp_write(eregs->esp_cfg1, (esp_read(eregs->esp_cfg1) | ESP_CONFIG1_SRRDISAB)); + esp_cmd(esp, eregs, ESP_CMD_RS); + udelay(400); + esp_write(eregs->esp_cfg1, esp->config1); + + /* Eat any bitrot in the chip and we are done... */ + trash = esp_read(eregs->esp_intrpt); +} +EXPORT_SYMBOL(esp_bootup_reset); + +/* Allocate structure and insert basic data such as SCSI chip frequency + * data and a pointer to the device + */ +struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev, + int hotplug) +{ + struct NCR_ESP *esp, *elink; + struct Scsi_Host *esp_host; + + if (hotplug) + esp_host = scsi_host_alloc(tpnt, sizeof(struct NCR_ESP)); + else + esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP)); + if(!esp_host) + panic("Cannot register ESP SCSI host"); + esp = (struct NCR_ESP *) esp_host->hostdata; + if(!esp) + panic("No esp in hostdata"); + esp->ehost = esp_host; + esp->edev = esp_dev; + esp->esp_id = nesps++; + + /* Set bitshift value (only used on Amiga with multiple ESPs) */ + esp->shift = 2; + + /* Put into the chain of esp chips detected */ + if(espchain) { + elink = espchain; + while(elink->next) elink = elink->next; + elink->next = esp; + } else { + espchain = esp; + } + esp->next = NULL; + + return esp; +} + +void esp_deallocate(struct NCR_ESP *esp) +{ + struct NCR_ESP *elink; + + if(espchain == esp) { + espchain = NULL; + } else { + for(elink = espchain; elink && (elink->next != esp); elink = elink->next); + if(elink) + elink->next = esp->next; + } + nesps--; +} + +/* Complete initialization of ESP structure and device + * Caller must have initialized appropriate parts of the ESP structure + * between the call to esp_allocate and this function. + */ +void esp_initialize(struct NCR_ESP *esp) +{ + struct ESP_regs *eregs = esp->eregs; + unsigned int fmhz; + unchar ccf; + int i; + + /* Check out the clock properties of the chip. */ + + /* This is getting messy but it has to be done + * correctly or else you get weird behavior all + * over the place. We are trying to basically + * figure out three pieces of information. + * + * a) Clock Conversion Factor + * + * This is a representation of the input + * crystal clock frequency going into the + * ESP on this machine. Any operation whose + * timing is longer than 400ns depends on this + * value being correct. For example, you'll + * get blips for arbitration/selection during + * high load or with multiple targets if this + * is not set correctly. + * + * b) Selection Time-Out + * + * The ESP isn't very bright and will arbitrate + * for the bus and try to select a target + * forever if you let it. This value tells + * the ESP when it has taken too long to + * negotiate and that it should interrupt + * the CPU so we can see what happened. + * The value is computed as follows (from + * NCR/Symbios chip docs). + * + * (Time Out Period) * (Input Clock) + * STO = ---------------------------------- + * (8192) * (Clock Conversion Factor) + * + * You usually want the time out period to be + * around 250ms, I think we'll set it a little + * bit higher to account for fully loaded SCSI + * bus's and slow devices that don't respond so + * quickly to selection attempts. (yeah, I know + * this is out of spec. but there is a lot of + * buggy pieces of firmware out there so bite me) + * + * c) Imperical constants for synchronous offset + * and transfer period register values + * + * This entails the smallest and largest sync + * period we could ever handle on this ESP. + */ + + fmhz = esp->cfreq; + + if(fmhz <= (5000000)) + ccf = 0; + else + ccf = (((5000000 - 1) + (fmhz))/(5000000)); + if(!ccf || ccf > 8) { + /* If we can't find anything reasonable, + * just assume 20MHZ. This is the clock + * frequency of the older sun4c's where I've + * been unable to find the clock-frequency + * PROM property. All other machines provide + * useful values it seems. + */ + ccf = ESP_CCF_F4; + fmhz = (20000000); + } + if(ccf==(ESP_CCF_F7+1)) + esp->cfact = ESP_CCF_F0; + else if(ccf == ESP_CCF_NEVER) + esp->cfact = ESP_CCF_F2; + else + esp->cfact = ccf; + esp->cfreq = fmhz; + esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz); + esp->ctick = ESP_TICK(ccf, esp->ccycle); + esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf); + esp->sync_defp = SYNC_DEFP_SLOW; + + printk("SCSI ID %d Clk %dMHz CCF=%d TOut %d ", + esp->scsi_id, (esp->cfreq / 1000000), + ccf, (int) esp->neg_defp); + + /* Fill in ehost data */ + esp->ehost->base = (unsigned long)eregs; + esp->ehost->this_id = esp->scsi_id; + esp->ehost->irq = esp->irq; + + /* SCSI id mask */ + esp->scsi_id_mask = (1 << esp->scsi_id); + + /* Probe the revision of this esp */ + esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7)); + esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY); + esp_write(eregs->esp_cfg2, esp->config2); + if((esp_read(eregs->esp_cfg2) & ~(ESP_CONFIG2_MAGIC)) != + (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) { + printk("NCR53C90(esp100)\n"); + esp->erev = esp100; + } else { + esp->config2 = 0; + esp_write(eregs->esp_cfg2, 0); + esp_write(eregs->esp_cfg3, 5); + if(esp_read(eregs->esp_cfg3) != 5) { + printk("NCR53C90A(esp100a)\n"); + esp->erev = esp100a; + } else { + int target; + + for(target=0; target<8; target++) + esp->config3[target] = 0; + esp->prev_cfg3 = 0; + esp_write(eregs->esp_cfg3, 0); + if(ccf > ESP_CCF_F5) { + printk("NCR53C9XF(espfast)\n"); + esp->erev = fast; + esp->sync_defp = SYNC_DEFP_FAST; + } else { + printk("NCR53C9x(esp236)\n"); + esp->erev = esp236; + } + } + } + + /* Initialize the command queues */ + esp->current_SC = NULL; + esp->disconnected_SC = NULL; + esp->issue_SC = NULL; + + /* Clear the state machines. */ + esp->targets_present = 0; + esp->resetting_bus = 0; + esp->snip = 0; + + init_waitqueue_head(&esp->reset_queue); + + esp->fas_premature_intr_workaround = 0; + for(i = 0; i < 32; i++) + esp->espcmdlog[i] = 0; + esp->espcmdent = 0; + for(i = 0; i < 16; i++) { + esp->cur_msgout[i] = 0; + esp->cur_msgin[i] = 0; + } + esp->prevmsgout = esp->prevmsgin = 0; + esp->msgout_len = esp->msgin_len = 0; + + /* Clear the one behind caches to hold unmatchable values. */ + esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff; + + /* Reset the thing before we try anything... */ + esp_bootup_reset(esp, eregs); + + esps_in_use++; +} + +/* The info function will return whatever useful + * information the developer sees fit. If not provided, then + * the name field will be used instead. + */ +const char *esp_info(struct Scsi_Host *host) +{ + struct NCR_ESP *esp; + + esp = (struct NCR_ESP *) host->hostdata; + switch(esp->erev) { + case esp100: + return "ESP100 (NCR53C90)"; + case esp100a: + return "ESP100A (NCR53C90A)"; + case esp236: + return "ESP236 (NCR53C9x)"; + case fas216: + return "Emulex FAS216"; + case fas236: + return "Emulex FAS236"; + case fas366: + return "QLogic FAS366"; + case fas100a: + return "FPESP100A"; + case fsc: + return "Symbios Logic 53CF9x-2"; + default: + panic("Bogon ESP revision"); + }; +} +EXPORT_SYMBOL(esp_info); + +/* From Wolfgang Stanglmeier's NCR scsi driver. */ +struct info_str +{ + char *buffer; + int length; + int offset; + int pos; +}; + +static void copy_mem_info(struct info_str *info, char *data, int len) +{ + if (info->pos + len > info->length) + len = info->length - info->pos; + + if (info->pos + len < info->offset) { + info->pos += len; + return; + } + if (info->pos < info->offset) { + data += (info->offset - info->pos); + len -= (info->offset - info->pos); + } + + if (len > 0) { + memcpy(info->buffer + info->pos, data, len); + info->pos += len; + } +} + +static int copy_info(struct info_str *info, char *fmt, ...) +{ + va_list args; + char buf[81]; + int len; + + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + copy_mem_info(info, buf, len); + return len; +} + +static int esp_host_info(struct NCR_ESP *esp, char *ptr, off_t offset, int len) +{ + struct scsi_device *sdev; + struct info_str info; + int i; + + info.buffer = ptr; + info.length = len; + info.offset = offset; + info.pos = 0; + + copy_info(&info, "ESP Host Adapter:\n"); + copy_info(&info, "\tESP Model\t\t"); + switch(esp->erev) { + case esp100: + copy_info(&info, "ESP100 (NCR53C90)\n"); + break; + case esp100a: + copy_info(&info, "ESP100A (NCR53C90A)\n"); + break; + case esp236: + copy_info(&info, "ESP236 (NCR53C9x)\n"); + break; + case fas216: + copy_info(&info, "Emulex FAS216\n"); + break; + case fas236: + copy_info(&info, "Emulex FAS236\n"); + break; + case fas100a: + copy_info(&info, "FPESP100A\n"); + break; + case fast: + copy_info(&info, "Generic FAST\n"); + break; + case fas366: + copy_info(&info, "QLogic FAS366\n"); + break; + case fsc: + copy_info(&info, "Symbios Logic 53C9x-2\n"); + break; + case espunknown: + default: + copy_info(&info, "Unknown!\n"); + break; + }; + copy_info(&info, "\tLive Targets\t\t[ "); + for(i = 0; i < 15; i++) { + if(esp->targets_present & (1 << i)) + copy_info(&info, "%d ", i); + } + copy_info(&info, "]\n\n"); + + /* Now describe the state of each existing target. */ + copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\n"); + + shost_for_each_device(sdev, esp->ehost) { + struct esp_device *esp_dev = sdev->hostdata; + uint id = sdev->id; + + if (!(esp->targets_present & (1 << id))) + continue; + + copy_info(&info, "%d\t\t", id); + copy_info(&info, "%08lx\t", esp->config3[id]); + copy_info(&info, "[%02lx,%02lx]\t\t\t", + esp_dev->sync_max_offset, + esp_dev->sync_min_period); + copy_info(&info, "%s\n", esp_dev->disconnect ? "yes" : "no"); + } + + return info.pos > info.offset? info.pos - info.offset : 0; +} + +/* ESP proc filesystem code. */ +int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, + int inout) +{ + struct NCR_ESP *esp = (struct NCR_ESP *)shost->hostdata; + + if(inout) + return -EINVAL; /* not yet */ + if(start) + *start = buffer; + return esp_host_info(esp, buffer, offset, length); +} +EXPORT_SYMBOL(esp_proc_info); + +static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + if(sp->use_sg == 0) { + sp->SCp.this_residual = sp->request_bufflen; + sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; + sp->SCp.buffers_residual = 0; + if (esp->dma_mmu_get_scsi_one) + esp->dma_mmu_get_scsi_one(esp, sp); + else + sp->SCp.ptr = + (char *) virt_to_phys(sp->request_buffer); + } else { + sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; + sp->SCp.buffers_residual = sp->use_sg - 1; + sp->SCp.this_residual = sp->SCp.buffer->length; + if (esp->dma_mmu_get_scsi_sgl) + esp->dma_mmu_get_scsi_sgl(esp, sp); + else + sp->SCp.ptr = + (char *) virt_to_phys(sg_virt(sp->SCp.buffer)); + } +} + +static void esp_release_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + if(sp->use_sg == 0) { + if (esp->dma_mmu_release_scsi_one) + esp->dma_mmu_release_scsi_one(esp, sp); + } else { + if (esp->dma_mmu_release_scsi_sgl) + esp->dma_mmu_release_scsi_sgl(esp, sp); + } +} + +static void esp_restore_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + struct esp_pointers *ep = &esp->data_pointers[scmd_id(sp)]; + + sp->SCp.ptr = ep->saved_ptr; + sp->SCp.buffer = ep->saved_buffer; + sp->SCp.this_residual = ep->saved_this_residual; + sp->SCp.buffers_residual = ep->saved_buffers_residual; +} + +static void esp_save_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + struct esp_pointers *ep = &esp->data_pointers[scmd_id(sp)]; + + ep->saved_ptr = sp->SCp.ptr; + ep->saved_buffer = sp->SCp.buffer; + ep->saved_this_residual = sp->SCp.this_residual; + ep->saved_buffers_residual = sp->SCp.buffers_residual; +} + +/* Some rules: + * + * 1) Never ever panic while something is live on the bus. + * If there is to be any chance of syncing the disks this + * rule is to be obeyed. + * + * 2) Any target that causes a foul condition will no longer + * have synchronous transfers done to it, no questions + * asked. + * + * 3) Keep register accesses to a minimum. Think about some + * day when we have Xbus machines this is running on and + * the ESP chip is on the other end of the machine on a + * different board from the cpu where this is running. + */ + +/* Fire off a command. We assume the bus is free and that the only + * case where we could see an interrupt is where we have disconnected + * commands active and they are trying to reselect us. + */ +static inline void esp_check_cmd(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + switch(sp->cmd_len) { + case 6: + case 10: + case 12: + esp->esp_slowcmd = 0; + break; + + default: + esp->esp_slowcmd = 1; + esp->esp_scmdleft = sp->cmd_len; + esp->esp_scmdp = &sp->cmnd[0]; + break; + }; +} + +static inline void build_sync_nego_msg(struct NCR_ESP *esp, int period, int offset) +{ + esp->cur_msgout[0] = EXTENDED_MESSAGE; + esp->cur_msgout[1] = 3; + esp->cur_msgout[2] = EXTENDED_SDTR; + esp->cur_msgout[3] = period; + esp->cur_msgout[4] = offset; + esp->msgout_len = 5; +} + +static void esp_exec_cmd(struct NCR_ESP *esp) +{ + struct ESP_regs *eregs = esp->eregs; + struct esp_device *esp_dev; + Scsi_Cmnd *SCptr; + struct scsi_device *SDptr; + volatile unchar *cmdp = esp->esp_command; + unsigned char the_esp_command; + int lun, target; + int i; + + /* Hold off if we have disconnected commands and + * an IRQ is showing... + */ + if(esp->disconnected_SC && esp->dma_irq_p(esp)) + return; + + /* Grab first member of the issue queue. */ + SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC); + + /* Safe to panic here because current_SC is null. */ + if(!SCptr) + panic("esp: esp_exec_cmd and issue queue is NULL"); + + SDptr = SCptr->device; + esp_dev = SDptr->hostdata; + lun = SCptr->device->lun; + target = SCptr->device->id; + + esp->snip = 0; + esp->msgout_len = 0; + + /* Send it out whole, or piece by piece? The ESP + * only knows how to automatically send out 6, 10, + * and 12 byte commands. I used to think that the + * Linux SCSI code would never throw anything other + * than that to us, but then again there is the + * SCSI generic driver which can send us anything. + */ + esp_check_cmd(esp, SCptr); + + /* If arbitration/selection is successful, the ESP will leave + * ATN asserted, causing the target to go into message out + * phase. The ESP will feed the target the identify and then + * the target can only legally go to one of command, + * datain/out, status, or message in phase, or stay in message + * out phase (should we be trying to send a sync negotiation + * message after the identify). It is not allowed to drop + * BSY, but some buggy targets do and we check for this + * condition in the selection complete code. Most of the time + * we'll make the command bytes available to the ESP and it + * will not interrupt us until it finishes command phase, we + * cannot do this for command sizes the ESP does not + * understand and in this case we'll get interrupted right + * when the target goes into command phase. + * + * It is absolutely _illegal_ in the presence of SCSI-2 devices + * to use the ESP select w/o ATN command. When SCSI-2 devices are + * present on the bus we _must_ always go straight to message out + * phase with an identify message for the target. Being that + * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2 + * selections should not confuse SCSI-1 we hope. + */ + + if(esp_dev->sync) { + /* this targets sync is known */ +#ifdef CONFIG_SCSI_MAC_ESP +do_sync_known: +#endif + if(esp_dev->disconnect) + *cmdp++ = IDENTIFY(1, lun); + else + *cmdp++ = IDENTIFY(0, lun); + + if(esp->esp_slowcmd) { + the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA); + esp_advance_phase(SCptr, in_slct_stop); + } else { + the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA); + esp_advance_phase(SCptr, in_slct_norm); + } + } else if(!(esp->targets_present & (1<disconnect)) { + /* After the bootup SCSI code sends both the + * TEST_UNIT_READY and INQUIRY commands we want + * to at least attempt allowing the device to + * disconnect. + */ + ESPMISC(("esp: Selecting device for first time. target=%d " + "lun=%d\n", target, SCptr->device->lun)); + if(!SDptr->borken && !esp_dev->disconnect) + esp_dev->disconnect = 1; + + *cmdp++ = IDENTIFY(0, lun); + esp->prevmsgout = NOP; + esp_advance_phase(SCptr, in_slct_norm); + the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA); + + /* Take no chances... */ + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + } else { + int toshiba_cdrom_hwbug_wkaround = 0; + +#ifdef CONFIG_SCSI_MAC_ESP + /* Never allow synchronous transfers (disconnect OK) on + * Macintosh. Well, maybe later when we figured out how to + * do DMA on the machines that support it ... + */ + esp_dev->disconnect = 1; + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + esp_dev->sync = 1; + esp->snip = 0; + goto do_sync_known; +#endif + /* We've talked to this guy before, + * but never negotiated. Let's try + * sync negotiation. + */ + if(!SDptr->borken) { + if((SDptr->type == TYPE_ROM) && + (!strncmp(SDptr->vendor, "TOSHIBA", 7))) { + /* Nice try sucker... */ + ESPMISC(("esp%d: Disabling sync for buggy " + "Toshiba CDROM.\n", esp->esp_id)); + toshiba_cdrom_hwbug_wkaround = 1; + build_sync_nego_msg(esp, 0, 0); + } else { + build_sync_nego_msg(esp, esp->sync_defp, 15); + } + } else { + build_sync_nego_msg(esp, 0, 0); + } + esp_dev->sync = 1; + esp->snip = 1; + + /* A fix for broken SCSI1 targets, when they disconnect + * they lock up the bus and confuse ESP. So disallow + * disconnects for SCSI1 targets for now until we + * find a better fix. + * + * Addendum: This is funny, I figured out what was going + * on. The blotzed SCSI1 target would disconnect, + * one of the other SCSI2 targets or both would be + * disconnected as well. The SCSI1 target would + * stay disconnected long enough that we start + * up a command on one of the SCSI2 targets. As + * the ESP is arbitrating for the bus the SCSI1 + * target begins to arbitrate as well to reselect + * the ESP. The SCSI1 target refuses to drop it's + * ID bit on the data bus even though the ESP is + * at ID 7 and is the obvious winner for any + * arbitration. The ESP is a poor sport and refuses + * to lose arbitration, it will continue indefinitely + * trying to arbitrate for the bus and can only be + * stopped via a chip reset or SCSI bus reset. + * Therefore _no_ disconnects for SCSI1 targets + * thank you very much. ;-) + */ + if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) || + toshiba_cdrom_hwbug_wkaround || SDptr->borken) { + ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d " + "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun)); + esp_dev->disconnect = 0; + *cmdp++ = IDENTIFY(0, lun); + } else { + *cmdp++ = IDENTIFY(1, lun); + } + + /* ESP fifo is only so big... + * Make this look like a slow command. + */ + esp->esp_slowcmd = 1; + esp->esp_scmdleft = SCptr->cmd_len; + esp->esp_scmdp = &SCptr->cmnd[0]; + + the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA); + esp_advance_phase(SCptr, in_slct_msg); + } + + if(!esp->esp_slowcmd) + for(i = 0; i < SCptr->cmd_len; i++) + *cmdp++ = SCptr->cmnd[i]; + + esp_write(eregs->esp_busid, (target & 7)); + if (esp->prev_soff != esp_dev->sync_max_offset || + esp->prev_stp != esp_dev->sync_min_period || + (esp->erev > esp100a && + esp->prev_cfg3 != esp->config3[target])) { + esp->prev_soff = esp_dev->sync_max_offset; + esp_write(eregs->esp_soff, esp->prev_soff); + esp->prev_stp = esp_dev->sync_min_period; + esp_write(eregs->esp_stp, esp->prev_stp); + if(esp->erev > esp100a) { + esp->prev_cfg3 = esp->config3[target]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + } + } + i = (cmdp - esp->esp_command); + + /* Set up the DMA and ESP counters */ + if(esp->do_pio_cmds){ + int j = 0; + + /* + * XXX MSch: + * + * It seems this is required, at least to clean up + * after failed commands when using PIO mode ... + */ + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + + for(;jesp_fdata, esp->esp_command[j]); + the_esp_command &= ~ESP_CMD_DMA; + + /* Tell ESP to "go". */ + esp_cmd(esp, eregs, the_esp_command); + } else { + /* Set up the ESP counters */ + esp_write(eregs->esp_tclow, i); + esp_write(eregs->esp_tcmed, 0); + esp->dma_init_write(esp, esp->esp_command_dvma, i); + + /* Tell ESP to "go". */ + esp_cmd(esp, eregs, the_esp_command); + } +} + +/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */ +int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + struct NCR_ESP *esp; + + /* Set up func ptr and initial driver cmd-phase. */ + SCpnt->scsi_done = done; + SCpnt->SCp.phase = not_issued; + + esp = (struct NCR_ESP *) SCpnt->device->host->hostdata; + + if(esp->dma_led_on) + esp->dma_led_on(esp); + + /* We use the scratch area. */ + ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->lun)); + ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->lun)); + + esp_get_dmabufs(esp, SCpnt); + esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */ + + SCpnt->SCp.Status = CHECK_CONDITION; + SCpnt->SCp.Message = 0xff; + SCpnt->SCp.sent_command = 0; + + /* Place into our queue. */ + if(SCpnt->cmnd[0] == REQUEST_SENSE) { + ESPQUEUE(("RQSENSE\n")); + prepend_SC(&esp->issue_SC, SCpnt); + } else { + ESPQUEUE(("\n")); + append_SC(&esp->issue_SC, SCpnt); + } + + /* Run it now if we can. */ + if(!esp->current_SC && !esp->resetting_bus) + esp_exec_cmd(esp); + + return 0; +} + +/* Dump driver state. */ +static void esp_dump_cmd(Scsi_Cmnd *SCptr) +{ + ESPLOG(("[tgt<%02x> lun<%02x> " + "pphase<%s> cphase<%s>]", + SCptr->device->id, SCptr->device->lun, + phase_string(SCptr->SCp.sent_command), + phase_string(SCptr->SCp.phase))); +} + +static void esp_dump_state(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; +#ifdef DEBUG_ESP_CMDS + int i; +#endif + + ESPLOG(("esp%d: dumping state\n", esp->esp_id)); + + /* Print DMA status */ + esp->dma_dump_state(esp); + + ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n", + esp->esp_id, esp->sreg, esp->seqreg, esp->ireg)); + ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n", + esp->esp_id, esp_read(eregs->esp_status), esp_read(eregs->esp_sstep), + esp_read(eregs->esp_intrpt))); +#ifdef DEBUG_ESP_CMDS + printk("esp%d: last ESP cmds [", esp->esp_id); + i = (esp->espcmdent - 1) & 31; + printk("<"); + esp_print_cmd(esp->espcmdlog[i]); + printk(">"); + i = (i - 1) & 31; + printk("<"); + esp_print_cmd(esp->espcmdlog[i]); + printk(">"); + i = (i - 1) & 31; + printk("<"); + esp_print_cmd(esp->espcmdlog[i]); + printk(">"); + i = (i - 1) & 31; + printk("<"); + esp_print_cmd(esp->espcmdlog[i]); + printk(">"); + printk("]\n"); +#endif /* (DEBUG_ESP_CMDS) */ + + if(SCptr) { + ESPLOG(("esp%d: current command ", esp->esp_id)); + esp_dump_cmd(SCptr); + } + ESPLOG(("\n")); + SCptr = esp->disconnected_SC; + ESPLOG(("esp%d: disconnected ", esp->esp_id)); + while(SCptr) { + esp_dump_cmd(SCptr); + SCptr = (Scsi_Cmnd *) SCptr->host_scribble; + } + ESPLOG(("\n")); +} + +/* Abort a command. The host_lock is acquired by caller. */ +int esp_abort(Scsi_Cmnd *SCptr) +{ + struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->device->host->hostdata; + struct ESP_regs *eregs = esp->eregs; + int don; + + ESPLOG(("esp%d: Aborting command\n", esp->esp_id)); + esp_dump_state(esp, eregs); + + /* Wheee, if this is the current command on the bus, the + * best we can do is assert ATN and wait for msgout phase. + * This should even fix a hung SCSI bus when we lose state + * in the driver and timeout because the eventual phase change + * will cause the ESP to (eventually) give an interrupt. + */ + if(esp->current_SC == SCptr) { + esp->cur_msgout[0] = ABORT; + esp->msgout_len = 1; + esp->msgout_ctr = 0; + esp_cmd(esp, eregs, ESP_CMD_SATN); + return SUCCESS; + } + + /* If it is still in the issue queue then we can safely + * call the completion routine and report abort success. + */ + don = esp->dma_ports_p(esp); + if(don) { + esp->dma_ints_off(esp); + synchronize_irq(esp->irq); + } + if(esp->issue_SC) { + Scsi_Cmnd **prev, *this; + for(prev = (&esp->issue_SC), this = esp->issue_SC; + this; + prev = (Scsi_Cmnd **) &(this->host_scribble), + this = (Scsi_Cmnd *) this->host_scribble) { + if(this == SCptr) { + *prev = (Scsi_Cmnd *) this->host_scribble; + this->host_scribble = NULL; + esp_release_dmabufs(esp, this); + this->result = DID_ABORT << 16; + this->scsi_done(this); + if(don) + esp->dma_ints_on(esp); + return SUCCESS; + } + } + } + + /* Yuck, the command to abort is disconnected, it is not + * worth trying to abort it now if something else is live + * on the bus at this time. So, we let the SCSI code wait + * a little bit and try again later. + */ + if(esp->current_SC) { + if(don) + esp->dma_ints_on(esp); + return FAILED; + } + + /* It's disconnected, we have to reconnect to re-establish + * the nexus and tell the device to abort. However, we really + * cannot 'reconnect' per se. Don't try to be fancy, just + * indicate failure, which causes our caller to reset the whole + * bus. + */ + + if(don) + esp->dma_ints_on(esp); + return FAILED; +} + +/* We've sent ESP_CMD_RS to the ESP, the interrupt had just + * arrived indicating the end of the SCSI bus reset. Our job + * is to clean out the command queues and begin re-execution + * of SCSI commands once more. + */ +static int esp_finish_reset(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + Scsi_Cmnd *sp = esp->current_SC; + + /* Clean up currently executing command, if any. */ + if (sp != NULL) { + esp_release_dmabufs(esp, sp); + sp->result = (DID_RESET << 16); + sp->scsi_done(sp); + esp->current_SC = NULL; + } + + /* Clean up disconnected queue, they have been invalidated + * by the bus reset. + */ + if (esp->disconnected_SC) { + while((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) { + esp_release_dmabufs(esp, sp); + sp->result = (DID_RESET << 16); + sp->scsi_done(sp); + } + } + + /* SCSI bus reset is complete. */ + esp->resetting_bus = 0; + wake_up(&esp->reset_queue); + + /* Ok, now it is safe to get commands going once more. */ + if(esp->issue_SC) + esp_exec_cmd(esp); + + return do_intr_end; +} + +static int esp_do_resetbus(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id)); + esp->resetting_bus = 1; + esp_cmd(esp, eregs, ESP_CMD_RS); + + return do_intr_end; +} + +/* Reset ESP chip, reset hanging bus, then kill active and + * disconnected commands for targets without soft reset. + * + * The host_lock is acquired by caller. + */ +int esp_reset(Scsi_Cmnd *SCptr) +{ + struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->device->host->hostdata; + + spin_lock_irq(esp->ehost->host_lock); + (void) esp_do_resetbus(esp, esp->eregs); + spin_unlock_irq(esp->ehost->host_lock); + + wait_event(esp->reset_queue, (esp->resetting_bus == 0)); + + return SUCCESS; +} + +/* Internal ESP done function. */ +static void esp_done(struct NCR_ESP *esp, int error) +{ + Scsi_Cmnd *done_SC; + + if(esp->current_SC) { + done_SC = esp->current_SC; + esp->current_SC = NULL; + esp_release_dmabufs(esp, done_SC); + done_SC->result = error; + done_SC->scsi_done(done_SC); + + /* Bus is free, issue any commands in the queue. */ + if(esp->issue_SC && !esp->current_SC) + esp_exec_cmd(esp); + } else { + /* Panic is safe as current_SC is null so we may still + * be able to accept more commands to sync disk buffers. + */ + ESPLOG(("panicing\n")); + panic("esp: done() called with NULL esp->current_SC"); + } +} + +/* Wheee, ESP interrupt engine. */ + +/* Forward declarations. */ +static int esp_do_phase_determine(struct NCR_ESP *esp, + struct ESP_regs *eregs); +static int esp_do_data_finale(struct NCR_ESP *esp, struct ESP_regs *eregs); +static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs); +static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs); +static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs); +static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs); +static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs); +static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs); + +#define sreg_datainp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DIP) +#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP) + +/* We try to avoid some interrupts by jumping ahead and see if the ESP + * has gotten far enough yet. Hence the following. + */ +static inline int skipahead1(struct NCR_ESP *esp, struct ESP_regs *eregs, + Scsi_Cmnd *scp, int prev_phase, int new_phase) +{ + if(scp->SCp.sent_command != prev_phase) + return 0; + + if(esp->dma_irq_p(esp)) { + /* Yes, we are able to save an interrupt. */ + esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR)); + esp->ireg = esp_read(eregs->esp_intrpt); + if(!(esp->ireg & ESP_INTR_SR)) + return 0; + else + return do_reset_complete; + } + /* Ho hum, target is taking forever... */ + scp->SCp.sent_command = new_phase; /* so we don't recurse... */ + return do_intr_end; +} + +static inline int skipahead2(struct NCR_ESP *esp, + struct ESP_regs *eregs, + Scsi_Cmnd *scp, int prev_phase1, int prev_phase2, + int new_phase) +{ + if(scp->SCp.sent_command != prev_phase1 && + scp->SCp.sent_command != prev_phase2) + return 0; + if(esp->dma_irq_p(esp)) { + /* Yes, we are able to save an interrupt. */ + esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR)); + esp->ireg = esp_read(eregs->esp_intrpt); + if(!(esp->ireg & ESP_INTR_SR)) + return 0; + else + return do_reset_complete; + } + /* Ho hum, target is taking forever... */ + scp->SCp.sent_command = new_phase; /* so we don't recurse... */ + return do_intr_end; +} + +/* Misc. esp helper macros. */ +#define esp_setcount(__eregs, __cnt) \ + esp_write((__eregs)->esp_tclow, ((__cnt) & 0xff)); \ + esp_write((__eregs)->esp_tcmed, (((__cnt) >> 8) & 0xff)) + +#define esp_getcount(__eregs) \ + ((esp_read((__eregs)->esp_tclow)&0xff) | \ + ((esp_read((__eregs)->esp_tcmed)&0xff) << 8)) + +#define fcount(__esp, __eregs) \ + (esp_read((__eregs)->esp_fflags) & ESP_FF_FBYTES) + +#define fnzero(__esp, __eregs) \ + (esp_read((__eregs)->esp_fflags) & ESP_FF_ONOTZERO) + +/* XXX speculative nops unnecessary when continuing amidst a data phase + * XXX even on esp100!!! another case of flooding the bus with I/O reg + * XXX writes... + */ +#define esp_maybe_nop(__esp, __eregs) \ + if((__esp)->erev == esp100) \ + esp_cmd((__esp), (__eregs), ESP_CMD_NULL) + +#define sreg_to_dataphase(__sreg) \ + ((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain) + +/* The ESP100 when in synchronous data phase, can mistake a long final + * REQ pulse from the target as an extra byte, it places whatever is on + * the data lines into the fifo. For now, we will assume when this + * happens that the target is a bit quirky and we don't want to + * be talking synchronously to it anyways. Regardless, we need to + * tell the ESP to eat the extraneous byte so that we can proceed + * to the next phase. + */ +static inline int esp100_sync_hwbug(struct NCR_ESP *esp, struct ESP_regs *eregs, + Scsi_Cmnd *sp, int fifocnt) +{ + /* Do not touch this piece of code. */ + if((!(esp->erev == esp100)) || + (!(sreg_datainp((esp->sreg = esp_read(eregs->esp_status))) && !fifocnt) && + !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) { + if(sp->SCp.phase == in_dataout) + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + return 0; + } else { + /* Async mode for this guy. */ + build_sync_nego_msg(esp, 0, 0); + + /* Ack the bogus byte, but set ATN first. */ + esp_cmd(esp, eregs, ESP_CMD_SATN); + esp_cmd(esp, eregs, ESP_CMD_MOK); + return 1; + } +} + +/* This closes the window during a selection with a reselect pending, because + * we use DMA for the selection process the FIFO should hold the correct + * contents if we get reselected during this process. So we just need to + * ack the possible illegal cmd interrupt pending on the esp100. + */ +static inline int esp100_reconnect_hwbug(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + volatile unchar junk; + + if(esp->erev != esp100) + return 0; + junk = esp_read(eregs->esp_intrpt); + + if(junk & ESP_INTR_SR) + return 1; + return 0; +} + +/* This verifies the BUSID bits during a reselection so that we know which + * target is talking to us. + */ +static inline int reconnect_target(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + int it, me = esp->scsi_id_mask, targ = 0; + + if(2 != fcount(esp, eregs)) + return -1; + it = esp_read(eregs->esp_fdata); + if(!(it & me)) + return -1; + it &= ~me; + if(it & (it - 1)) + return -1; + while(!(it & 1)) + targ++, it >>= 1; + return targ; +} + +/* This verifies the identify from the target so that we know which lun is + * being reconnected. + */ +static inline int reconnect_lun(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + int lun; + + if((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) + return -1; + lun = esp_read(eregs->esp_fdata); + + /* Yes, you read this correctly. We report lun of zero + * if we see parity error. ESP reports parity error for + * the lun byte, and this is the only way to hope to recover + * because the target is connected. + */ + if(esp->sreg & ESP_STAT_PERR) + return 0; + + /* Check for illegal bits being set in the lun. */ + if((lun & 0x40) || !(lun & 0x80)) + return -1; + + return lun & 7; +} + +/* This puts the driver in a state where it can revitalize a command that + * is being continued due to reselection. + */ +static inline void esp_connect(struct NCR_ESP *esp, struct ESP_regs *eregs, + Scsi_Cmnd *sp) +{ + struct scsi_device *dp = sp->device; + struct esp_device *esp_dev = dp->hostdata; + + if(esp->prev_soff != esp_dev->sync_max_offset || + esp->prev_stp != esp_dev->sync_min_period || + (esp->erev > esp100a && + esp->prev_cfg3 != esp->config3[scmd_id(sp)])) { + esp->prev_soff = esp_dev->sync_max_offset; + esp_write(eregs->esp_soff, esp->prev_soff); + esp->prev_stp = esp_dev->sync_min_period; + esp_write(eregs->esp_stp, esp->prev_stp); + if(esp->erev > esp100a) { + esp->prev_cfg3 = esp->config3[scmd_id(sp)]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + } + } + esp->current_SC = sp; +} + +/* This will place the current working command back into the issue queue + * if we are to receive a reselection amidst a selection attempt. + */ +static inline void esp_reconnect(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + if(!esp->disconnected_SC) + ESPLOG(("esp%d: Weird, being reselected but disconnected " + "command queue is empty.\n", esp->esp_id)); + esp->snip = 0; + esp->current_SC = NULL; + sp->SCp.phase = not_issued; + append_SC(&esp->issue_SC, sp); +} + +/* Begin message in phase. */ +static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + esp_maybe_nop(esp, eregs); + esp_cmd(esp, eregs, ESP_CMD_TI); + esp->msgin_len = 1; + esp->msgin_ctr = 0; + esp_advance_phase(esp->current_SC, in_msgindone); + return do_work_bus; +} + +static inline void advance_sg(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + ++sp->SCp.buffer; + --sp->SCp.buffers_residual; + sp->SCp.this_residual = sp->SCp.buffer->length; + if (esp->dma_advance_sg) + esp->dma_advance_sg (sp); + else + sp->SCp.ptr = (char *) virt_to_phys(sg_virt(sp->SCp.buffer)); + +} + +/* Please note that the way I've coded these routines is that I _always_ + * check for a disconnect during any and all information transfer + * phases. The SCSI standard states that the target _can_ cause a BUS + * FREE condition by dropping all MSG/CD/IO/BSY signals. Also note + * that during information transfer phases the target controls every + * change in phase, the only thing the initiator can do is "ask" for + * a message out phase by driving ATN true. The target can, and sometimes + * will, completely ignore this request so we cannot assume anything when + * we try to force a message out phase to abort/reset a target. Most of + * the time the target will eventually be nice and go to message out, so + * we may have to hold on to our state about what we want to tell the target + * for some period of time. + */ + +/* I think I have things working here correctly. Even partial transfers + * within a buffer or sub-buffer should not upset us at all no matter + * how bad the target and/or ESP fucks things up. + */ +static int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + int thisphase, hmuch; + + ESPDATA(("esp_do_data: ")); + esp_maybe_nop(esp, eregs); + thisphase = sreg_to_dataphase(esp->sreg); + esp_advance_phase(SCptr, thisphase); + ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT")); + hmuch = esp->dma_can_transfer(esp, SCptr); + + /* + * XXX MSch: cater for PIO transfer here; PIO used if hmuch == 0 + */ + if (hmuch) { /* DMA */ + /* + * DMA + */ + ESPDATA(("hmuch<%d> ", hmuch)); + esp->current_transfer_size = hmuch; + esp_setcount(eregs, (esp->fas_premature_intr_workaround ? + (hmuch + 0x40) : hmuch)); + esp->dma_setup(esp, (__u32)((unsigned long)SCptr->SCp.ptr), + hmuch, (thisphase == in_datain)); + ESPDATA(("DMA|TI --> do_intr_end\n")); + esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); + return do_intr_end; + /* + * end DMA + */ + } else { + /* + * PIO + */ + int oldphase, i = 0; /* or where we left off last time ?? esp->current_data ?? */ + int fifocnt = 0; + unsigned char *p = phys_to_virt((unsigned long)SCptr->SCp.ptr); + + oldphase = esp_read(eregs->esp_status) & ESP_STAT_PMASK; + + /* + * polled transfer; ugly, can we make this happen in a DRQ + * interrupt handler ?? + * requires keeping track of state information in host or + * command struct! + * Problem: I've never seen a DRQ happen on Mac, not even + * with ESP_CMD_DMA ... + */ + + /* figure out how much needs to be transferred */ + hmuch = SCptr->SCp.this_residual; + ESPDATA(("hmuch<%d> pio ", hmuch)); + esp->current_transfer_size = hmuch; + + /* tell the ESP ... */ + esp_setcount(eregs, hmuch); + + /* loop */ + while (hmuch) { + int j, fifo_stuck = 0, newphase; + unsigned long timeout; +#if 0 + unsigned long flags; +#endif +#if 0 + if ( i % 10 ) + ESPDATA(("\r")); + else + ESPDATA(( /*"\n"*/ "\r")); +#endif +#if 0 + local_irq_save(flags); +#endif + if(thisphase == in_datain) { + /* 'go' ... */ + esp_cmd(esp, eregs, ESP_CMD_TI); + + /* wait for data */ + timeout = 1000000; + while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout) + udelay(2); + if (timeout == 0) + printk("DRQ datain timeout! \n"); + + newphase = esp->sreg & ESP_STAT_PMASK; + + /* see how much we got ... */ + fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES); + + if (!fifocnt) + fifo_stuck++; + else + fifo_stuck = 0; + + ESPDATA(("\rgot %d st %x ph %x", fifocnt, esp->sreg, newphase)); + + /* read fifo */ + for(j=0;jesp_fdata); + + ESPDATA(("(%d) ", i)); + + /* how many to go ?? */ + hmuch -= fifocnt; + + /* break if status phase !! */ + if(newphase == ESP_STATP) { + /* clear int. */ + esp->ireg = esp_read(eregs->esp_intrpt); + break; + } + } else { +#define MAX_FIFO 8 + /* how much will fit ? */ + int this_count = MAX_FIFO - fifocnt; + if (this_count > hmuch) + this_count = hmuch; + + /* fill fifo */ + for(j=0;jesp_fdata, p[i++]); + + /* how many left if this goes out ?? */ + hmuch -= this_count; + + /* 'go' ... */ + esp_cmd(esp, eregs, ESP_CMD_TI); + + /* wait for 'got it' */ + timeout = 1000000; + while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout) + udelay(2); + if (timeout == 0) + printk("DRQ dataout timeout! \n"); + + newphase = esp->sreg & ESP_STAT_PMASK; + + /* need to check how much was sent ?? */ + fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES); + + ESPDATA(("\rsent %d st %x ph %x", this_count - fifocnt, esp->sreg, newphase)); + + ESPDATA(("(%d) ", i)); + + /* break if status phase !! */ + if(newphase == ESP_STATP) { + /* clear int. */ + esp->ireg = esp_read(eregs->esp_intrpt); + break; + } + + } + + /* clear int. */ + esp->ireg = esp_read(eregs->esp_intrpt); + + ESPDATA(("ir %x ... ", esp->ireg)); + + if (hmuch == 0) + ESPDATA(("done! \n")); + +#if 0 + local_irq_restore(flags); +#endif + + /* check new bus phase */ + if (newphase != oldphase && i < esp->current_transfer_size) { + /* something happened; disconnect ?? */ + ESPDATA(("phase change, dropped out with %d done ... ", i)); + break; + } + + /* check int. status */ + if (esp->ireg & ESP_INTR_DC) { + /* disconnect */ + ESPDATA(("disconnect; %d transferred ... ", i)); + break; + } else if (esp->ireg & ESP_INTR_FDONE) { + /* function done */ + ESPDATA(("function done; %d transferred ... ", i)); + break; + } + + /* XXX fixme: bail out on stall */ + if (fifo_stuck > 10) { + /* we're stuck */ + ESPDATA(("fifo stall; %d transferred ... ", i)); + break; + } + } + + ESPDATA(("\n")); + /* check successful completion ?? */ + + if (thisphase == in_dataout) + hmuch += fifocnt; /* stuck?? adjust data pointer ...*/ + + /* tell do_data_finale how much was transferred */ + esp->current_transfer_size -= hmuch; + + /* still not completely sure on this one ... */ + return /*do_intr_end*/ do_work_bus /*do_phase_determine*/ ; + + /* + * end PIO + */ + } + return do_intr_end; +} + +/* See how successful the data transfer was. */ +static int esp_do_data_finale(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + struct esp_device *esp_dev = SCptr->device->hostdata; + int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0; + + if(esp->dma_led_off) + esp->dma_led_off(esp); + + ESPDATA(("esp_do_data_finale: ")); + + if(SCptr->SCp.phase == in_datain) { + if(esp->sreg & ESP_STAT_PERR) { + /* Yuck, parity error. The ESP asserts ATN + * so that we can go to message out phase + * immediately and inform the target that + * something bad happened. + */ + ESPLOG(("esp%d: data bad parity detected.\n", + esp->esp_id)); + esp->cur_msgout[0] = INITIATOR_ERROR; + esp->msgout_len = 1; + } + if(esp->dma_drain) + esp->dma_drain(esp); + } + if(esp->dma_invalidate) + esp->dma_invalidate(esp); + + /* This could happen for the above parity error case. */ + if(!(esp->ireg == ESP_INTR_BSERV)) { + /* Please go to msgout phase, please please please... */ + ESPLOG(("esp%d: !BSERV after data, probably to msgout\n", + esp->esp_id)); + return esp_do_phase_determine(esp, eregs); + } + + /* Check for partial transfers and other horrible events. */ + fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES); + ecount = esp_getcount(eregs); + if(esp->fas_premature_intr_workaround) + ecount -= 0x40; + bytes_sent = esp->current_transfer_size; + + ESPDATA(("trans_sz=%d, ", bytes_sent)); + if(!(esp->sreg & ESP_STAT_TCNT)) + bytes_sent -= ecount; + if(SCptr->SCp.phase == in_dataout) + bytes_sent -= fifocnt; + + ESPDATA(("bytes_sent=%d (ecount=%d, fifocnt=%d), ", bytes_sent, + ecount, fifocnt)); + + /* If we were in synchronous mode, check for peculiarities. */ + if(esp_dev->sync_max_offset) + bogus_data = esp100_sync_hwbug(esp, eregs, SCptr, fifocnt); + else + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + + /* Until we are sure of what has happened, we are certainly + * in the dark. + */ + esp_advance_phase(SCptr, in_the_dark); + + /* Check for premature interrupt condition. Can happen on FAS2x6 + * chips. QLogic recommends a workaround by overprogramming the + * transfer counters, but this makes doing scatter-gather impossible. + * Until there is a way to disable scatter-gather for a single target, + * and not only for the entire host adapter as it is now, the workaround + * is way to expensive performance wise. + * Instead, it turns out that when this happens the target has disconnected + * already but it doesn't show in the interrupt register. Compensate for + * that here to try and avoid a SCSI bus reset. + */ + if(!esp->fas_premature_intr_workaround && (fifocnt == 1) && + sreg_dataoutp(esp->sreg)) { + ESPLOG(("esp%d: Premature interrupt, enabling workaround\n", + esp->esp_id)); +#if 0 + /* Disable scatter-gather operations, they are not possible + * when using this workaround. + */ + esp->ehost->sg_tablesize = 0; + esp->ehost->use_clustering = ENABLE_CLUSTERING; + esp->fas_premature_intr_workaround = 1; + bytes_sent = 0; + if(SCptr->use_sg) { + ESPLOG(("esp%d: Aborting scatter-gather operation\n", + esp->esp_id)); + esp->cur_msgout[0] = ABORT; + esp->msgout_len = 1; + esp->msgout_ctr = 0; + esp_cmd(esp, eregs, ESP_CMD_SATN); + esp_setcount(eregs, 0xffff); + esp_cmd(esp, eregs, ESP_CMD_NULL); + esp_cmd(esp, eregs, ESP_CMD_TPAD | ESP_CMD_DMA); + return do_intr_end; + } +#else + /* Just set the disconnected bit. That's what appears to + * happen anyway. The state machine will pick it up when + * we return. + */ + esp->ireg |= ESP_INTR_DC; +#endif + } + + if(bytes_sent < 0) { + /* I've seen this happen due to lost state in this + * driver. No idea why it happened, but allowing + * this value to be negative caused things to + * lock up. This allows greater chance of recovery. + * In fact every time I've seen this, it has been + * a driver bug without question. + */ + ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id)); + ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n", + esp->esp_id, + esp->current_transfer_size, fifocnt, ecount)); + ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n", + esp->esp_id, + SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual)); + ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id, + SCptr->device->id)); + SCptr->device->borken = 1; + esp_dev->sync = 0; + bytes_sent = 0; + } + + /* Update the state of our transfer. */ + SCptr->SCp.ptr += bytes_sent; + SCptr->SCp.this_residual -= bytes_sent; + if(SCptr->SCp.this_residual < 0) { + /* shit */ + ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id)); + SCptr->SCp.this_residual = 0; + } + + /* Maybe continue. */ + if(!bogus_data) { + ESPDATA(("!bogus_data, ")); + /* NO MATTER WHAT, we advance the scatterlist, + * if the target should decide to disconnect + * in between scatter chunks (which is common) + * we could die horribly! I used to have the sg + * advance occur only if we are going back into + * (or are staying in) a data phase, you can + * imagine the hell I went through trying to + * figure this out. + */ + if(!SCptr->SCp.this_residual && SCptr->SCp.buffers_residual) + advance_sg(esp, SCptr); +#ifdef DEBUG_ESP_DATA + if(sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) { + ESPDATA(("to more data\n")); + } else { + ESPDATA(("to new phase\n")); + } +#endif + return esp_do_phase_determine(esp, eregs); + } + /* Bogus data, just wait for next interrupt. */ + ESPLOG(("esp%d: bogus_data during end of data phase\n", + esp->esp_id)); + return do_intr_end; +} + +/* We received a non-good status return at the end of + * running a SCSI command. This is used to decide if + * we should clear our synchronous transfer state for + * such a device when that happens. + * + * The idea is that when spinning up a disk or rewinding + * a tape, we don't want to go into a loop re-negotiating + * synchronous capabilities over and over. + */ +static int esp_should_clear_sync(Scsi_Cmnd *sp) +{ + unchar cmd = sp->cmnd[0]; + + /* These cases are for spinning up a disk and + * waiting for that spinup to complete. + */ + if(cmd == START_STOP) + return 0; + + if(cmd == TEST_UNIT_READY) + return 0; + + /* One more special case for SCSI tape drives, + * this is what is used to probe the device for + * completion of a rewind or tape load operation. + */ + if(sp->device->type == TYPE_TAPE && cmd == MODE_SENSE) + return 0; + + return 1; +} + +/* Either a command is completing or a target is dropping off the bus + * to continue the command in the background so we can do other work. + */ +static int esp_do_freebus(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + int rval; + + rval = skipahead2(esp, eregs, SCptr, in_status, in_msgindone, in_freeing); + if(rval) + return rval; + + if(esp->ireg != ESP_INTR_DC) { + ESPLOG(("esp%d: Target will not disconnect\n", esp->esp_id)); + return do_reset_bus; /* target will not drop BSY... */ + } + esp->msgout_len = 0; + esp->prevmsgout = NOP; + if(esp->prevmsgin == COMMAND_COMPLETE) { + struct esp_device *esp_dev = SCptr->device->hostdata; + /* Normal end of nexus. */ + if(esp->disconnected_SC) + esp_cmd(esp, eregs, ESP_CMD_ESEL); + + if(SCptr->SCp.Status != GOOD && + SCptr->SCp.Status != CONDITION_GOOD && + ((1<targets_present) && + esp_dev->sync && esp_dev->sync_max_offset) { + /* SCSI standard says that the synchronous capabilities + * should be renegotiated at this point. Most likely + * we are about to request sense from this target + * in which case we want to avoid using sync + * transfers until we are sure of the current target + * state. + */ + ESPMISC(("esp: Status <%d> for target %d lun %d\n", + SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun)); + + /* But don't do this when spinning up a disk at + * boot time while we poll for completion as it + * fills up the console with messages. Also, tapes + * can report not ready many times right after + * loading up a tape. + */ + if(esp_should_clear_sync(SCptr) != 0) + esp_dev->sync = 0; + } + ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun)); + esp_done(esp, ((SCptr->SCp.Status & 0xff) | + ((SCptr->SCp.Message & 0xff)<<8) | + (DID_OK << 16))); + } else if(esp->prevmsgin == DISCONNECT) { + /* Normal disconnect. */ + esp_cmd(esp, eregs, ESP_CMD_ESEL); + ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun)); + append_SC(&esp->disconnected_SC, SCptr); + esp->current_SC = NULL; + if(esp->issue_SC) + esp_exec_cmd(esp); + } else { + /* Driver bug, we do not expect a disconnect here + * and should not have advanced the state engine + * to in_freeing. + */ + ESPLOG(("esp%d: last msg not disc and not cmd cmplt.\n", + esp->esp_id)); + return do_reset_bus; + } + return do_intr_end; +} + +/* When a reselect occurs, and we cannot find the command to + * reconnect to in our queues, we do this. + */ +static int esp_bad_reconnect(struct NCR_ESP *esp) +{ + Scsi_Cmnd *sp; + + ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n", + esp->esp_id)); + ESPLOG(("QUEUE DUMP\n")); + sp = esp->issue_SC; + ESPLOG(("esp%d: issue_SC[", esp->esp_id)); + while(sp) { + ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); + sp = (Scsi_Cmnd *) sp->host_scribble; + } + ESPLOG(("]\n")); + sp = esp->current_SC; + ESPLOG(("esp%d: current_SC[", esp->esp_id)); + while(sp) { + ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); + sp = (Scsi_Cmnd *) sp->host_scribble; + } + ESPLOG(("]\n")); + sp = esp->disconnected_SC; + ESPLOG(("esp%d: disconnected_SC[", esp->esp_id)); + while(sp) { + ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); + sp = (Scsi_Cmnd *) sp->host_scribble; + } + ESPLOG(("]\n")); + return do_reset_bus; +} + +/* Do the needy when a target tries to reconnect to us. */ +static int esp_do_reconnect(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + int lun, target; + Scsi_Cmnd *SCptr; + + /* Check for all bogus conditions first. */ + target = reconnect_target(esp, eregs); + if(target < 0) { + ESPDISC(("bad bus bits\n")); + return do_reset_bus; + } + lun = reconnect_lun(esp, eregs); + if(lun < 0) { + ESPDISC(("target=%2x, bad identify msg\n", target)); + return do_reset_bus; + } + + /* Things look ok... */ + ESPDISC(("R<%02x,%02x>", target, lun)); + + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + if(esp100_reconnect_hwbug(esp, eregs)) + return do_reset_bus; + esp_cmd(esp, eregs, ESP_CMD_NULL); + + SCptr = remove_SC(&esp->disconnected_SC, (unchar) target, (unchar) lun); + if(!SCptr) + return esp_bad_reconnect(esp); + + esp_connect(esp, eregs, SCptr); + esp_cmd(esp, eregs, ESP_CMD_MOK); + + /* Reconnect implies a restore pointers operation. */ + esp_restore_pointers(esp, SCptr); + + esp->snip = 0; + esp_advance_phase(SCptr, in_the_dark); + return do_intr_end; +} + +/* End of NEXUS (hopefully), pick up status + message byte then leave if + * all goes well. + */ +static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + int intr, rval; + + rval = skipahead1(esp, eregs, SCptr, in_the_dark, in_status); + if(rval) + return rval; + + intr = esp->ireg; + ESPSTAT(("esp_do_status: ")); + if(intr != ESP_INTR_DC) { + int message_out = 0; /* for parity problems */ + + /* Ack the message. */ + ESPSTAT(("ack msg, ")); + esp_cmd(esp, eregs, ESP_CMD_MOK); + + if(esp->dma_poll) + esp->dma_poll(esp, (unsigned char *) esp->esp_command); + + ESPSTAT(("got something, ")); + /* ESP chimes in with one of + * + * 1) function done interrupt: + * both status and message in bytes + * are available + * + * 2) bus service interrupt: + * only status byte was acquired + * + * 3) Anything else: + * can't happen, but we test for it + * anyways + * + * ALSO: If bad parity was detected on either + * the status _or_ the message byte then + * the ESP has asserted ATN on the bus + * and we must therefore wait for the + * next phase change. + */ + if(intr & ESP_INTR_FDONE) { + /* We got it all, hallejulia. */ + ESPSTAT(("got both, ")); + SCptr->SCp.Status = esp->esp_command[0]; + SCptr->SCp.Message = esp->esp_command[1]; + esp->prevmsgin = SCptr->SCp.Message; + esp->cur_msgin[0] = SCptr->SCp.Message; + if(esp->sreg & ESP_STAT_PERR) { + /* There was bad parity for the + * message byte, the status byte + * was ok. + */ + message_out = MSG_PARITY_ERROR; + } + } else if(intr == ESP_INTR_BSERV) { + /* Only got status byte. */ + ESPLOG(("esp%d: got status only, ", esp->esp_id)); + if(!(esp->sreg & ESP_STAT_PERR)) { + SCptr->SCp.Status = esp->esp_command[0]; + SCptr->SCp.Message = 0xff; + } else { + /* The status byte had bad parity. + * we leave the scsi_pointer Status + * field alone as we set it to a default + * of CHECK_CONDITION in esp_queue. + */ + message_out = INITIATOR_ERROR; + } + } else { + /* This shouldn't happen ever. */ + ESPSTAT(("got bolixed\n")); + esp_advance_phase(SCptr, in_the_dark); + return esp_do_phase_determine(esp, eregs); + } + + if(!message_out) { + ESPSTAT(("status=%2x msg=%2x, ", SCptr->SCp.Status, + SCptr->SCp.Message)); + if(SCptr->SCp.Message == COMMAND_COMPLETE) { + ESPSTAT(("and was COMMAND_COMPLETE\n")); + esp_advance_phase(SCptr, in_freeing); + return esp_do_freebus(esp, eregs); + } else { + ESPLOG(("esp%d: and _not_ COMMAND_COMPLETE\n", + esp->esp_id)); + esp->msgin_len = esp->msgin_ctr = 1; + esp_advance_phase(SCptr, in_msgindone); + return esp_do_msgindone(esp, eregs); + } + } else { + /* With luck we'll be able to let the target + * know that bad parity happened, it will know + * which byte caused the problems and send it + * again. For the case where the status byte + * receives bad parity, I do not believe most + * targets recover very well. We'll see. + */ + ESPLOG(("esp%d: bad parity somewhere mout=%2x\n", + esp->esp_id, message_out)); + esp->cur_msgout[0] = message_out; + esp->msgout_len = esp->msgout_ctr = 1; + esp_advance_phase(SCptr, in_the_dark); + return esp_do_phase_determine(esp, eregs); + } + } else { + /* If we disconnect now, all hell breaks loose. */ + ESPLOG(("esp%d: whoops, disconnect\n", esp->esp_id)); + esp_advance_phase(SCptr, in_the_dark); + return esp_do_phase_determine(esp, eregs); + } +} + +static int esp_enter_status(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + unchar thecmd = ESP_CMD_ICCSEQ; + + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + + if(esp->do_pio_cmds) { + esp_advance_phase(esp->current_SC, in_status); + esp_cmd(esp, eregs, thecmd); + while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR)); + esp->esp_command[0] = esp_read(eregs->esp_fdata); + while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR)); + esp->esp_command[1] = esp_read(eregs->esp_fdata); + } else { + esp->esp_command[0] = esp->esp_command[1] = 0xff; + esp_write(eregs->esp_tclow, 2); + esp_write(eregs->esp_tcmed, 0); + esp->dma_init_read(esp, esp->esp_command_dvma, 2); + thecmd |= ESP_CMD_DMA; + esp_cmd(esp, eregs, thecmd); + esp_advance_phase(esp->current_SC, in_status); + } + + return esp_do_status(esp, eregs); +} + +static int esp_disconnect_amidst_phases(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + Scsi_Cmnd *sp = esp->current_SC; + struct esp_device *esp_dev = sp->device->hostdata; + + /* This means real problems if we see this + * here. Unless we were actually trying + * to force the device to abort/reset. + */ + ESPLOG(("esp%d: Disconnect amidst phases, ", esp->esp_id)); + ESPLOG(("pphase<%s> cphase<%s>, ", + phase_string(sp->SCp.phase), + phase_string(sp->SCp.sent_command))); + + if(esp->disconnected_SC) + esp_cmd(esp, eregs, ESP_CMD_ESEL); + + switch(esp->cur_msgout[0]) { + default: + /* We didn't expect this to happen at all. */ + ESPLOG(("device is bolixed\n")); + esp_advance_phase(sp, in_tgterror); + esp_done(esp, (DID_ERROR << 16)); + break; + + case BUS_DEVICE_RESET: + ESPLOG(("device reset successful\n")); + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + esp_dev->sync = 0; + esp_advance_phase(sp, in_resetdev); + esp_done(esp, (DID_RESET << 16)); + break; + + case ABORT: + ESPLOG(("device abort successful\n")); + esp_advance_phase(sp, in_abortone); + esp_done(esp, (DID_ABORT << 16)); + break; + + }; + return do_intr_end; +} + +static int esp_enter_msgout(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + esp_advance_phase(esp->current_SC, in_msgout); + return esp_do_msgout(esp, eregs); +} + +static int esp_enter_msgin(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + esp_advance_phase(esp->current_SC, in_msgin); + return esp_do_msgin(esp, eregs); +} + +static int esp_enter_cmd(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + esp_advance_phase(esp->current_SC, in_cmdbegin); + return esp_do_cmdbegin(esp, eregs); +} + +static int esp_enter_badphase(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id, + esp->sreg & ESP_STAT_PMASK)); + return do_reset_bus; +} + +typedef int (*espfunc_t)(struct NCR_ESP *, + struct ESP_regs *); + +static espfunc_t phase_vector[] = { + esp_do_data, /* ESP_DOP */ + esp_do_data, /* ESP_DIP */ + esp_enter_cmd, /* ESP_CMDP */ + esp_enter_status, /* ESP_STATP */ + esp_enter_badphase, /* ESP_STAT_PMSG */ + esp_enter_badphase, /* ESP_STAT_PMSG | ESP_STAT_PIO */ + esp_enter_msgout, /* ESP_MOP */ + esp_enter_msgin, /* ESP_MIP */ +}; + +/* The target has control of the bus and we have to see where it has + * taken us. + */ +static int esp_do_phase_determine(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + if ((esp->ireg & ESP_INTR_DC) != 0) + return esp_disconnect_amidst_phases(esp, eregs); + return phase_vector[esp->sreg & ESP_STAT_PMASK](esp, eregs); +} + +/* First interrupt after exec'ing a cmd comes here. */ +static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + struct esp_device *esp_dev = SCptr->device->hostdata; + int cmd_bytes_sent, fcnt; + + fcnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES); + cmd_bytes_sent = esp->dma_bytes_sent(esp, fcnt); + if(esp->dma_invalidate) + esp->dma_invalidate(esp); + + /* Let's check to see if a reselect happened + * while we we're trying to select. This must + * be checked first. + */ + if(esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) { + esp_reconnect(esp, SCptr); + return esp_do_reconnect(esp, eregs); + } + + /* Looks like things worked, we should see a bus service & + * a function complete interrupt at this point. Note we + * are doing a direct comparison because we don't want to + * be fooled into thinking selection was successful if + * ESP_INTR_DC is set, see below. + */ + if(esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) { + /* target speaks... */ + esp->targets_present |= (1<snip) + esp_dev->sync = 1; + + /* See how far, if at all, we got in getting + * the information out to the target. + */ + switch(esp->seqreg) { + default: + + case ESP_STEP_ASEL: + /* Arbitration won, target selected, but + * we are in some phase which is not command + * phase nor is it message out phase. + * + * XXX We've confused the target, obviously. + * XXX So clear it's state, but we also end + * XXX up clearing everyone elses. That isn't + * XXX so nice. I'd like to just reset this + * XXX target, but if I cannot even get it's + * XXX attention and finish selection to talk + * XXX to it, there is not much more I can do. + * XXX If we have a loaded bus we're going to + * XXX spend the next second or so renegotiating + * XXX for synchronous transfers. + */ + ESPLOG(("esp%d: STEP_ASEL for tgt %d\n", + esp->esp_id, SCptr->device->id)); + + case ESP_STEP_SID: + /* Arbitration won, target selected, went + * to message out phase, sent one message + * byte, then we stopped. ATN is asserted + * on the SCSI bus and the target is still + * there hanging on. This is a legal + * sequence step if we gave the ESP a select + * and stop command. + * + * XXX See above, I could set the borken flag + * XXX in the device struct and retry the + * XXX command. But would that help for + * XXX tagged capable targets? + */ + + case ESP_STEP_NCMD: + /* Arbitration won, target selected, maybe + * sent the one message byte in message out + * phase, but we did not go to command phase + * in the end. Actually, we could have sent + * only some of the message bytes if we tried + * to send out the entire identify and tag + * message using ESP_CMD_SA3. + */ + cmd_bytes_sent = 0; + break; + + case ESP_STEP_PPC: + /* No, not the powerPC pinhead. Arbitration + * won, all message bytes sent if we went to + * message out phase, went to command phase + * but only part of the command was sent. + * + * XXX I've seen this, but usually in conjunction + * XXX with a gross error which appears to have + * XXX occurred between the time I told the + * XXX ESP to arbitrate and when I got the + * XXX interrupt. Could I have misloaded the + * XXX command bytes into the fifo? Actually, + * XXX I most likely missed a phase, and therefore + * XXX went into never never land and didn't even + * XXX know it. That was the old driver though. + * XXX What is even more peculiar is that the ESP + * XXX showed the proper function complete and + * XXX bus service bits in the interrupt register. + */ + + case ESP_STEP_FINI4: + case ESP_STEP_FINI5: + case ESP_STEP_FINI6: + case ESP_STEP_FINI7: + /* Account for the identify message */ + if(SCptr->SCp.phase == in_slct_norm) + cmd_bytes_sent -= 1; + }; + esp_cmd(esp, eregs, ESP_CMD_NULL); + + /* Be careful, we could really get fucked during synchronous + * data transfers if we try to flush the fifo now. + */ + if(!fcnt && /* Fifo is empty and... */ + /* either we are not doing synchronous transfers or... */ + (!esp_dev->sync_max_offset || + /* We are not going into data in phase. */ + ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP))) + esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* flush is safe */ + + /* See how far we got if this is not a slow command. */ + if(!esp->esp_slowcmd) { + if(cmd_bytes_sent < 0) + cmd_bytes_sent = 0; + if(cmd_bytes_sent != SCptr->cmd_len) { + /* Crapola, mark it as a slowcmd + * so that we have some chance of + * keeping the command alive with + * good luck. + * + * XXX Actually, if we didn't send it all + * XXX this means either we didn't set things + * XXX up properly (driver bug) or the target + * XXX or the ESP detected parity on one of + * XXX the command bytes. This makes much + * XXX more sense, and therefore this code + * XXX should be changed to send out a + * XXX parity error message or if the status + * XXX register shows no parity error then + * XXX just expect the target to bring the + * XXX bus into message in phase so that it + * XXX can send us the parity error message. + * XXX SCSI sucks... + */ + esp->esp_slowcmd = 1; + esp->esp_scmdp = &(SCptr->cmnd[cmd_bytes_sent]); + esp->esp_scmdleft = (SCptr->cmd_len - cmd_bytes_sent); + } + } + + /* Now figure out where we went. */ + esp_advance_phase(SCptr, in_the_dark); + return esp_do_phase_determine(esp, eregs); + } + + /* Did the target even make it? */ + if(esp->ireg == ESP_INTR_DC) { + /* wheee... nobody there or they didn't like + * what we told it to do, clean up. + */ + + /* If anyone is off the bus, but working on + * a command in the background for us, tell + * the ESP to listen for them. + */ + if(esp->disconnected_SC) + esp_cmd(esp, eregs, ESP_CMD_ESEL); + + if(((1<device->id) & esp->targets_present) && + esp->seqreg && esp->cur_msgout[0] == EXTENDED_MESSAGE && + (SCptr->SCp.phase == in_slct_msg || + SCptr->SCp.phase == in_slct_stop)) { + /* shit */ + esp->snip = 0; + ESPLOG(("esp%d: Failed synchronous negotiation for target %d " + "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun)); + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + esp_dev->sync = 1; /* so we don't negotiate again */ + + /* Run the command again, this time though we + * won't try to negotiate for synchronous transfers. + * + * XXX I'd like to do something like send an + * XXX INITIATOR_ERROR or ABORT message to the + * XXX target to tell it, "Sorry I confused you, + * XXX please come back and I will be nicer next + * XXX time". But that requires having the target + * XXX on the bus, and it has dropped BSY on us. + */ + esp->current_SC = NULL; + esp_advance_phase(SCptr, not_issued); + prepend_SC(&esp->issue_SC, SCptr); + esp_exec_cmd(esp); + return do_intr_end; + } + + /* Ok, this is normal, this is what we see during boot + * or whenever when we are scanning the bus for targets. + * But first make sure that is really what is happening. + */ + if(((1<device->id) & esp->targets_present)) { + ESPLOG(("esp%d: Warning, live target %d not responding to " + "selection.\n", esp->esp_id, SCptr->device->id)); + + /* This _CAN_ happen. The SCSI standard states that + * the target is to _not_ respond to selection if + * _it_ detects bad parity on the bus for any reason. + * Therefore, we assume that if we've talked successfully + * to this target before, bad parity is the problem. + */ + esp_done(esp, (DID_PARITY << 16)); + } else { + /* Else, there really isn't anyone there. */ + ESPMISC(("esp: selection failure, maybe nobody there?\n")); + ESPMISC(("esp: target %d lun %d\n", + SCptr->device->id, SCptr->device->lun)); + esp_done(esp, (DID_BAD_TARGET << 16)); + } + return do_intr_end; + } + + + ESPLOG(("esp%d: Selection failure.\n", esp->esp_id)); + printk("esp%d: Currently -- ", esp->esp_id); + esp_print_ireg(esp->ireg); + printk(" "); + esp_print_statreg(esp->sreg); + printk(" "); + esp_print_seqreg(esp->seqreg); + printk("\n"); + printk("esp%d: New -- ", esp->esp_id); + esp->sreg = esp_read(eregs->esp_status); + esp->seqreg = esp_read(eregs->esp_sstep); + esp->ireg = esp_read(eregs->esp_intrpt); + esp_print_ireg(esp->ireg); + printk(" "); + esp_print_statreg(esp->sreg); + printk(" "); + esp_print_seqreg(esp->seqreg); + printk("\n"); + ESPLOG(("esp%d: resetting bus\n", esp->esp_id)); + return do_reset_bus; /* ugh... */ +} + +/* Continue reading bytes for msgin phase. */ +static int esp_do_msgincont(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + if(esp->ireg & ESP_INTR_BSERV) { + /* in the right phase too? */ + if((esp->sreg & ESP_STAT_PMASK) == ESP_MIP) { + /* phew... */ + esp_cmd(esp, eregs, ESP_CMD_TI); + esp_advance_phase(esp->current_SC, in_msgindone); + return do_intr_end; + } + + /* We changed phase but ESP shows bus service, + * in this case it is most likely that we, the + * hacker who has been up for 20hrs straight + * staring at the screen, drowned in coffee + * smelling like retched cigarette ashes + * have miscoded something..... so, try to + * recover as best we can. + */ + ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id)); + } + esp_advance_phase(esp->current_SC, in_the_dark); + return do_phase_determine; +} + +static int check_singlebyte_msg(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + esp->prevmsgin = esp->cur_msgin[0]; + if(esp->cur_msgin[0] & 0x80) { + /* wheee... */ + ESPLOG(("esp%d: target sends identify amidst phases\n", + esp->esp_id)); + esp_advance_phase(esp->current_SC, in_the_dark); + return 0; + } else if(((esp->cur_msgin[0] & 0xf0) == 0x20) || + (esp->cur_msgin[0] == EXTENDED_MESSAGE)) { + esp->msgin_len = 2; + esp_advance_phase(esp->current_SC, in_msgincont); + return 0; + } + esp_advance_phase(esp->current_SC, in_the_dark); + switch(esp->cur_msgin[0]) { + default: + /* We don't want to hear about it. */ + ESPLOG(("esp%d: msg %02x which we don't know about\n", esp->esp_id, + esp->cur_msgin[0])); + return MESSAGE_REJECT; + + case NOP: + ESPLOG(("esp%d: target %d sends a nop\n", esp->esp_id, + esp->current_SC->device->id)); + return 0; + + case RESTORE_POINTERS: + /* In this case we might also have to backup the + * "slow command" pointer. It is rare to get such + * a save/restore pointer sequence so early in the + * bus transition sequences, but cover it. + */ + if(esp->esp_slowcmd) { + esp->esp_scmdleft = esp->current_SC->cmd_len; + esp->esp_scmdp = &esp->current_SC->cmnd[0]; + } + esp_restore_pointers(esp, esp->current_SC); + return 0; + + case SAVE_POINTERS: + esp_save_pointers(esp, esp->current_SC); + return 0; + + case COMMAND_COMPLETE: + case DISCONNECT: + /* Freeing the bus, let it go. */ + esp->current_SC->SCp.phase = in_freeing; + return 0; + + case MESSAGE_REJECT: + ESPMISC(("msg reject, ")); + if(esp->prevmsgout == EXTENDED_MESSAGE) { + struct esp_device *esp_dev = esp->current_SC->device->hostdata; + + /* Doesn't look like this target can + * do synchronous or WIDE transfers. + */ + ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n")); + esp_dev->sync = 1; + esp_dev->wide = 1; + esp_dev->sync_min_period = 0; + esp_dev->sync_max_offset = 0; + return 0; + } else { + ESPMISC(("not sync nego, sending ABORT\n")); + return ABORT; + } + }; +} + +/* Target negotiates for synchronous transfers before we do, this + * is legal although very strange. What is even funnier is that + * the SCSI2 standard specifically recommends against targets doing + * this because so many initiators cannot cope with this occurring. + */ +static int target_with_ants_in_pants(struct NCR_ESP *esp, + Scsi_Cmnd *SCptr, + struct esp_device *esp_dev) +{ + if(esp_dev->sync || SCptr->device->borken) { + /* sorry, no can do */ + ESPSDTR(("forcing to async, ")); + build_sync_nego_msg(esp, 0, 0); + esp_dev->sync = 1; + esp->snip = 1; + ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id)); + esp_advance_phase(SCptr, in_the_dark); + return EXTENDED_MESSAGE; + } + + /* Ok, we'll check them out... */ + return 0; +} + +static void sync_report(struct NCR_ESP *esp) +{ + int msg3, msg4; + char *type; + + msg3 = esp->cur_msgin[3]; + msg4 = esp->cur_msgin[4]; + if(msg4) { + int hz = 1000000000 / (msg3 * 4); + int integer = hz / 1000000; + int fraction = (hz - (integer * 1000000)) / 10000; + if((msg3 * 4) < 200) { + type = "FAST"; + } else { + type = "synchronous"; + } + + /* Do not transform this back into one big printk + * again, it triggers a bug in our sparc64-gcc272 + * sibling call optimization. -DaveM + */ + ESPLOG((KERN_INFO "esp%d: target %d ", + esp->esp_id, esp->current_SC->device->id)); + ESPLOG(("[period %dns offset %d %d.%02dMHz ", + (int) msg3 * 4, (int) msg4, + integer, fraction)); + ESPLOG(("%s SCSI%s]\n", type, + (((msg3 * 4) < 200) ? "-II" : ""))); + } else { + ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n", + esp->esp_id, esp->current_SC->device->id)); + } +} + +static int check_multibyte_msg(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + struct esp_device *esp_dev = SCptr->device->hostdata; + unchar regval = 0; + int message_out = 0; + + ESPSDTR(("chk multibyte msg: ")); + if(esp->cur_msgin[2] == EXTENDED_SDTR) { + int period = esp->cur_msgin[3]; + int offset = esp->cur_msgin[4]; + + ESPSDTR(("is sync nego response, ")); + if(!esp->snip) { + int rval; + + /* Target negotiates first! */ + ESPSDTR(("target jumps the gun, ")); + message_out = EXTENDED_MESSAGE; /* we must respond */ + rval = target_with_ants_in_pants(esp, SCptr, esp_dev); + if(rval) + return rval; + } + + ESPSDTR(("examining sdtr, ")); + + /* Offset cannot be larger than ESP fifo size. */ + if(offset > 15) { + ESPSDTR(("offset too big %2x, ", offset)); + offset = 15; + ESPSDTR(("sending back new offset\n")); + build_sync_nego_msg(esp, period, offset); + return EXTENDED_MESSAGE; + } + + if(offset && period > esp->max_period) { + /* Yeee, async for this slow device. */ + ESPSDTR(("period too long %2x, ", period)); + build_sync_nego_msg(esp, 0, 0); + ESPSDTR(("hoping for msgout\n")); + esp_advance_phase(esp->current_SC, in_the_dark); + return EXTENDED_MESSAGE; + } else if (offset && period < esp->min_period) { + ESPSDTR(("period too short %2x, ", period)); + period = esp->min_period; + if(esp->erev > esp236) + regval = 4; + else + regval = 5; + } else if(offset) { + int tmp; + + ESPSDTR(("period is ok, ")); + tmp = esp->ccycle / 1000; + regval = (((period << 2) + tmp - 1) / tmp); + if(regval && (esp->erev > esp236)) { + if(period >= 50) + regval--; + } + } + + if(offset) { + unchar bit; + + esp_dev->sync_min_period = (regval & 0x1f); + esp_dev->sync_max_offset = (offset | esp->radelay); + if(esp->erev > esp236) { + if(esp->erev == fas100a) + bit = ESP_CONFIG3_FAST; + else + bit = ESP_CONFIG3_FSCSI; + if(period < 50) + esp->config3[SCptr->device->id] |= bit; + else + esp->config3[SCptr->device->id] &= ~bit; + esp->prev_cfg3 = esp->config3[SCptr->device->id]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + } + esp->prev_soff = esp_dev->sync_min_period; + esp_write(eregs->esp_soff, esp->prev_soff); + esp->prev_stp = esp_dev->sync_max_offset; + esp_write(eregs->esp_stp, esp->prev_stp); + + ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n", + esp_dev->sync_max_offset, + esp_dev->sync_min_period, + esp->config3[scmd_id(SCptr)])); + + esp->snip = 0; + } else if(esp_dev->sync_max_offset) { + unchar bit; + + /* back to async mode */ + ESPSDTR(("unaccaptable sync nego, forcing async\n")); + esp_dev->sync_max_offset = 0; + esp_dev->sync_min_period = 0; + esp->prev_soff = 0; + esp_write(eregs->esp_soff, 0); + esp->prev_stp = 0; + esp_write(eregs->esp_stp, 0); + if(esp->erev > esp236) { + if(esp->erev == fas100a) + bit = ESP_CONFIG3_FAST; + else + bit = ESP_CONFIG3_FSCSI; + esp->config3[SCptr->device->id] &= ~bit; + esp->prev_cfg3 = esp->config3[SCptr->device->id]; + esp_write(eregs->esp_cfg3, esp->prev_cfg3); + } + } + + sync_report(esp); + + ESPSDTR(("chk multibyte msg: sync is known, ")); + esp_dev->sync = 1; + + if(message_out) { + ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n", + esp->esp_id)); + build_sync_nego_msg(esp, period, offset); + esp_advance_phase(SCptr, in_the_dark); + return EXTENDED_MESSAGE; + } + + ESPSDTR(("returning zero\n")); + esp_advance_phase(SCptr, in_the_dark); /* ...or else! */ + return 0; + } else if(esp->cur_msgin[2] == EXTENDED_WDTR) { + ESPLOG(("esp%d: AIEEE wide msg received\n", esp->esp_id)); + message_out = MESSAGE_REJECT; + } else if(esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) { + ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id)); + message_out = MESSAGE_REJECT; + } + esp_advance_phase(SCptr, in_the_dark); + return message_out; +} + +static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + int message_out = 0, it = 0, rval; + + rval = skipahead1(esp, eregs, SCptr, in_msgin, in_msgindone); + if(rval) + return rval; + if(SCptr->SCp.sent_command != in_status) { + if(!(esp->ireg & ESP_INTR_DC)) { + if(esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) { + message_out = MSG_PARITY_ERROR; + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + } else if((it = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES))!=1) { + /* We certainly dropped the ball somewhere. */ + message_out = INITIATOR_ERROR; + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + } else if(!esp->msgin_len) { + it = esp_read(eregs->esp_fdata); + esp_advance_phase(SCptr, in_msgincont); + } else { + /* it is ok and we want it */ + it = esp->cur_msgin[esp->msgin_ctr] = + esp_read(eregs->esp_fdata); + esp->msgin_ctr++; + } + } else { + esp_advance_phase(SCptr, in_the_dark); + return do_work_bus; + } + } else { + it = esp->cur_msgin[0]; + } + if(!message_out && esp->msgin_len) { + if(esp->msgin_ctr < esp->msgin_len) { + esp_advance_phase(SCptr, in_msgincont); + } else if(esp->msgin_len == 1) { + message_out = check_singlebyte_msg(esp, eregs); + } else if(esp->msgin_len == 2) { + if(esp->cur_msgin[0] == EXTENDED_MESSAGE) { + if((it+2) >= 15) { + message_out = MESSAGE_REJECT; + } else { + esp->msgin_len = (it + 2); + esp_advance_phase(SCptr, in_msgincont); + } + } else { + message_out = MESSAGE_REJECT; /* foo on you */ + } + } else { + message_out = check_multibyte_msg(esp, eregs); + } + } + if(message_out < 0) { + return -message_out; + } else if(message_out) { + if(((message_out != 1) && + ((message_out < 0x20) || (message_out & 0x80)))) + esp->msgout_len = 1; + esp->cur_msgout[0] = message_out; + esp_cmd(esp, eregs, ESP_CMD_SATN); + esp_advance_phase(SCptr, in_the_dark); + esp->msgin_len = 0; + } + esp->sreg = esp_read(eregs->esp_status); + esp->sreg &= ~(ESP_STAT_INTR); + if((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD)) + esp_cmd(esp, eregs, ESP_CMD_MOK); + if((SCptr->SCp.sent_command == in_msgindone) && + (SCptr->SCp.phase == in_freeing)) + return esp_do_freebus(esp, eregs); + return do_intr_end; +} + +static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + unsigned char tmp; + Scsi_Cmnd *SCptr = esp->current_SC; + + esp_advance_phase(SCptr, in_cmdend); + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + tmp = *esp->esp_scmdp++; + esp->esp_scmdleft--; + esp_write(eregs->esp_fdata, tmp); + esp_cmd(esp, eregs, ESP_CMD_TI); + return do_intr_end; +} + +static int esp_do_cmddone(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + esp_cmd(esp, eregs, ESP_CMD_NULL); + if(esp->ireg & ESP_INTR_BSERV) { + esp_advance_phase(esp->current_SC, in_the_dark); + return esp_do_phase_determine(esp, eregs); + } + ESPLOG(("esp%d: in do_cmddone() but didn't get BSERV interrupt.\n", + esp->esp_id)); + return do_reset_bus; +} + +static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + switch(esp->msgout_len) { + case 1: + esp_write(eregs->esp_fdata, esp->cur_msgout[0]); + esp_cmd(esp, eregs, ESP_CMD_TI); + break; + + case 2: + if(esp->do_pio_cmds){ + esp_write(eregs->esp_fdata, esp->cur_msgout[0]); + esp_write(eregs->esp_fdata, esp->cur_msgout[1]); + esp_cmd(esp, eregs, ESP_CMD_TI); + } else { + esp->esp_command[0] = esp->cur_msgout[0]; + esp->esp_command[1] = esp->cur_msgout[1]; + esp->dma_setup(esp, esp->esp_command_dvma, 2, 0); + esp_setcount(eregs, 2); + esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); + } + break; + + case 4: + esp->snip = 1; + if(esp->do_pio_cmds){ + esp_write(eregs->esp_fdata, esp->cur_msgout[0]); + esp_write(eregs->esp_fdata, esp->cur_msgout[1]); + esp_write(eregs->esp_fdata, esp->cur_msgout[2]); + esp_write(eregs->esp_fdata, esp->cur_msgout[3]); + esp_cmd(esp, eregs, ESP_CMD_TI); + } else { + esp->esp_command[0] = esp->cur_msgout[0]; + esp->esp_command[1] = esp->cur_msgout[1]; + esp->esp_command[2] = esp->cur_msgout[2]; + esp->esp_command[3] = esp->cur_msgout[3]; + esp->dma_setup(esp, esp->esp_command_dvma, 4, 0); + esp_setcount(eregs, 4); + esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); + } + break; + + case 5: + esp->snip = 1; + if(esp->do_pio_cmds){ + esp_write(eregs->esp_fdata, esp->cur_msgout[0]); + esp_write(eregs->esp_fdata, esp->cur_msgout[1]); + esp_write(eregs->esp_fdata, esp->cur_msgout[2]); + esp_write(eregs->esp_fdata, esp->cur_msgout[3]); + esp_write(eregs->esp_fdata, esp->cur_msgout[4]); + esp_cmd(esp, eregs, ESP_CMD_TI); + } else { + esp->esp_command[0] = esp->cur_msgout[0]; + esp->esp_command[1] = esp->cur_msgout[1]; + esp->esp_command[2] = esp->cur_msgout[2]; + esp->esp_command[3] = esp->cur_msgout[3]; + esp->esp_command[4] = esp->cur_msgout[4]; + esp->dma_setup(esp, esp->esp_command_dvma, 5, 0); + esp_setcount(eregs, 5); + esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); + } + break; + + default: + /* whoops */ + ESPMISC(("bogus msgout sending NOP\n")); + esp->cur_msgout[0] = NOP; + esp_write(eregs->esp_fdata, esp->cur_msgout[0]); + esp->msgout_len = 1; + esp_cmd(esp, eregs, ESP_CMD_TI); + break; + } + esp_advance_phase(esp->current_SC, in_msgoutdone); + return do_intr_end; +} + +static int esp_do_msgoutdone(struct NCR_ESP *esp, + struct ESP_regs *eregs) +{ + if((esp->msgout_len > 1) && esp->dma_barrier) + esp->dma_barrier(esp); + + if(!(esp->ireg & ESP_INTR_DC)) { + esp_cmd(esp, eregs, ESP_CMD_NULL); + switch(esp->sreg & ESP_STAT_PMASK) { + case ESP_MOP: + /* whoops, parity error */ + ESPLOG(("esp%d: still in msgout, parity error assumed\n", + esp->esp_id)); + if(esp->msgout_len > 1) + esp_cmd(esp, eregs, ESP_CMD_SATN); + esp_advance_phase(esp->current_SC, in_msgout); + return do_work_bus; + + case ESP_DIP: + break; + + default: + if(!fcount(esp, eregs) && + !(((struct esp_device *)esp->current_SC->device->hostdata)->sync_max_offset)) + esp_cmd(esp, eregs, ESP_CMD_FLUSH); + break; + + }; + } + + /* If we sent out a synchronous negotiation message, update + * our state. + */ + if(esp->cur_msgout[2] == EXTENDED_MESSAGE && + esp->cur_msgout[4] == EXTENDED_SDTR) { + esp->snip = 1; /* anal retentiveness... */ + } + + esp->prevmsgout = esp->cur_msgout[0]; + esp->msgout_len = 0; + esp_advance_phase(esp->current_SC, in_the_dark); + return esp_do_phase_determine(esp, eregs); +} + +static int esp_bus_unexpected(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + ESPLOG(("esp%d: command in weird state %2x\n", + esp->esp_id, esp->current_SC->SCp.phase)); + return do_reset_bus; +} + +static espfunc_t bus_vector[] = { + esp_do_data_finale, + esp_do_data_finale, + esp_bus_unexpected, + esp_do_msgin, + esp_do_msgincont, + esp_do_msgindone, + esp_do_msgout, + esp_do_msgoutdone, + esp_do_cmdbegin, + esp_do_cmddone, + esp_do_status, + esp_do_freebus, + esp_do_phase_determine, + esp_bus_unexpected, + esp_bus_unexpected, + esp_bus_unexpected, +}; + +/* This is the second tier in our dual-level SCSI state machine. */ +static int esp_work_bus(struct NCR_ESP *esp, struct ESP_regs *eregs) +{ + Scsi_Cmnd *SCptr = esp->current_SC; + unsigned int phase; + + ESPBUS(("esp_work_bus: ")); + if(!SCptr) { + ESPBUS(("reconnect\n")); + return esp_do_reconnect(esp, eregs); + } + phase = SCptr->SCp.phase; + if ((phase & 0xf0) == in_phases_mask) + return bus_vector[(phase & 0x0f)](esp, eregs); + else if((phase & 0xf0) == in_slct_mask) + return esp_select_complete(esp, eregs); + else + return esp_bus_unexpected(esp, eregs); +} + +static espfunc_t isvc_vector[] = { + NULL, + esp_do_phase_determine, + esp_do_resetbus, + esp_finish_reset, + esp_work_bus +}; + +/* Main interrupt handler for an esp adapter. */ +void esp_handle(struct NCR_ESP *esp) +{ + struct ESP_regs *eregs; + Scsi_Cmnd *SCptr; + int what_next = do_intr_end; + eregs = esp->eregs; + SCptr = esp->current_SC; + + if(esp->dma_irq_entry) + esp->dma_irq_entry(esp); + + /* Check for errors. */ + esp->sreg = esp_read(eregs->esp_status); + esp->sreg &= (~ESP_STAT_INTR); + esp->seqreg = (esp_read(eregs->esp_sstep) & ESP_STEP_VBITS); + esp->ireg = esp_read(eregs->esp_intrpt); /* Unlatch intr and stat regs */ + ESPIRQ(("handle_irq: [sreg<%02x> sstep<%02x> ireg<%02x>]\n", + esp->sreg, esp->seqreg, esp->ireg)); + if(esp->sreg & (ESP_STAT_SPAM)) { + /* Gross error, could be due to one of: + * + * - top of fifo overwritten, could be because + * we tried to do a synchronous transfer with + * an offset greater than ESP fifo size + * + * - top of command register overwritten + * + * - DMA setup to go in one direction, SCSI + * bus points in the other, whoops + * + * - weird phase change during asynchronous + * data phase while we are initiator + */ + ESPLOG(("esp%d: Gross error sreg=%2x\n", esp->esp_id, esp->sreg)); + + /* If a command is live on the bus we cannot safely + * reset the bus, so we'll just let the pieces fall + * where they may. Here we are hoping that the + * target will be able to cleanly go away soon + * so we can safely reset things. + */ + if(!SCptr) { + ESPLOG(("esp%d: No current cmd during gross error, " + "resetting bus\n", esp->esp_id)); + what_next = do_reset_bus; + goto state_machine; + } + } + + /* No current cmd is only valid at this point when there are + * commands off the bus or we are trying a reset. + */ + if(!SCptr && !esp->disconnected_SC && !(esp->ireg & ESP_INTR_SR)) { + /* Panic is safe, since current_SC is null. */ + ESPLOG(("esp%d: no command in esp_handle()\n", esp->esp_id)); + panic("esp_handle: current_SC == penguin within interrupt!"); + } + + if(esp->ireg & (ESP_INTR_IC)) { + /* Illegal command fed to ESP. Outside of obvious + * software bugs that could cause this, there is + * a condition with ESP100 where we can confuse the + * ESP into an erroneous illegal command interrupt + * because it does not scrape the FIFO properly + * for reselection. See esp100_reconnect_hwbug() + * to see how we try very hard to avoid this. + */ + ESPLOG(("esp%d: invalid command\n", esp->esp_id)); + + esp_dump_state(esp, eregs); + + if(SCptr) { + /* Devices with very buggy firmware can drop BSY + * during a scatter list interrupt when using sync + * mode transfers. We continue the transfer as + * expected, the target drops the bus, the ESP + * gets confused, and we get a illegal command + * interrupt because the bus is in the disconnected + * state now and ESP_CMD_TI is only allowed when + * a nexus is alive on the bus. + */ + ESPLOG(("esp%d: Forcing async and disabling disconnect for " + "target %d\n", esp->esp_id, SCptr->device->id)); + SCptr->device->borken = 1; /* foo on you */ + } + + what_next = do_reset_bus; + } else if(!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) { + int phase; + + if(SCptr) { + phase = SCptr->SCp.phase; + if(phase & in_phases_mask) { + what_next = esp_work_bus(esp, eregs); + } else if(phase & in_slct_mask) { + what_next = esp_select_complete(esp, eregs); + } else { + ESPLOG(("esp%d: interrupt for no good reason...\n", + esp->esp_id)); + what_next = do_intr_end; + } + } else { + ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n", + esp->esp_id)); + what_next = do_reset_bus; + } + } else if(esp->ireg & ESP_INTR_SR) { + ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id)); + what_next = do_reset_complete; + } else if(esp->ireg & (ESP_INTR_S | ESP_INTR_SATN)) { + ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n", + esp->esp_id)); + what_next = do_reset_bus; + } else if(esp->ireg & ESP_INTR_RSEL) { + if(!SCptr) { + /* This is ok. */ + what_next = esp_do_reconnect(esp, eregs); + } else if(SCptr->SCp.phase & in_slct_mask) { + /* Only selection code knows how to clean + * up properly. + */ + ESPDISC(("Reselected during selection attempt\n")); + what_next = esp_select_complete(esp, eregs); + } else { + ESPLOG(("esp%d: Reselected while bus is busy\n", + esp->esp_id)); + what_next = do_reset_bus; + } + } + + /* This is tier-one in our dual level SCSI state machine. */ +state_machine: + while(what_next != do_intr_end) { + if (what_next >= do_phase_determine && + what_next < do_intr_end) + what_next = isvc_vector[what_next](esp, eregs); + else { + /* state is completely lost ;-( */ + ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n", + esp->esp_id)); + what_next = do_reset_bus; + } + } + if(esp->dma_irq_exit) + esp->dma_irq_exit(esp); +} +EXPORT_SYMBOL(esp_handle); + +#ifndef CONFIG_SMP +irqreturn_t esp_intr(int irq, void *dev_id) +{ + struct NCR_ESP *esp; + unsigned long flags; + int again; + struct Scsi_Host *dev = dev_id; + + /* Handle all ESP interrupts showing at this IRQ level. */ + spin_lock_irqsave(dev->host_lock, flags); +repeat: + again = 0; + for_each_esp(esp) { +#ifndef __mips__ + if(((esp)->irq & 0xff) == irq) { +#endif + if(esp->dma_irq_p(esp)) { + again = 1; + + esp->dma_ints_off(esp); + + ESPIRQ(("I%d(", esp->esp_id)); + esp_handle(esp); + ESPIRQ((")")); + + esp->dma_ints_on(esp); + } +#ifndef __mips__ + } +#endif + } + if(again) + goto repeat; + spin_unlock_irqrestore(dev->host_lock, flags); + return IRQ_HANDLED; +} +#else +/* For SMP we only service one ESP on the list list at our IRQ level! */ +irqreturn_t esp_intr(int irq, void *dev_id) +{ + struct NCR_ESP *esp; + unsigned long flags; + struct Scsi_Host *dev = dev_id; + + /* Handle all ESP interrupts showing at this IRQ level. */ + spin_lock_irqsave(dev->host_lock, flags); + for_each_esp(esp) { + if(((esp)->irq & 0xf) == irq) { + if(esp->dma_irq_p(esp)) { + esp->dma_ints_off(esp); + + ESPIRQ(("I[%d:%d](", + smp_processor_id(), esp->esp_id)); + esp_handle(esp); + ESPIRQ((")")); + + esp->dma_ints_on(esp); + goto out; + } + } + } +out: + spin_unlock_irqrestore(dev->host_lock, flags); + return IRQ_HANDLED; +} +#endif + +int esp_slave_alloc(struct scsi_device *SDptr) +{ + struct esp_device *esp_dev = + kzalloc(sizeof(struct esp_device), GFP_ATOMIC); + + if (!esp_dev) + return -ENOMEM; + SDptr->hostdata = esp_dev; + return 0; +} + +void esp_slave_destroy(struct scsi_device *SDptr) +{ + struct NCR_ESP *esp = (struct NCR_ESP *) SDptr->host->hostdata; + + esp->targets_present &= ~(1 << sdev_id(SDptr)); + kfree(SDptr->hostdata); + SDptr->hostdata = NULL; +} + +#ifdef MODULE +int init_module(void) { return 0; } +void cleanup_module(void) {} +void esp_release(void) +{ + esps_in_use--; + esps_running = esps_in_use; +} +EXPORT_SYMBOL(esp_release); +#endif + +EXPORT_SYMBOL(esp_abort); +EXPORT_SYMBOL(esp_allocate); +EXPORT_SYMBOL(esp_deallocate); +EXPORT_SYMBOL(esp_initialize); +EXPORT_SYMBOL(esp_intr); +EXPORT_SYMBOL(esp_queue); +EXPORT_SYMBOL(esp_reset); +EXPORT_SYMBOL(esp_slave_alloc); +EXPORT_SYMBOL(esp_slave_destroy); +EXPORT_SYMBOL(esps_in_use); + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/NCR53C9x.h b/trunk/drivers/scsi/NCR53C9x.h new file mode 100644 index 000000000000..00a0ba040dba --- /dev/null +++ b/trunk/drivers/scsi/NCR53C9x.h @@ -0,0 +1,668 @@ +/* NCR53C9x.c: Defines and structures for the NCR53C9x generic driver. + * + * Originally esp.h: Defines and structures for the Sparc ESP + * (Enhanced SCSI Processor) driver under Linux. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * Generalization by Jesper Skov (jskov@cygnus.co.uk) + * + * More generalization (for i386 stuff) by Tymm Twillman (tymm@computer.org) + */ + +#ifndef NCR53C9X_H +#define NCR53C9X_H + +#include + +/* djweis for mac driver */ +#if defined(CONFIG_MAC) +#define PAD_SIZE 15 +#else +#define PAD_SIZE 3 +#endif + +/* Handle multiple hostadapters on Amiga + * generally PAD_SIZE = 3 + * but there is one exception: Oktagon (PAD_SIZE = 1) */ +#if defined(CONFIG_OKTAGON_SCSI) || defined(CONFIG_OKTAGON_SCSI_MODULE) +#undef PAD_SIZE +#if defined(CONFIG_BLZ1230_SCSI) || defined(CONFIG_BLZ1230_SCSI_MODULE) || \ + defined(CONFIG_BLZ2060_SCSI) || defined(CONFIG_BLZ2060_SCSI_MODULE) || \ + defined(CONFIG_CYBERSTORM_SCSI) || defined(CONFIG_CYBERSTORM_SCSI_MODULE) || \ + defined(CONFIG_CYBERSTORMII_SCSI) || defined(CONFIG_CYBERSTORMII_SCSI_MODULE) || \ + defined(CONFIG_FASTLANE_SCSI) || defined(CONFIG_FASTLANE_SCSI_MODULE) +#define MULTIPLE_PAD_SIZES +#else +#define PAD_SIZE 1 +#endif +#endif + +/* Macros for debugging messages */ + +#define DEBUG_ESP +/* #define DEBUG_ESP_DATA */ +/* #define DEBUG_ESP_QUEUE */ +/* #define DEBUG_ESP_DISCONNECT */ +/* #define DEBUG_ESP_STATUS */ +/* #define DEBUG_ESP_PHASES */ +/* #define DEBUG_ESP_WORKBUS */ +/* #define DEBUG_STATE_MACHINE */ +/* #define DEBUG_ESP_CMDS */ +/* #define DEBUG_ESP_IRQS */ +/* #define DEBUG_SDTR */ +/* #define DEBUG_ESP_SG */ + +/* Use the following to sprinkle debugging messages in a way which + * suits you if combinations of the above become too verbose when + * trying to track down a specific problem. + */ +/* #define DEBUG_ESP_MISC */ + +#if defined(DEBUG_ESP) +#define ESPLOG(foo) printk foo +#else +#define ESPLOG(foo) +#endif /* (DEBUG_ESP) */ + +#if defined(DEBUG_ESP_DATA) +#define ESPDATA(foo) printk foo +#else +#define ESPDATA(foo) +#endif + +#if defined(DEBUG_ESP_QUEUE) +#define ESPQUEUE(foo) printk foo +#else +#define ESPQUEUE(foo) +#endif + +#if defined(DEBUG_ESP_DISCONNECT) +#define ESPDISC(foo) printk foo +#else +#define ESPDISC(foo) +#endif + +#if defined(DEBUG_ESP_STATUS) +#define ESPSTAT(foo) printk foo +#else +#define ESPSTAT(foo) +#endif + +#if defined(DEBUG_ESP_PHASES) +#define ESPPHASE(foo) printk foo +#else +#define ESPPHASE(foo) +#endif + +#if defined(DEBUG_ESP_WORKBUS) +#define ESPBUS(foo) printk foo +#else +#define ESPBUS(foo) +#endif + +#if defined(DEBUG_ESP_IRQS) +#define ESPIRQ(foo) printk foo +#else +#define ESPIRQ(foo) +#endif + +#if defined(DEBUG_SDTR) +#define ESPSDTR(foo) printk foo +#else +#define ESPSDTR(foo) +#endif + +#if defined(DEBUG_ESP_MISC) +#define ESPMISC(foo) printk foo +#else +#define ESPMISC(foo) +#endif + +/* + * padding for register structure + */ +#ifdef CONFIG_JAZZ_ESP +#define EREGS_PAD(n) +#else +#ifndef MULTIPLE_PAD_SIZES +#define EREGS_PAD(n) unchar n[PAD_SIZE]; +#endif +#endif + +/* The ESP SCSI controllers have their register sets in three + * "classes": + * + * 1) Registers which are both read and write. + * 2) Registers which are read only. + * 3) Registers which are write only. + * + * Yet, they all live within the same IO space. + */ + +#if !defined(__i386__) && !defined(__x86_64__) + +#ifndef MULTIPLE_PAD_SIZES + +#ifdef CONFIG_CPU_HAS_WB +#include +#define esp_write(__reg, __val) do{(__reg) = (__val); wbflush();} while(0) +#else +#define esp_write(__reg, __val) ((__reg) = (__val)) +#endif +#define esp_read(__reg) (__reg) + +struct ESP_regs { + /* Access Description Offset */ + volatile unchar esp_tclow; /* rw Low bits of the transfer count 0x00 */ + EREGS_PAD(tlpad1); + volatile unchar esp_tcmed; /* rw Mid bits of the transfer count 0x04 */ + EREGS_PAD(fdpad); + volatile unchar esp_fdata; /* rw FIFO data bits 0x08 */ + EREGS_PAD(cbpad); + volatile unchar esp_cmnd; /* rw SCSI command bits 0x0c */ + EREGS_PAD(stpad); + volatile unchar esp_status; /* ro ESP status register 0x10 */ +#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */ + EREGS_PAD(irqpd); + volatile unchar esp_intrpt; /* ro Kind of interrupt 0x14 */ +#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */ + EREGS_PAD(sspad); + volatile unchar esp_sstep; /* ro Sequence step register 0x18 */ +#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */ + EREGS_PAD(ffpad); + volatile unchar esp_fflags; /* ro Bits of current FIFO info 0x1c */ +#define esp_soff esp_fflags /* wo Sync offset 0x1c */ + EREGS_PAD(cf1pd); + volatile unchar esp_cfg1; /* rw First configuration register 0x20 */ + EREGS_PAD(cfpad); + volatile unchar esp_cfact; /* wo Clock conversion factor 0x24 */ + EREGS_PAD(ctpad); + volatile unchar esp_ctest; /* wo Chip test register 0x28 */ + EREGS_PAD(cf2pd); + volatile unchar esp_cfg2; /* rw Second configuration register 0x2c */ + EREGS_PAD(cf3pd); + + /* The following is only found on the 53C9X series SCSI chips */ + volatile unchar esp_cfg3; /* rw Third configuration register 0x30 */ + EREGS_PAD(cf4pd); + volatile unchar esp_cfg4; /* rw Fourth configuration register 0x34 */ + EREGS_PAD(thpd); + /* The following is found on all chips except the NCR53C90 (ESP100) */ + volatile unchar esp_tchi; /* rw High bits of transfer count 0x38 */ +#define esp_uid esp_tchi /* ro Unique ID code 0x38 */ + EREGS_PAD(fgpad); + volatile unchar esp_fgrnd; /* rw Data base for fifo 0x3c */ +}; + +#else /* MULTIPLE_PAD_SIZES */ + +#define esp_write(__reg, __val) (*(__reg) = (__val)) +#define esp_read(__reg) (*(__reg)) + +struct ESP_regs { + unsigned char io_addr[64]; /* dummy */ + /* Access Description Offset */ +#define esp_tclow io_addr /* rw Low bits of the transfer count 0x00 */ +#define esp_tcmed io_addr + (1<<(esp->shift)) /* rw Mid bits of the transfer count 0x04 */ +#define esp_fdata io_addr + (2<<(esp->shift)) /* rw FIFO data bits 0x08 */ +#define esp_cmnd io_addr + (3<<(esp->shift)) /* rw SCSI command bits 0x0c */ +#define esp_status io_addr + (4<<(esp->shift)) /* ro ESP status register 0x10 */ +#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */ +#define esp_intrpt io_addr + (5<<(esp->shift)) /* ro Kind of interrupt 0x14 */ +#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */ +#define esp_sstep io_addr + (6<<(esp->shift)) /* ro Sequence step register 0x18 */ +#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */ +#define esp_fflags io_addr + (7<<(esp->shift)) /* ro Bits of current FIFO info 0x1c */ +#define esp_soff esp_fflags /* wo Sync offset 0x1c */ +#define esp_cfg1 io_addr + (8<<(esp->shift)) /* rw First configuration register 0x20 */ +#define esp_cfact io_addr + (9<<(esp->shift)) /* wo Clock conversion factor 0x24 */ +#define esp_ctest io_addr + (10<<(esp->shift)) /* wo Chip test register 0x28 */ +#define esp_cfg2 io_addr + (11<<(esp->shift)) /* rw Second configuration register 0x2c */ + + /* The following is only found on the 53C9X series SCSI chips */ +#define esp_cfg3 io_addr + (12<<(esp->shift)) /* rw Third configuration register 0x30 */ +#define esp_cfg4 io_addr + (13<<(esp->shift)) /* rw Fourth configuration register 0x34 */ + + /* The following is found on all chips except the NCR53C90 (ESP100) */ +#define esp_tchi io_addr + (14<<(esp->shift)) /* rw High bits of transfer count 0x38 */ +#define esp_uid esp_tchi /* ro Unique ID code 0x38 */ +#define esp_fgrnd io_addr + (15<<(esp->shift)) /* rw Data base for fifo 0x3c */ +}; + +#endif + +#else /* !defined(__i386__) && !defined(__x86_64__) */ + +#define esp_write(__reg, __val) outb((__val), (__reg)) +#define esp_read(__reg) inb((__reg)) + +struct ESP_regs { + unsigned int io_addr; + /* Access Description Offset */ +#define esp_tclow io_addr /* rw Low bits of the transfer count 0x00 */ +#define esp_tcmed io_addr + 1 /* rw Mid bits of the transfer count 0x04 */ +#define esp_fdata io_addr + 2 /* rw FIFO data bits 0x08 */ +#define esp_cmnd io_addr + 3 /* rw SCSI command bits 0x0c */ +#define esp_status io_addr + 4 /* ro ESP status register 0x10 */ +#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */ +#define esp_intrpt io_addr + 5 /* ro Kind of interrupt 0x14 */ +#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */ +#define esp_sstep io_addr + 6 /* ro Sequence step register 0x18 */ +#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */ +#define esp_fflags io_addr + 7 /* ro Bits of current FIFO info 0x1c */ +#define esp_soff esp_fflags /* wo Sync offset 0x1c */ +#define esp_cfg1 io_addr + 8 /* rw First configuration register 0x20 */ +#define esp_cfact io_addr + 9 /* wo Clock conversion factor 0x24 */ +#define esp_ctest io_addr + 10 /* wo Chip test register 0x28 */ +#define esp_cfg2 io_addr + 11 /* rw Second configuration register 0x2c */ + + /* The following is only found on the 53C9X series SCSI chips */ +#define esp_cfg3 io_addr + 12 /* rw Third configuration register 0x30 */ +#define esp_cfg4 io_addr + 13 /* rw Fourth configuration register 0x34 */ + + /* The following is found on all chips except the NCR53C90 (ESP100) */ +#define esp_tchi io_addr + 14 /* rw High bits of transfer count 0x38 */ +#define esp_uid esp_tchi /* ro Unique ID code 0x38 */ +#define esp_fgrnd io_addr + 15 /* rw Data base for fifo 0x3c */ +}; + +#endif /* !defined(__i386__) && !defined(__x86_64__) */ + +/* Various revisions of the ESP board. */ +enum esp_rev { + esp100 = 0x00, /* NCR53C90 - very broken */ + esp100a = 0x01, /* NCR53C90A */ + esp236 = 0x02, + fas236 = 0x03, + fas100a = 0x04, + fast = 0x05, + fas366 = 0x06, + fas216 = 0x07, + fsc = 0x08, /* SYM53C94-2 */ + espunknown = 0x09 +}; + +/* We allocate one of these for each scsi device and attach it to + * SDptr->hostdata for use in the driver + */ +struct esp_device { + unsigned char sync_min_period; + unsigned char sync_max_offset; + unsigned sync:1; + unsigned wide:1; + unsigned disconnect:1; +}; + +/* We get one of these for each ESP probed. */ +struct NCR_ESP { + struct NCR_ESP *next; /* Next ESP on probed or NULL */ + struct ESP_regs *eregs; /* All esp registers */ + int dma; /* Who I do transfers with. */ + void *dregs; /* And his registers. */ + struct Scsi_Host *ehost; /* Backpointer to SCSI Host */ + + void *edev; /* Pointer to controller base/SBus */ + int esp_id; /* Unique per-ESP ID number */ + + /* ESP Configuration Registers */ + unsigned char config1; /* Copy of the 1st config register */ + unsigned char config2; /* Copy of the 2nd config register */ + unsigned char config3[16]; /* Copy of the 3rd config register */ + + /* The current command we are sending to the ESP chip. This esp_command + * ptr needs to be mapped in DVMA area so we can send commands and read + * from the ESP fifo without burning precious CPU cycles. Programmed I/O + * sucks when we have the DVMA to do it for us. The ESP is stupid and will + * only send out 6, 10, and 12 byte SCSI commands, others we need to send + * one byte at a time. esp_slowcmd being set says that we are doing one + * of the command types ESP doesn't understand, esp_scmdp keeps track of + * which byte we are sending, esp_scmdleft says how many bytes to go. + */ + volatile unchar *esp_command; /* Location of command (CPU view) */ + __u32 esp_command_dvma; /* Location of command (DVMA view) */ + unsigned char esp_clen; /* Length of this command */ + unsigned char esp_slowcmd; + unsigned char *esp_scmdp; + unsigned char esp_scmdleft; + + /* The following are used to determine the cause of an IRQ. Upon every + * IRQ entry we synchronize these with the hardware registers. + */ + unchar ireg; /* Copy of ESP interrupt register */ + unchar sreg; /* Same for ESP status register */ + unchar seqreg; /* The ESP sequence register */ + + /* The following is set when a premature interrupt condition is detected + * in some FAS revisions. + */ + unchar fas_premature_intr_workaround; + + /* To save register writes to the ESP, which can be expensive, we + * keep track of the previous value that various registers had for + * the last target we connected to. If they are the same for the + * current target, we skip the register writes as they are not needed. + */ + unchar prev_soff, prev_stp, prev_cfg3; + + /* For each target we keep track of save/restore data + * pointer information. This needs to be updated majorly + * when we add support for tagged queueing. -DaveM + */ + struct esp_pointers { + char *saved_ptr; + struct scatterlist *saved_buffer; + int saved_this_residual; + int saved_buffers_residual; + } data_pointers[16] /*XXX [MAX_TAGS_PER_TARGET]*/; + + /* Clock periods, frequencies, synchronization, etc. */ + unsigned int cfreq; /* Clock frequency in HZ */ + unsigned int cfact; /* Clock conversion factor */ + unsigned int ccycle; /* One ESP clock cycle */ + unsigned int ctick; /* One ESP clock time */ + unsigned int radelay; /* FAST chip req/ack delay */ + unsigned int neg_defp; /* Default negotiation period */ + unsigned int sync_defp; /* Default sync transfer period */ + unsigned int max_period; /* longest our period can be */ + unsigned int min_period; /* shortest period we can withstand */ + /* For slow to medium speed input clock rates we shoot for 5mb/s, + * but for high input clock rates we try to do 10mb/s although I + * don't think a transfer can even run that fast with an ESP even + * with DMA2 scatter gather pipelining. + */ +#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */ +#define SYNC_DEFP_FAST 0x19 /* 10mb/s */ + + unsigned int snip; /* Sync. negotiation in progress */ + unsigned int wnip; /* WIDE negotiation in progress */ + unsigned int targets_present; /* targets spoken to before */ + + int current_transfer_size; /* Set at beginning of data dma */ + + unchar espcmdlog[32]; /* Log of current esp cmds sent. */ + unchar espcmdent; /* Current entry in esp cmd log. */ + + /* Misc. info about this ESP */ + enum esp_rev erev; /* ESP revision */ + int irq; /* IRQ for this ESP */ + int scsi_id; /* Who am I as initiator? */ + int scsi_id_mask; /* Bitmask of 'me'. */ + int diff; /* Differential SCSI bus? */ + int slot; /* Slot the adapter occupies */ + + /* Our command queues, only one cmd lives in the current_SC queue. */ + Scsi_Cmnd *issue_SC; /* Commands to be issued */ + Scsi_Cmnd *current_SC; /* Who is currently working the bus */ + Scsi_Cmnd *disconnected_SC; /* Commands disconnected from the bus */ + + /* Message goo */ + unchar cur_msgout[16]; + unchar cur_msgin[16]; + unchar prevmsgout, prevmsgin; + unchar msgout_len, msgin_len; + unchar msgout_ctr, msgin_ctr; + + /* States that we cannot keep in the per cmd structure because they + * cannot be assosciated with any specific command. + */ + unchar resetting_bus; + wait_queue_head_t reset_queue; + + unchar do_pio_cmds; /* Do command transfer with pio */ + + /* How much bits do we have to shift the registers */ + unsigned char shift; + + /* Functions handling DMA + */ + /* Required functions */ + int (*dma_bytes_sent)(struct NCR_ESP *, int); + int (*dma_can_transfer)(struct NCR_ESP *, Scsi_Cmnd *); + void (*dma_dump_state)(struct NCR_ESP *); + void (*dma_init_read)(struct NCR_ESP *, __u32, int); + void (*dma_init_write)(struct NCR_ESP *, __u32, int); + void (*dma_ints_off)(struct NCR_ESP *); + void (*dma_ints_on)(struct NCR_ESP *); + int (*dma_irq_p)(struct NCR_ESP *); + int (*dma_ports_p)(struct NCR_ESP *); + void (*dma_setup)(struct NCR_ESP *, __u32, int, int); + + /* Optional functions (i.e. may be initialized to 0) */ + void (*dma_barrier)(struct NCR_ESP *); + void (*dma_drain)(struct NCR_ESP *); + void (*dma_invalidate)(struct NCR_ESP *); + void (*dma_irq_entry)(struct NCR_ESP *); + void (*dma_irq_exit)(struct NCR_ESP *); + void (*dma_led_off)(struct NCR_ESP *); + void (*dma_led_on)(struct NCR_ESP *); + void (*dma_poll)(struct NCR_ESP *, unsigned char *); + void (*dma_reset)(struct NCR_ESP *); + + /* Optional virtual DMA functions */ + void (*dma_mmu_get_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *); + void (*dma_mmu_get_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *); + void (*dma_mmu_release_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *); + void (*dma_mmu_release_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *); + void (*dma_advance_sg)(Scsi_Cmnd *); +}; + +/* Bitfield meanings for the above registers. */ + +/* ESP config reg 1, read-write, found on all ESP chips */ +#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */ +#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */ +#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */ +#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */ +#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */ +#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */ + +/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236+fsc chips */ +#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236,fsc) */ +#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236,fsc) */ +#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */ +#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tmode only) */ +#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */ +#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */ +#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236,fsc) */ +#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,esp216,fsc) */ +#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (esp236) */ +#define ESP_CONFIG2_RFB 0x80 /* Reserve FIFO byte (fsc) */ +#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */ + +/* ESP config register 3 read-write, found only esp236+fas236+fas100a+fsc chips */ +#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/fas366) */ +#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236/fsc) */ +#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a) */ +#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236/fsc) */ +#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a) */ +#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236/fsc) */ +#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a) */ +#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236/fsc) */ +#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a) */ +#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236/fsc) */ +#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236/fsc) */ +#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236/fsc) */ +#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236/fsc) */ + +/* ESP config register 4 read-write, found only on fsc chips */ +#define ESP_CONFIG4_BBTE 0x01 /* Back-to-Back transfer enable */ +#define ESP_CONFIG4_TEST 0x02 /* Transfer counter test mode */ +#define ESP_CONFIG4_EAN 0x04 /* Enable Active Negotiation */ + +/* ESP command register read-write */ +/* Group 1 commands: These may be sent at any point in time to the ESP + * chip. None of them can generate interrupts 'cept + * the "SCSI bus reset" command if you have not disabled + * SCSI reset interrupts in the config1 ESP register. + */ +#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */ +#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */ +#define ESP_CMD_RC 0x02 /* Chip reset */ +#define ESP_CMD_RS 0x03 /* SCSI bus reset */ + +/* Group 2 commands: ESP must be an initiator and connected to a target + * for these commands to work. + */ +#define ESP_CMD_TI 0x10 /* Transfer Information */ +#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */ +#define ESP_CMD_MOK 0x12 /* Message okie-dokie */ +#define ESP_CMD_TPAD 0x18 /* Transfer Pad */ +#define ESP_CMD_SATN 0x1a /* Set ATN */ +#define ESP_CMD_RATN 0x1b /* De-assert ATN */ + +/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected + * to a target as the initiator for these commands to work. + */ +#define ESP_CMD_SMSG 0x20 /* Send message */ +#define ESP_CMD_SSTAT 0x21 /* Send status */ +#define ESP_CMD_SDATA 0x22 /* Send data */ +#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */ +#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */ +#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */ +#define ESP_CMD_DCNCT 0x27 /* Disconnect */ +#define ESP_CMD_RMSG 0x28 /* Receive Message */ +#define ESP_CMD_RCMD 0x29 /* Receive Command */ +#define ESP_CMD_RDATA 0x2a /* Receive Data */ +#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */ + +/* Group 4 commands: The ESP must be in the disconnected state and must + * not be connected to any targets as initiator for + * these commands to work. + */ +#define ESP_CMD_RSEL 0x40 /* Reselect */ +#define ESP_CMD_SEL 0x41 /* Select w/o ATN */ +#define ESP_CMD_SELA 0x42 /* Select w/ATN */ +#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */ +#define ESP_CMD_ESEL 0x44 /* Enable selection */ +#define ESP_CMD_DSEL 0x45 /* Disable selections */ +#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */ +#define ESP_CMD_RSEL3 0x47 /* Reselect3 */ + +/* This bit enables the ESP's DMA */ +#define ESP_CMD_DMA 0x80 /* Do DMA? */ + +/* ESP status register read-only */ +#define ESP_STAT_PIO 0x01 /* IO phase bit */ +#define ESP_STAT_PCD 0x02 /* CD phase bit */ +#define ESP_STAT_PMSG 0x04 /* MSG phase bit */ +#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */ +#define ESP_STAT_TDONE 0x08 /* Transfer Completed */ +#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */ +#define ESP_STAT_PERR 0x20 /* Parity error */ +#define ESP_STAT_SPAM 0x40 /* Real bad error */ +/* This indicates the 'interrupt pending' condition, it is a reserved + * bit on old revs of the ESP (ESP100, ESP100A, FAS100A). + */ +#define ESP_STAT_INTR 0x80 /* Interrupt */ + +/* The status register can be masked with ESP_STAT_PMASK and compared + * with the following values to determine the current phase the ESP + * (at least thinks it) is in. For our purposes we also add our own + * software 'done' bit for our phase management engine. + */ +#define ESP_DOP (0) /* Data Out */ +#define ESP_DIP (ESP_STAT_PIO) /* Data In */ +#define ESP_CMDP (ESP_STAT_PCD) /* Command */ +#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */ +#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */ +#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */ + +/* ESP interrupt register read-only */ +#define ESP_INTR_S 0x01 /* Select w/o ATN */ +#define ESP_INTR_SATN 0x02 /* Select w/ATN */ +#define ESP_INTR_RSEL 0x04 /* Reselected */ +#define ESP_INTR_FDONE 0x08 /* Function done */ +#define ESP_INTR_BSERV 0x10 /* Bus service */ +#define ESP_INTR_DC 0x20 /* Disconnect */ +#define ESP_INTR_IC 0x40 /* Illegal command given */ +#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */ + +/* Interrupt status macros */ +#define ESP_SRESET_IRQ(esp) ((esp)->intreg & (ESP_INTR_SR)) +#define ESP_ILLCMD_IRQ(esp) ((esp)->intreg & (ESP_INTR_IC)) +#define ESP_SELECT_WITH_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_SATN)) +#define ESP_SELECT_WITHOUT_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_S)) +#define ESP_SELECTION_IRQ(esp) ((ESP_SELECT_WITH_ATN_IRQ(esp)) || \ + (ESP_SELECT_WITHOUT_ATN_IRQ(esp))) +#define ESP_RESELECTION_IRQ(esp) ((esp)->intreg & (ESP_INTR_RSEL)) + +/* ESP sequence step register read-only */ +#define ESP_STEP_VBITS 0x07 /* Valid bits */ +#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */ +#define ESP_STEP_SID 0x01 /* One msg byte sent */ +#define ESP_STEP_NCMD 0x02 /* Was not in command phase */ +#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd + * bytes to be lost + */ +#define ESP_STEP_FINI4 0x04 /* Command was sent ok */ + +/* Ho hum, some ESP's set the step register to this as well... */ +#define ESP_STEP_FINI5 0x05 +#define ESP_STEP_FINI6 0x06 +#define ESP_STEP_FINI7 0x07 +#define ESP_STEP_SOM 0x08 /* Synchronous Offset Max */ + +/* ESP chip-test register read-write */ +#define ESP_TEST_TARG 0x01 /* Target test mode */ +#define ESP_TEST_INI 0x02 /* Initiator test mode */ +#define ESP_TEST_TS 0x04 /* Tristate test mode */ + +/* ESP unique ID register read-only, found on fas236+fas100a+fsc only */ +#define ESP_UID_F100A 0x00 /* FAS100A */ +#define ESP_UID_F236 0x02 /* FAS236 */ +#define ESP_UID_FSC 0xa2 /* NCR53CF9x-2 */ +#define ESP_UID_REV 0x07 /* ESP revision */ +#define ESP_UID_FAM 0xf8 /* ESP family */ + +/* ESP fifo flags register read-only */ +/* Note that the following implies a 16 byte FIFO on the ESP. */ +#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */ +#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100,fsc) */ +#define ESP_FF_SSTEP 0xe0 /* Sequence step */ + +/* ESP clock conversion factor register write-only */ +#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */ +#define ESP_CCF_NEVER 0x01 /* Set it to this and die */ +#define ESP_CCF_F2 0x02 /* 10MHz */ +#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */ +#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */ +#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */ +#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */ +#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */ + +#define ESP_BUS_TIMEOUT 275 /* In milli-seconds */ +#define ESP_TIMEO_CONST 8192 +#define FSC_TIMEO_CONST 7668 +#define ESP_NEG_DEFP(mhz, cfact) \ + ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact))) +#define FSC_NEG_DEFP(mhz, cfact) \ + ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (7668 * (cfact))) +#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000)) +#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000)) + + +/* UGLY, UGLY, UGLY! */ +extern int nesps, esps_in_use, esps_running; + +/* For our interrupt engine. */ +#define for_each_esp(esp) \ + for((esp) = espchain; (esp); (esp) = (esp)->next) + + +/* External functions */ +extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs); +extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *, int); +extern void esp_deallocate(struct NCR_ESP *); +extern void esp_release(void); +extern void esp_initialize(struct NCR_ESP *); +extern irqreturn_t esp_intr(int, void *); +extern const char *esp_info(struct Scsi_Host *); +extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int esp_abort(Scsi_Cmnd *); +extern int esp_reset(Scsi_Cmnd *); +extern int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, + int inout); +extern int esp_slave_alloc(struct scsi_device *); +extern void esp_slave_destroy(struct scsi_device *); +#endif /* !(NCR53C9X_H) */ diff --git a/trunk/drivers/scsi/aacraid/aachba.c b/trunk/drivers/scsi/aacraid/aachba.c index bfd0e64964ac..d7235f42cf5f 100644 --- a/trunk/drivers/scsi/aacraid/aachba.c +++ b/trunk/drivers/scsi/aacraid/aachba.c @@ -859,31 +859,44 @@ static int setinqserial(struct aac_dev *dev, void *data, int cid) le32_to_cpu(dev->adapter_info.serial[0]), cid); } -static inline void set_sense(struct sense_data *sense_data, u8 sense_key, - u8 sense_code, u8 a_sense_code, u8 bit_pointer, u16 field_pointer) +static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code, + u8 a_sense_code, u8 incorrect_length, + u8 bit_pointer, u16 field_pointer, + u32 residue) { - u8 *sense_buf = (u8 *)sense_data; - /* Sense data valid, err code 70h */ - sense_buf[0] = 0x70; /* No info field */ + sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */ sense_buf[1] = 0; /* Segment number, always zero */ - sense_buf[2] = sense_key; /* Sense key */ + if (incorrect_length) { + sense_buf[2] = sense_key | 0x20;/* Set ILI bit | sense key */ + sense_buf[3] = BYTE3(residue); + sense_buf[4] = BYTE2(residue); + sense_buf[5] = BYTE1(residue); + sense_buf[6] = BYTE0(residue); + } else + sense_buf[2] = sense_key; /* Sense key */ + + if (sense_key == ILLEGAL_REQUEST) + sense_buf[7] = 10; /* Additional sense length */ + else + sense_buf[7] = 6; /* Additional sense length */ sense_buf[12] = sense_code; /* Additional sense code */ sense_buf[13] = a_sense_code; /* Additional sense code qualifier */ - if (sense_key == ILLEGAL_REQUEST) { - sense_buf[7] = 10; /* Additional sense length */ + sense_buf[15] = 0; - sense_buf[15] = bit_pointer; + if (sense_code == SENCODE_INVALID_PARAM_FIELD) + sense_buf[15] = 0x80;/* Std sense key specific field */ /* Illegal parameter is in the parameter block */ + if (sense_code == SENCODE_INVALID_CDB_FIELD) - sense_buf[15] |= 0xc0;/* Std sense key specific field */ + sense_buf[15] = 0xc0;/* Std sense key specific field */ /* Illegal parameter is in the CDB block */ + sense_buf[15] |= bit_pointer; sense_buf[16] = field_pointer >> 8; /* MSB */ sense_buf[17] = field_pointer; /* LSB */ - } else - sense_buf[7] = 6; /* Additional sense length */ + } } static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) @@ -893,9 +906,11 @@ static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); + set_sense((u8 *) &dev->fsa_dev[cid].sense_data, + HARDWARE_ERROR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); @@ -1505,9 +1520,11 @@ static void io_callback(void *context, struct fib * fibptr) le32_to_cpu(readreply->status)); #endif scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); + set_sense((u8 *) &dev->fsa_dev[cid].sense_data, + HARDWARE_ERROR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); @@ -1716,9 +1733,11 @@ static void synchronize_callback(void *context, struct fib *fibptr) le32_to_cpu(synchronizereply->status)); cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); + set_sense((u8 *)&dev->fsa_dev[cid].sense_data, + HARDWARE_ERROR, + SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, + 0, 0); memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); @@ -1926,9 +1945,10 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) { dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0])); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, - ASENCODE_INVALID_COMMAND, 0, 0); + set_sense((u8 *) &dev->fsa_dev[cid].sense_data, + ILLEGAL_REQUEST, + SENCODE_INVALID_COMMAND, + ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); @@ -1975,9 +1995,10 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - ILLEGAL_REQUEST, SENCODE_INVALID_CDB_FIELD, - ASENCODE_NO_SENSE, 7, 2); + set_sense((u8 *) &dev->fsa_dev[cid].sense_data, + ILLEGAL_REQUEST, + SENCODE_INVALID_CDB_FIELD, + ASENCODE_NO_SENSE, 0, 7, 2, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, @@ -2233,9 +2254,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) */ dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0])); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, - ASENCODE_INVALID_COMMAND, 0, 0); + set_sense((u8 *) &dev->fsa_dev[cid].sense_data, + ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, + ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), diff --git a/trunk/drivers/scsi/aacraid/commctrl.c b/trunk/drivers/scsi/aacraid/commctrl.c index abef05146d75..f8afa358b6b6 100644 --- a/trunk/drivers/scsi/aacraid/commctrl.c +++ b/trunk/drivers/scsi/aacraid/commctrl.c @@ -243,7 +243,6 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) * Search the list of AdapterFibContext addresses on the adapter * to be sure this is a valid address */ - spin_lock_irqsave(&dev->fib_lock, flags); entry = dev->fib_list.next; fibctx = NULL; @@ -252,25 +251,24 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) /* * Extract the AdapterFibContext from the Input parameters. */ - if (fibctx->unique == f.fibctx) { /* We found a winner */ + if (fibctx->unique == f.fibctx) { /* We found a winner */ break; } entry = entry->next; fibctx = NULL; } if (!fibctx) { - spin_unlock_irqrestore(&dev->fib_lock, flags); dprintk ((KERN_INFO "Fib Context not found\n")); return -EINVAL; } if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || (fibctx->size != sizeof(struct aac_fib_context))) { - spin_unlock_irqrestore(&dev->fib_lock, flags); dprintk ((KERN_INFO "Fib Context corrupt?\n")); return -EINVAL; } status = 0; + spin_lock_irqsave(&dev->fib_lock, flags); /* * If there are no fibs to send back, then either wait or return * -EAGAIN @@ -416,8 +414,8 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) * @arg: ioctl arguments * * This routine returns the driver version. - * Under Linux, there have been no version incompatibilities, so this is - * simple! + * Under Linux, there have been no version incompatibilities, so this is + * simple! */ static int check_revision(struct aac_dev *dev, void __user *arg) @@ -465,7 +463,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) u32 data_dir; void __user *sg_user[32]; void *sg_list[32]; - u32 sg_indx = 0; + u32 sg_indx = 0; u32 byte_count = 0; u32 actual_fibsize64, actual_fibsize = 0; int i; @@ -519,11 +517,11 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) // Fix up srb for endian and force some values srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this - srbcmd->channel = cpu_to_le32(user_srbcmd->channel); + srbcmd->channel = cpu_to_le32(user_srbcmd->channel); srbcmd->id = cpu_to_le32(user_srbcmd->id); - srbcmd->lun = cpu_to_le32(user_srbcmd->lun); - srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); - srbcmd->flags = cpu_to_le32(flags); + srbcmd->lun = cpu_to_le32(user_srbcmd->lun); + srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); + srbcmd->flags = cpu_to_le32(flags); srbcmd->retry_limit = 0; // Obsolete parameter srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size); memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb)); @@ -788,9 +786,9 @@ static int aac_get_pci_info(struct aac_dev* dev, void __user *arg) pci_info.bus = dev->pdev->bus->number; pci_info.slot = PCI_SLOT(dev->pdev->devfn); - if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { - dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); - return -EFAULT; + if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { + dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); + return -EFAULT; } return 0; } diff --git a/trunk/drivers/scsi/aacraid/linit.c b/trunk/drivers/scsi/aacraid/linit.c index e80d2a0c46af..fb0886140dd7 100644 --- a/trunk/drivers/scsi/aacraid/linit.c +++ b/trunk/drivers/scsi/aacraid/linit.c @@ -1130,29 +1130,31 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, if (error < 0) goto out_deinit; + if (!(aac->adapter_info.options & AAC_OPT_NEW_COMM)) { + error = pci_set_dma_max_seg_size(pdev, 65536); + if (error) + goto out_deinit; + } + /* * Lets override negotiations and drop the maximum SG limit to 34 */ if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) && - (shost->sg_tablesize > 34)) { - shost->sg_tablesize = 34; - shost->max_sectors = (shost->sg_tablesize * 8) + 112; + (aac->scsi_host_ptr->sg_tablesize > 34)) { + aac->scsi_host_ptr->sg_tablesize = 34; + aac->scsi_host_ptr->max_sectors + = (aac->scsi_host_ptr->sg_tablesize * 8) + 112; } if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) && - (shost->sg_tablesize > 17)) { - shost->sg_tablesize = 17; - shost->max_sectors = (shost->sg_tablesize * 8) + 112; + (aac->scsi_host_ptr->sg_tablesize > 17)) { + aac->scsi_host_ptr->sg_tablesize = 17; + aac->scsi_host_ptr->max_sectors + = (aac->scsi_host_ptr->sg_tablesize * 8) + 112; } - error = pci_set_dma_max_seg_size(pdev, - (aac->adapter_info.options & AAC_OPT_NEW_COMM) ? - (shost->max_sectors << 9) : 65536); - if (error) - goto out_deinit; - /* - * Firmware printf works only with older firmware. + * Firware printf works only with older firmware. */ if (aac_drivers[index].quirks & AAC_QUIRK_34SG) aac->printf_enabled = 1; diff --git a/trunk/drivers/scsi/advansys.c b/trunk/drivers/scsi/advansys.c index ccef891d642f..374ed025dc5a 100644 --- a/trunk/drivers/scsi/advansys.c +++ b/trunk/drivers/scsi/advansys.c @@ -12261,7 +12261,7 @@ static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr) /* * Write the EEPROM from 'cfg_buf'. */ -static void __devinit +void __devinit AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) { ushort *wbuf; @@ -12328,7 +12328,7 @@ AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) /* * Write the EEPROM from 'cfg_buf'. */ -static void __devinit +void __devinit AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) { ushort *wbuf; @@ -12395,7 +12395,7 @@ AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) /* * Write the EEPROM from 'cfg_buf'. */ -static void __devinit +void __devinit AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf) { ushort *wbuf; diff --git a/trunk/drivers/scsi/arcmsr/arcmsr.h b/trunk/drivers/scsi/arcmsr/arcmsr.h index 57786502e3ec..a67e29f83ae5 100644 --- a/trunk/drivers/scsi/arcmsr/arcmsr.h +++ b/trunk/drivers/scsi/arcmsr/arcmsr.h @@ -48,7 +48,7 @@ struct class_device_attribute; /*The limit of outstanding scsi command that firmware can handle*/ #define ARCMSR_MAX_OUTSTANDING_CMD 256 #define ARCMSR_MAX_FREECCB_NUM 320 -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/12/24" +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/08/30" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 @@ -248,7 +248,6 @@ struct FIRMWARE_INFO #define ARCMSR_MESSAGE_START_BGRB 0x00060008 #define ARCMSR_MESSAGE_START_DRIVER_MODE 0x000E0008 #define ARCMSR_MESSAGE_SET_POST_WINDOW 0x000F0008 -#define ARCMSR_MESSAGE_ACTIVE_EOI_MODE 0x00100008 /* ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK */ #define ARCMSR_MESSAGE_FIRMWARE_OK 0x80000000 /* ioctl transfer */ @@ -257,7 +256,6 @@ struct FIRMWARE_INFO #define ARCMSR_DRV2IOP_DATA_READ_OK 0x00000002 #define ARCMSR_DRV2IOP_CDB_POSTED 0x00000004 #define ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED 0x00000008 -#define ARCMSR_DRV2IOP_END_OF_INTERRUPT 0x00000010 /* data tunnel buffer between user space program and its firmware */ /* user space data to iop 128bytes */ diff --git a/trunk/drivers/scsi/arcmsr/arcmsr_hba.c b/trunk/drivers/scsi/arcmsr/arcmsr_hba.c index 4f9ff32cfed0..f4a202e8df26 100644 --- a/trunk/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/trunk/drivers/scsi/arcmsr/arcmsr_hba.c @@ -315,6 +315,9 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); } + reg = (struct MessageUnit_B *)(dma_coherent + + ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock)); + dma_addr = dma_coherent_handle; ccb_tmp = (struct CommandControlBlock *)dma_coherent; for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { @@ -368,8 +371,8 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) out: dma_free_coherent(&acb->pdev->dev, - (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 + - sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle); + ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20, + acb->dma_coherent, acb->dma_coherent_handle); return -ENOMEM; } @@ -506,7 +509,6 @@ static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN , reg->iop2drv_doorbell_reg); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg); return 0x00; } msleep(10); @@ -746,7 +748,6 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t fla , ccb->startdone , atomic_read(&acb->ccboutstandingcount)); } - else arcmsr_report_ccb_state(acb, ccb, flag_ccb); } @@ -885,7 +886,7 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \ } } -static int arcmsr_build_ccb(struct AdapterControlBlock *acb, +static void arcmsr_build_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd) { struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; @@ -905,8 +906,6 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb, memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len); nseg = scsi_dma_map(pcmd); - if (nseg > ARCMSR_MAX_SG_ENTRIES) - return FAILED; BUG_ON(nseg < 0); if (nseg) { @@ -947,7 +946,6 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb, arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE; ccb->ccb_flags |= CCB_FLAG_WRITE; } - return SUCCESS; } static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) @@ -1038,22 +1036,18 @@ static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { iounmap(acb->pmuA); - dma_free_coherent(&acb->pdev->dev, - ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, - acb->dma_coherent, - acb->dma_coherent_handle); break; } case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; iounmap(reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL); iounmap(reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER); - dma_free_coherent(&acb->pdev->dev, - (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 + - sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle); } } - + dma_free_coherent(&acb->pdev->dev, + ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, + acb->dma_coherent, + acb->dma_coherent_handle); } void arcmsr_iop_message_read(struct AdapterControlBlock *acb) @@ -1279,9 +1273,7 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) return 1; writel(~outbound_doorbell, reg->iop2drv_doorbell_reg); - /*in case the last action of doorbell interrupt clearance is cached, this action can push HW to write down the clear bit*/ - readl(reg->iop2drv_doorbell_reg); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg); + if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { arcmsr_iop2drv_data_wrote_handle(acb); } @@ -1388,13 +1380,12 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \ case ARCMSR_MESSAGE_READ_RQBUFFER: { unsigned long *ver_addr; + dma_addr_t buf_handle; uint8_t *pQbuffer, *ptmpQbuffer; int32_t allxfer_len = 0; - void *tmp; - tmp = kmalloc(1032, GFP_KERNEL|GFP_DMA); - ver_addr = (unsigned long *)tmp; - if (!tmp) { + ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); + if (!ver_addr) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } @@ -1430,19 +1421,18 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \ memcpy(pcmdmessagefld->messagedatabuffer, (uint8_t *)ver_addr, allxfer_len); pcmdmessagefld->cmdmessage.Length = allxfer_len; pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; - kfree(tmp); + pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); } break; case ARCMSR_MESSAGE_WRITE_WQBUFFER: { unsigned long *ver_addr; + dma_addr_t buf_handle; int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; uint8_t *pQbuffer, *ptmpuserbuffer; - void *tmp; - tmp = kmalloc(1032, GFP_KERNEL|GFP_DMA); - ver_addr = (unsigned long *)tmp; - if (!tmp) { + ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); + if (!ver_addr) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } @@ -1492,7 +1482,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \ retvalue = ARCMSR_MESSAGE_FAIL; } } - kfree(tmp); + pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); } break; @@ -1692,11 +1682,8 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd, ccb = arcmsr_get_freeccb(acb); if (!ccb) return SCSI_MLQUEUE_HOST_BUSY; - if ( arcmsr_build_ccb( acb, ccb, cmd ) == FAILED ) { - cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1); - cmd->scsi_done(cmd); - return 0; - } + + arcmsr_build_ccb(acb, ccb, cmd); arcmsr_post_ccb(acb, ccb); return 0; } @@ -1857,7 +1844,7 @@ static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, } } -static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, +static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, \ struct CommandControlBlock *poll_ccb) { struct MessageUnit_B *reg = acb->pmuB; @@ -1891,7 +1878,7 @@ static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, (acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ poll_ccb_done = (ccb == poll_ccb) ? 1:0; if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { - if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { + if (ccb->startdone == ARCMSR_CCB_ABORTED) { printk(KERN_NOTICE "arcmsr%d: \ scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n" ,acb->host->host_no @@ -1914,7 +1901,7 @@ static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, } /*drain reply FIFO*/ } -static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, +static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, \ struct CommandControlBlock *poll_ccb) { switch (acb->adapter_type) { @@ -2039,7 +2026,6 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) do { firmware_state = readl(reg->iop2drv_doorbell_reg); } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg); } break; } @@ -2104,39 +2090,19 @@ static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb) } } -static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb) -{ - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: - return; - case ACB_ADAPTER_TYPE_B: - { - struct MessageUnit_B *reg = acb->pmuB; - writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell_reg); - if(arcmsr_hbb_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT"); - return; - } - } - break; - } - return; -} - static void arcmsr_iop_init(struct AdapterControlBlock *acb) { uint32_t intmask_org; - /* disable all outbound interrupt */ - intmask_org = arcmsr_disable_outbound_ints(acb); arcmsr_wait_firmware_ready(acb); arcmsr_iop_confirm(acb); + /* disable all outbound interrupt */ + intmask_org = arcmsr_disable_outbound_ints(acb); arcmsr_get_firmware_spec(acb); /*start background rebuild*/ arcmsr_start_adapter_bgrb(acb); /* empty doorbell Qbuffer if door bell ringed */ arcmsr_clear_doorbell_queue_buffer(acb); - arcmsr_enable_eoi_mode(acb); /* enable outbound Post Queue,outbound doorbell Interrupt */ arcmsr_enable_outbound_ints(acb, intmask_org); acb->acb_flags |= ACB_F_IOP_INITED; @@ -2309,7 +2275,6 @@ static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev) arcmsr_start_adapter_bgrb(acb); /* empty doorbell Qbuffer if door bell ringed */ arcmsr_clear_doorbell_queue_buffer(acb); - arcmsr_enable_eoi_mode(acb); /* enable outbound Post Queue,outbound doorbell Interrupt */ arcmsr_enable_outbound_ints(acb, intmask_org); acb->acb_flags |= ACB_F_IOP_INITED; diff --git a/trunk/drivers/scsi/arm/acornscsi.c b/trunk/drivers/scsi/arm/acornscsi.c index 3bedf2466bd1..eceacf6d49ea 100644 --- a/trunk/drivers/scsi/arm/acornscsi.c +++ b/trunk/drivers/scsi/arm/acornscsi.c @@ -1790,7 +1790,7 @@ int acornscsi_starttransfer(AS_Host *host) return 0; } - residual = scsi_bufflen(host->SCpnt) - host->scsi.SCp.scsi_xferred; + residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred; sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer); sbic_arm_writenext(host->scsi.io_port, residual >> 16); @@ -2270,7 +2270,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4b: /* -> PHASE_STATUSIN */ case 0x8b: /* -> PHASE_STATUSIN */ /* DATA IN -> STATUS */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - + host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_readstatusbyte(host); @@ -2281,7 +2281,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4e: /* -> PHASE_MSGOUT */ case 0x8e: /* -> PHASE_MSGOUT */ /* DATA IN -> MESSAGE OUT */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - + host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_sendmessage(host); @@ -2291,7 +2291,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4f: /* message in */ case 0x8f: /* message in */ /* DATA IN -> MESSAGE IN */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - + host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ @@ -2319,7 +2319,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4b: /* -> PHASE_STATUSIN */ case 0x8b: /* -> PHASE_STATUSIN */ /* DATA OUT -> STATUS */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - + host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_dma_adjust(host); @@ -2331,7 +2331,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4e: /* -> PHASE_MSGOUT */ case 0x8e: /* -> PHASE_MSGOUT */ /* DATA OUT -> MESSAGE OUT */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - + host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_dma_adjust(host); @@ -2342,7 +2342,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4f: /* message in */ case 0x8f: /* message in */ /* DATA OUT -> MESSAGE IN */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - + host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_dma_adjust(host); diff --git a/trunk/drivers/scsi/arm/scsi.h b/trunk/drivers/scsi/arm/scsi.h index 138a521ba1a8..bb6550e31926 100644 --- a/trunk/drivers/scsi/arm/scsi.h +++ b/trunk/drivers/scsi/arm/scsi.h @@ -18,32 +18,17 @@ * The scatter-gather list handling. This contains all * the yucky stuff that needs to be fixed properly. */ - -/* - * copy_SCp_to_sg() Assumes contiguous allocation at @sg of at-most @max - * entries of uninitialized memory. SCp is from scsi-ml and has a valid - * (possibly chained) sg-list - */ static inline int copy_SCp_to_sg(struct scatterlist *sg, struct scsi_pointer *SCp, int max) { int bufs = SCp->buffers_residual; - /* FIXME: It should be easy for drivers to loop on copy_SCp_to_sg(). - * and to remove this BUG_ON. Use min() in-its-place - */ BUG_ON(bufs + 1 > max); sg_set_buf(sg, SCp->ptr, SCp->this_residual); - if (bufs) { - struct scatterlist *src_sg; - unsigned i; - - for_each_sg(sg_next(SCp->buffer), src_sg, bufs, i) - *(++sg) = *src_sg; - sg_mark_end(sg); - } - + if (bufs) + memcpy(sg + 1, SCp->buffer + 1, + sizeof(struct scatterlist) * bufs); return bufs + 1; } @@ -51,7 +36,7 @@ static inline int next_SCp(struct scsi_pointer *SCp) { int ret = SCp->buffers_residual; if (ret) { - SCp->buffer = sg_next(SCp->buffer); + SCp->buffer++; SCp->buffers_residual--; SCp->ptr = sg_virt(SCp->buffer); SCp->this_residual = SCp->buffer->length; @@ -83,46 +68,46 @@ static inline void init_SCp(struct scsi_cmnd *SCpnt) { memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer)); - if (scsi_bufflen(SCpnt)) { + if (SCpnt->use_sg) { unsigned long len = 0; + int buf; - SCpnt->SCp.buffer = scsi_sglist(SCpnt); - SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1; + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; SCpnt->SCp.ptr = sg_virt(SCpnt->SCp.buffer); SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - SCpnt->SCp.phase = scsi_bufflen(SCpnt); + SCpnt->SCp.phase = SCpnt->request_bufflen; #ifdef BELT_AND_BRACES - { /* - * Calculate correct buffer length. Some commands - * come in with the wrong scsi_bufflen. - */ - struct scatterlist *sg; - unsigned i, sg_count = scsi_sg_count(SCpnt); - - scsi_for_each_sg(SCpnt, sg, sg_count, i) - len += sg->length; - - if (scsi_bufflen(SCpnt) != len) { - printk(KERN_WARNING - "scsi%d.%c: bad request buffer " - "length %d, should be %ld\n", - SCpnt->device->host->host_no, - '0' + SCpnt->device->id, - scsi_bufflen(SCpnt), len); - /* - * FIXME: Totaly naive fixup. We should abort - * with error - */ - SCpnt->SCp.phase = - min_t(unsigned long, len, - scsi_bufflen(SCpnt)); - } - } + /* + * Calculate correct buffer length. Some commands + * come in with the wrong request_bufflen. + */ + for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++) + len += SCpnt->SCp.buffer[buf].length; + + if (SCpnt->request_bufflen != len) + printk(KERN_WARNING "scsi%d.%c: bad request buffer " + "length %d, should be %ld\n", SCpnt->device->host->host_no, + '0' + SCpnt->device->id, SCpnt->request_bufflen, len); + SCpnt->request_bufflen = len; #endif } else { + SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.phase = SCpnt->request_bufflen; + } + + /* + * If the upper SCSI layers pass a buffer, but zero length, + * we aren't interested in the buffer pointer. + */ + if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.ptr) { +#if 0 //def BELT_AND_BRACES + printk(KERN_WARNING "scsi%d.%c: zero length buffer passed for " + "command ", SCpnt->host->host_no, '0' + SCpnt->target); + __scsi_print_command(SCpnt->cmnd); +#endif SCpnt->SCp.ptr = NULL; - SCpnt->SCp.this_residual = 0; - SCpnt->SCp.phase = 0; } } diff --git a/trunk/drivers/scsi/blz1230.c b/trunk/drivers/scsi/blz1230.c new file mode 100644 index 000000000000..23f7c24ab809 --- /dev/null +++ b/trunk/drivers/scsi/blz1230.c @@ -0,0 +1,353 @@ +/* blz1230.c: Driver for Blizzard 1230 SCSI IV Controller. + * + * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) + * + * This driver is based on the CyberStorm driver, hence the occasional + * reference to CyberStorm. + */ + +/* TODO: + * + * 1) Figure out how to make a cleaner merge with the sparc driver with regard + * to the caches and the Sparc MMU mapping. + * 2) Make as few routines required outside the generic driver. A lot of the + * routines in this file used to be inline! + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include + +#include + +#define MKIV 1 + +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define BLZ1230_ESP_ADDR 0x8000 +#define BLZ1230_DMA_ADDR 0x10000 +#define BLZ1230II_ESP_ADDR 0x10000 +#define BLZ1230II_DMA_ADDR 0x10021 + + +/* The Blizzard 1230 DMA interface + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Only two things can be programmed in the Blizzard DMA: + * 1) The data direction is controlled by the status of bit 31 (1 = write) + * 2) The source/dest address (word aligned, shifted one right) in bits 30-0 + * + * Program DMA by first latching the highest byte of the address/direction + * (i.e. bits 31-24 of the long word constructed as described in steps 1+2 + * above). Then write each byte of the address/direction (starting with the + * top byte, working down) to the DMA address register. + * + * Figure out interrupt status by reading the ESP status byte. + */ +struct blz1230_dma_registers { + volatile unsigned char dma_addr; /* DMA address [0x0000] */ + unsigned char dmapad2[0x7fff]; + volatile unsigned char dma_latch; /* DMA latch [0x8000] */ +}; + +struct blz1230II_dma_registers { + volatile unsigned char dma_addr; /* DMA address [0x0000] */ + unsigned char dmapad2[0xf]; + volatile unsigned char dma_latch; /* DMA latch [0x0010] */ +}; + +#define BLZ1230_DMA_WRITE 0x80000000 + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are transferred to the ESP chip + * via PIO. + */ + +/***************************************************************** Detection */ +int __init blz1230_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct zorro_dev *z = NULL; + unsigned long address; + struct ESP_regs *eregs; + unsigned long board; + +#if MKIV +#define REAL_BLZ1230_ID ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260 +#define REAL_BLZ1230_ESP_ADDR BLZ1230_ESP_ADDR +#define REAL_BLZ1230_DMA_ADDR BLZ1230_DMA_ADDR +#else +#define REAL_BLZ1230_ID ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060 +#define REAL_BLZ1230_ESP_ADDR BLZ1230II_ESP_ADDR +#define REAL_BLZ1230_DMA_ADDR BLZ1230II_DMA_ADDR +#endif + + if ((z = zorro_find_device(REAL_BLZ1230_ID, z))) { + board = z->resource.start; + if (request_mem_region(board+REAL_BLZ1230_ESP_ADDR, + sizeof(struct ESP_regs), "NCR53C9x")) { + /* Do some magic to figure out if the blizzard is + * equipped with a SCSI controller + */ + address = ZTWO_VADDR(board); + eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR); + esp = esp_allocate(tpnt, (void *)board + REAL_BLZ1230_ESP_ADDR, + 0); + + esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); + udelay(5); + if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)) + goto err_out; + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = 0; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_led_on = 0; + esp->dma_led_off = 0; + esp->dma_poll = 0; + esp->dma_reset = 0; + + /* SCSI chip speed */ + esp->cfreq = 40000000; + + /* The DMA registers on the Blizzard are mapped + * relative to the device (i.e. in the same Zorro + * I/O block). + */ + esp->dregs = (void *)(address + REAL_BLZ1230_DMA_ADDR); + + /* ESP register base */ + esp->eregs = eregs; + + /* Set the command buffer */ + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); + + esp->irq = IRQ_AMIGA_PORTS; + esp->slot = board+REAL_BLZ1230_ESP_ADDR; + if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, + "Blizzard 1230 SCSI IV", esp->ehost)) + goto err_out; + + /* Figure out our scsi ID on the bus */ + esp->scsi_id = 7; + + /* We don't have a differential SCSI-bus. */ + esp->diff = 0; + + esp_initialize(esp); + + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + return esps_in_use; + } + } + return 0; + + err_out: + scsi_unregister(esp->ehost); + esp_deallocate(esp); + release_mem_region(board+REAL_BLZ1230_ESP_ADDR, + sizeof(struct ESP_regs)); + return 0; +} + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Since the Blizzard DMA is fully dedicated to the ESP chip, + * the number of bytes sent (to the ESP chip) equals the number + * of bytes in the FIFO - there is no buffering in the DMA controller. + * XXXX Do I read this right? It is from host to ESP, right? + */ + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + /* I don't think there's any limit on the Blizzard DMA. So we use what + * the ESP chip can handle (24 bit). + */ + unsigned long sz = sp->SCp.this_residual; + if(sz > 0x1000000) + sz = 0x1000000; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ + ESPLOG(("intreq:<%04x>, intena:<%04x>\n", + amiga_custom.intreqr, amiga_custom.intenar)); +} + +void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) +{ +#if MKIV + struct blz1230_dma_registers *dregs = + (struct blz1230_dma_registers *) (esp->dregs); +#else + struct blz1230II_dma_registers *dregs = + (struct blz1230II_dma_registers *) (esp->dregs); +#endif + + cache_clear(addr, length); + + addr >>= 1; + addr &= ~(BLZ1230_DMA_WRITE); + + /* First set latch */ + dregs->dma_latch = (addr >> 24) & 0xff; + + /* Then pump the address to the DMA address register */ +#if MKIV + dregs->dma_addr = (addr >> 24) & 0xff; +#endif + dregs->dma_addr = (addr >> 16) & 0xff; + dregs->dma_addr = (addr >> 8) & 0xff; + dregs->dma_addr = (addr ) & 0xff; +} + +void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) +{ +#if MKIV + struct blz1230_dma_registers *dregs = + (struct blz1230_dma_registers *) (esp->dregs); +#else + struct blz1230II_dma_registers *dregs = + (struct blz1230II_dma_registers *) (esp->dregs); +#endif + + cache_push(addr, length); + + addr >>= 1; + addr |= BLZ1230_DMA_WRITE; + + /* First set latch */ + dregs->dma_latch = (addr >> 24) & 0xff; + + /* Then pump the address to the DMA address register */ +#if MKIV + dregs->dma_addr = (addr >> 24) & 0xff; +#endif + dregs->dma_addr = (addr >> 16) & 0xff; + dregs->dma_addr = (addr >> 8) & 0xff; + dregs->dma_addr = (addr ) & 0xff; +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(esp->irq); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(esp->irq); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR); +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + return ((amiga_custom.intenar) & IF_PORTS); +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if(write){ + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +#define HOSTS_C + +int blz1230_esp_release(struct Scsi_Host *instance) +{ +#ifdef MODULE + unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; + esp_deallocate((struct NCR_ESP *)instance->hostdata); + esp_release(); + release_mem_region(address, sizeof(struct ESP_regs)); + free_irq(IRQ_AMIGA_PORTS, esp_intr); +#endif + return 1; +} + + +static struct scsi_host_template driver_template = { + .proc_name = "esp-blz1230", + .proc_info = esp_proc_info, + .name = "Blizzard1230 SCSI IV", + .detect = blz1230_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = blz1230_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/blz2060.c b/trunk/drivers/scsi/blz2060.c new file mode 100644 index 000000000000..b6203ec00961 --- /dev/null +++ b/trunk/drivers/scsi/blz2060.c @@ -0,0 +1,306 @@ +/* blz2060.c: Driver for Blizzard 2060 SCSI Controller. + * + * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) + * + * This driver is based on the CyberStorm driver, hence the occasional + * reference to CyberStorm. + */ + +/* TODO: + * + * 1) Figure out how to make a cleaner merge with the sparc driver with regard + * to the caches and the Sparc MMU mapping. + * 2) Make as few routines required outside the generic driver. A lot of the + * routines in this file used to be inline! + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include + +#include + +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define BLZ2060_ESP_ADDR 0x1ff00 +#define BLZ2060_DMA_ADDR 0x1ffe0 + + +/* The Blizzard 2060 DMA interface + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Only two things can be programmed in the Blizzard DMA: + * 1) The data direction is controlled by the status of bit 31 (1 = write) + * 2) The source/dest address (word aligned, shifted one right) in bits 30-0 + * + * Figure out interrupt status by reading the ESP status byte. + */ +struct blz2060_dma_registers { + volatile unsigned char dma_led_ctrl; /* DMA led control [0x000] */ + unsigned char dmapad1[0x0f]; + volatile unsigned char dma_addr0; /* DMA address (MSB) [0x010] */ + unsigned char dmapad2[0x03]; + volatile unsigned char dma_addr1; /* DMA address [0x014] */ + unsigned char dmapad3[0x03]; + volatile unsigned char dma_addr2; /* DMA address [0x018] */ + unsigned char dmapad4[0x03]; + volatile unsigned char dma_addr3; /* DMA address (LSB) [0x01c] */ +}; + +#define BLZ2060_DMA_WRITE 0x80000000 + +/* DMA control bits */ +#define BLZ2060_DMA_LED 0x02 /* HD led control 1 = off */ + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static void dma_led_off(struct NCR_ESP *esp); +static void dma_led_on(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are transferred to the ESP chip + * via PIO. + */ + +/***************************************************************** Detection */ +int __init blz2060_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct zorro_dev *z = NULL; + unsigned long address; + + if ((z = zorro_find_device(ZORRO_PROD_PHASE5_BLIZZARD_2060, z))) { + unsigned long board = z->resource.start; + if (request_mem_region(board+BLZ2060_ESP_ADDR, + sizeof(struct ESP_regs), "NCR53C9x")) { + esp = esp_allocate(tpnt, (void *)board + BLZ2060_ESP_ADDR, 0); + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = 0; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_led_on = &dma_led_on; + esp->dma_led_off = &dma_led_off; + esp->dma_poll = 0; + esp->dma_reset = 0; + + /* SCSI chip speed */ + esp->cfreq = 40000000; + + /* The DMA registers on the Blizzard are mapped + * relative to the device (i.e. in the same Zorro + * I/O block). + */ + address = (unsigned long)ZTWO_VADDR(board); + esp->dregs = (void *)(address + BLZ2060_DMA_ADDR); + + /* ESP register base */ + esp->eregs = (struct ESP_regs *)(address + BLZ2060_ESP_ADDR); + + /* Set the command buffer */ + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); + + esp->irq = IRQ_AMIGA_PORTS; + request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, + "Blizzard 2060 SCSI", esp->ehost); + + /* Figure out our scsi ID on the bus */ + esp->scsi_id = 7; + + /* We don't have a differential SCSI-bus. */ + esp->diff = 0; + + esp_initialize(esp); + + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + return esps_in_use; + } + } + return 0; +} + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Since the Blizzard DMA is fully dedicated to the ESP chip, + * the number of bytes sent (to the ESP chip) equals the number + * of bytes in the FIFO - there is no buffering in the DMA controller. + * XXXX Do I read this right? It is from host to ESP, right? + */ + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + /* I don't think there's any limit on the Blizzard DMA. So we use what + * the ESP chip can handle (24 bit). + */ + unsigned long sz = sp->SCp.this_residual; + if(sz > 0x1000000) + sz = 0x1000000; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ + ESPLOG(("intreq:<%04x>, intena:<%04x>\n", + amiga_custom.intreqr, amiga_custom.intenar)); +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct blz2060_dma_registers *dregs = + (struct blz2060_dma_registers *) (esp->dregs); + + cache_clear(addr, length); + + addr >>= 1; + addr &= ~(BLZ2060_DMA_WRITE); + dregs->dma_addr3 = (addr ) & 0xff; + dregs->dma_addr2 = (addr >> 8) & 0xff; + dregs->dma_addr1 = (addr >> 16) & 0xff; + dregs->dma_addr0 = (addr >> 24) & 0xff; +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct blz2060_dma_registers *dregs = + (struct blz2060_dma_registers *) (esp->dregs); + + cache_push(addr, length); + + addr >>= 1; + addr |= BLZ2060_DMA_WRITE; + dregs->dma_addr3 = (addr ) & 0xff; + dregs->dma_addr2 = (addr >> 8) & 0xff; + dregs->dma_addr1 = (addr >> 16) & 0xff; + dregs->dma_addr0 = (addr >> 24) & 0xff; +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(esp->irq); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(esp->irq); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR); +} + +static void dma_led_off(struct NCR_ESP *esp) +{ + ((struct blz2060_dma_registers *) (esp->dregs))->dma_led_ctrl = + BLZ2060_DMA_LED; +} + +static void dma_led_on(struct NCR_ESP *esp) +{ + ((struct blz2060_dma_registers *) (esp->dregs))->dma_led_ctrl = 0; +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + return ((amiga_custom.intenar) & IF_PORTS); +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if(write){ + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +#define HOSTS_C + +int blz2060_esp_release(struct Scsi_Host *instance) +{ +#ifdef MODULE + unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; + + esp_deallocate((struct NCR_ESP *)instance->hostdata); + esp_release(); + release_mem_region(address, sizeof(struct ESP_regs)); + free_irq(IRQ_AMIGA_PORTS, esp_intr); +#endif + return 1; +} + + +static struct scsi_host_template driver_template = { + .proc_name = "esp-blz2060", + .proc_info = esp_proc_info, + .name = "Blizzard2060 SCSI", + .detect = blz2060_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = blz2060_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/cyberstorm.c b/trunk/drivers/scsi/cyberstorm.c new file mode 100644 index 000000000000..c6b98a42e89d --- /dev/null +++ b/trunk/drivers/scsi/cyberstorm.c @@ -0,0 +1,377 @@ +/* cyberstorm.c: Driver for CyberStorm SCSI Controller. + * + * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) + * + * The CyberStorm SCSI driver is based on David S. Miller's ESP driver + * for the Sparc computers. + * + * This work was made possible by Phase5 who willingly (and most generously) + * supported me with hardware and all the information I needed. + */ + +/* TODO: + * + * 1) Figure out how to make a cleaner merge with the sparc driver with regard + * to the caches and the Sparc MMU mapping. + * 2) Make as few routines required outside the generic driver. A lot of the + * routines in this file used to be inline! + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include + +#include + +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define CYBER_ESP_ADDR 0xf400 +#define CYBER_DMA_ADDR 0xf800 + + +/* The CyberStorm DMA interface */ +struct cyber_dma_registers { + volatile unsigned char dma_addr0; /* DMA address (MSB) [0x000] */ + unsigned char dmapad1[1]; + volatile unsigned char dma_addr1; /* DMA address [0x002] */ + unsigned char dmapad2[1]; + volatile unsigned char dma_addr2; /* DMA address [0x004] */ + unsigned char dmapad3[1]; + volatile unsigned char dma_addr3; /* DMA address (LSB) [0x006] */ + unsigned char dmapad4[0x3fb]; + volatile unsigned char cond_reg; /* DMA cond (ro) [0x402] */ +#define ctrl_reg cond_reg /* DMA control (wo) [0x402] */ +}; + +/* DMA control bits */ +#define CYBER_DMA_LED 0x80 /* HD led control 1 = on */ +#define CYBER_DMA_WRITE 0x40 /* DMA direction. 1 = write */ +#define CYBER_DMA_Z3 0x20 /* 16 (Z2) or 32 (CHIP/Z3) bit DMA transfer */ + +/* DMA status bits */ +#define CYBER_DMA_HNDL_INTR 0x80 /* DMA IRQ pending? */ + +/* The bits below appears to be Phase5 Debug bits only; they were not + * described by Phase5 so using them may seem a bit stupid... + */ +#define CYBER_HOST_ID 0x02 /* If set, host ID should be 7, otherwise + * it should be 6. + */ +#define CYBER_SLOW_CABLE 0x08 /* If *not* set, assume SLOW_CABLE */ + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static void dma_led_off(struct NCR_ESP *esp); +static void dma_led_on(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); + +static unsigned char ctrl_data = 0; /* Keep backup of the stuff written + * to ctrl_reg. Always write a copy + * to this register when writing to + * the hardware register! + */ + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are transferred to the ESP chip + * via PIO. + */ + +/***************************************************************** Detection */ +int __init cyber_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct zorro_dev *z = NULL; + unsigned long address; + + while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { + unsigned long board = z->resource.start; + if ((z->id == ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM || + z->id == ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060) && + request_mem_region(board+CYBER_ESP_ADDR, + sizeof(struct ESP_regs), "NCR53C9x")) { + /* Figure out if this is a CyberStorm or really a + * Fastlane/Blizzard Mk II by looking at the board size. + * CyberStorm maps 64kB + * (ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM does anyway) + */ + if(z->resource.end-board != 0xffff) { + release_mem_region(board+CYBER_ESP_ADDR, + sizeof(struct ESP_regs)); + return 0; + } + esp = esp_allocate(tpnt, (void *)board + CYBER_ESP_ADDR, 0); + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = 0; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_led_on = &dma_led_on; + esp->dma_led_off = &dma_led_off; + esp->dma_poll = 0; + esp->dma_reset = 0; + + /* SCSI chip speed */ + esp->cfreq = 40000000; + + /* The DMA registers on the CyberStorm are mapped + * relative to the device (i.e. in the same Zorro + * I/O block). + */ + address = (unsigned long)ZTWO_VADDR(board); + esp->dregs = (void *)(address + CYBER_DMA_ADDR); + + /* ESP register base */ + esp->eregs = (struct ESP_regs *)(address + CYBER_ESP_ADDR); + + /* Set the command buffer */ + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); + + esp->irq = IRQ_AMIGA_PORTS; + request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, + "CyberStorm SCSI", esp->ehost); + /* Figure out our scsi ID on the bus */ + /* The DMA cond flag contains a hardcoded jumper bit + * which can be used to select host number 6 or 7. + * However, even though it may change, we use a hardcoded + * value of 7. + */ + esp->scsi_id = 7; + + /* We don't have a differential SCSI-bus. */ + esp->diff = 0; + + esp_initialize(esp); + + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + return esps_in_use; + } + } + return 0; +} + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Since the CyberStorm DMA is fully dedicated to the ESP chip, + * the number of bytes sent (to the ESP chip) equals the number + * of bytes in the FIFO - there is no buffering in the DMA controller. + * XXXX Do I read this right? It is from host to ESP, right? + */ + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + /* I don't think there's any limit on the CyberDMA. So we use what + * the ESP chip can handle (24 bit). + */ + unsigned long sz = sp->SCp.this_residual; + if(sz > 0x1000000) + sz = 0x1000000; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ + ESPLOG(("esp%d: dma -- cond_reg<%02x>\n", + esp->esp_id, ((struct cyber_dma_registers *) + (esp->dregs))->cond_reg)); + ESPLOG(("intreq:<%04x>, intena:<%04x>\n", + amiga_custom.intreqr, amiga_custom.intenar)); +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct cyber_dma_registers *dregs = + (struct cyber_dma_registers *) esp->dregs; + + cache_clear(addr, length); + + addr &= ~(1); + dregs->dma_addr0 = (addr >> 24) & 0xff; + dregs->dma_addr1 = (addr >> 16) & 0xff; + dregs->dma_addr2 = (addr >> 8) & 0xff; + dregs->dma_addr3 = (addr ) & 0xff; + ctrl_data &= ~(CYBER_DMA_WRITE); + + /* Check if physical address is outside Z2 space and of + * block length/block aligned in memory. If this is the + * case, enable 32 bit transfer. In all other cases, fall back + * to 16 bit transfer. + * Obviously 32 bit transfer should be enabled if the DMA address + * and length are 32 bit aligned. However, this leads to some + * strange behavior. Even 64 bit aligned addr/length fails. + * Until I've found a reason for this, 32 bit transfer is only + * used for full-block transfers (1kB). + * -jskov + */ +#if 0 + if((addr & 0x3fc) || length & 0x3ff || ((addr > 0x200000) && + (addr < 0xff0000))) + ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */ + else + ctrl_data |= CYBER_DMA_Z3; /* CHIP/Z3, do 32 bit DMA */ +#else + ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */ +#endif + dregs->ctrl_reg = ctrl_data; +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct cyber_dma_registers *dregs = + (struct cyber_dma_registers *) esp->dregs; + + cache_push(addr, length); + + addr |= 1; + dregs->dma_addr0 = (addr >> 24) & 0xff; + dregs->dma_addr1 = (addr >> 16) & 0xff; + dregs->dma_addr2 = (addr >> 8) & 0xff; + dregs->dma_addr3 = (addr ) & 0xff; + ctrl_data |= CYBER_DMA_WRITE; + + /* See comment above */ +#if 0 + if((addr & 0x3fc) || length & 0x3ff || ((addr > 0x200000) && + (addr < 0xff0000))) + ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */ + else + ctrl_data |= CYBER_DMA_Z3; /* CHIP/Z3, do 32 bit DMA */ +#else + ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */ +#endif + dregs->ctrl_reg = ctrl_data; +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(esp->irq); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(esp->irq); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + /* It's important to check the DMA IRQ bit in the correct way! */ + return ((esp_read(esp->eregs->esp_status) & ESP_STAT_INTR) && + ((((struct cyber_dma_registers *)(esp->dregs))->cond_reg) & + CYBER_DMA_HNDL_INTR)); +} + +static void dma_led_off(struct NCR_ESP *esp) +{ + ctrl_data &= ~CYBER_DMA_LED; + ((struct cyber_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data; +} + +static void dma_led_on(struct NCR_ESP *esp) +{ + ctrl_data |= CYBER_DMA_LED; + ((struct cyber_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data; +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + return ((amiga_custom.intenar) & IF_PORTS); +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if(write){ + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +#define HOSTS_C + +int cyber_esp_release(struct Scsi_Host *instance) +{ +#ifdef MODULE + unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; + + esp_deallocate((struct NCR_ESP *)instance->hostdata); + esp_release(); + release_mem_region(address, sizeof(struct ESP_regs)); + free_irq(IRQ_AMIGA_PORTS, esp_intr); +#endif + return 1; +} + + +static struct scsi_host_template driver_template = { + .proc_name = "esp-cyberstorm", + .proc_info = esp_proc_info, + .name = "CyberStorm SCSI", + .detect = cyber_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = cyber_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/cyberstormII.c b/trunk/drivers/scsi/cyberstormII.c new file mode 100644 index 000000000000..e336e853e66f --- /dev/null +++ b/trunk/drivers/scsi/cyberstormII.c @@ -0,0 +1,314 @@ +/* cyberstormII.c: Driver for CyberStorm SCSI Mk II + * + * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) + * + * This driver is based on cyberstorm.c + */ + +/* TODO: + * + * 1) Figure out how to make a cleaner merge with the sparc driver with regard + * to the caches and the Sparc MMU mapping. + * 2) Make as few routines required outside the generic driver. A lot of the + * routines in this file used to be inline! + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include + +#include + +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define CYBERII_ESP_ADDR 0x1ff03 +#define CYBERII_DMA_ADDR 0x1ff43 + + +/* The CyberStorm II DMA interface */ +struct cyberII_dma_registers { + volatile unsigned char cond_reg; /* DMA cond (ro) [0x000] */ +#define ctrl_reg cond_reg /* DMA control (wo) [0x000] */ + unsigned char dmapad4[0x3f]; + volatile unsigned char dma_addr0; /* DMA address (MSB) [0x040] */ + unsigned char dmapad1[3]; + volatile unsigned char dma_addr1; /* DMA address [0x044] */ + unsigned char dmapad2[3]; + volatile unsigned char dma_addr2; /* DMA address [0x048] */ + unsigned char dmapad3[3]; + volatile unsigned char dma_addr3; /* DMA address (LSB) [0x04c] */ +}; + +/* DMA control bits */ +#define CYBERII_DMA_LED 0x02 /* HD led control 1 = on */ + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static void dma_led_off(struct NCR_ESP *esp); +static void dma_led_on(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are transferred to the ESP chip + * via PIO. + */ + +/***************************************************************** Detection */ +int __init cyberII_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct zorro_dev *z = NULL; + unsigned long address; + struct ESP_regs *eregs; + + if ((z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERSTORM_MK_II, z))) { + unsigned long board = z->resource.start; + if (request_mem_region(board+CYBERII_ESP_ADDR, + sizeof(struct ESP_regs), "NCR53C9x")) { + /* Do some magic to figure out if the CyberStorm Mk II + * is equipped with a SCSI controller + */ + address = (unsigned long)ZTWO_VADDR(board); + eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR); + + esp = esp_allocate(tpnt, (void *)board + CYBERII_ESP_ADDR, 0); + + esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); + udelay(5); + if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)) { + esp_deallocate(esp); + scsi_unregister(esp->ehost); + release_mem_region(board+CYBERII_ESP_ADDR, + sizeof(struct ESP_regs)); + return 0; /* Bail out if address did not hold data */ + } + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = 0; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_led_on = &dma_led_on; + esp->dma_led_off = &dma_led_off; + esp->dma_poll = 0; + esp->dma_reset = 0; + + /* SCSI chip speed */ + esp->cfreq = 40000000; + + /* The DMA registers on the CyberStorm are mapped + * relative to the device (i.e. in the same Zorro + * I/O block). + */ + esp->dregs = (void *)(address + CYBERII_DMA_ADDR); + + /* ESP register base */ + esp->eregs = eregs; + + /* Set the command buffer */ + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); + + esp->irq = IRQ_AMIGA_PORTS; + request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, + "CyberStorm SCSI Mk II", esp->ehost); + + /* Figure out our scsi ID on the bus */ + esp->scsi_id = 7; + + /* We don't have a differential SCSI-bus. */ + esp->diff = 0; + + esp_initialize(esp); + + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + return esps_in_use; + } + } + return 0; +} + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Since the CyberStorm DMA is fully dedicated to the ESP chip, + * the number of bytes sent (to the ESP chip) equals the number + * of bytes in the FIFO - there is no buffering in the DMA controller. + * XXXX Do I read this right? It is from host to ESP, right? + */ + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + /* I don't think there's any limit on the CyberDMA. So we use what + * the ESP chip can handle (24 bit). + */ + unsigned long sz = sp->SCp.this_residual; + if(sz > 0x1000000) + sz = 0x1000000; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ + ESPLOG(("esp%d: dma -- cond_reg<%02x>\n", + esp->esp_id, ((struct cyberII_dma_registers *) + (esp->dregs))->cond_reg)); + ESPLOG(("intreq:<%04x>, intena:<%04x>\n", + amiga_custom.intreqr, amiga_custom.intenar)); +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct cyberII_dma_registers *dregs = + (struct cyberII_dma_registers *) esp->dregs; + + cache_clear(addr, length); + + addr &= ~(1); + dregs->dma_addr0 = (addr >> 24) & 0xff; + dregs->dma_addr1 = (addr >> 16) & 0xff; + dregs->dma_addr2 = (addr >> 8) & 0xff; + dregs->dma_addr3 = (addr ) & 0xff; +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct cyberII_dma_registers *dregs = + (struct cyberII_dma_registers *) esp->dregs; + + cache_push(addr, length); + + addr |= 1; + dregs->dma_addr0 = (addr >> 24) & 0xff; + dregs->dma_addr1 = (addr >> 16) & 0xff; + dregs->dma_addr2 = (addr >> 8) & 0xff; + dregs->dma_addr3 = (addr ) & 0xff; +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(esp->irq); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(esp->irq); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + /* It's important to check the DMA IRQ bit in the correct way! */ + return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR); +} + +static void dma_led_off(struct NCR_ESP *esp) +{ + ((struct cyberII_dma_registers *)(esp->dregs))->ctrl_reg &= ~CYBERII_DMA_LED; +} + +static void dma_led_on(struct NCR_ESP *esp) +{ + ((struct cyberII_dma_registers *)(esp->dregs))->ctrl_reg |= CYBERII_DMA_LED; +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + return ((amiga_custom.intenar) & IF_PORTS); +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if(write){ + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +#define HOSTS_C + +int cyberII_esp_release(struct Scsi_Host *instance) +{ +#ifdef MODULE + unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; + + esp_deallocate((struct NCR_ESP *)instance->hostdata); + esp_release(); + release_mem_region(address, sizeof(struct ESP_regs)); + free_irq(IRQ_AMIGA_PORTS, esp_intr); +#endif + return 1; +} + + +static struct scsi_host_template driver_template = { + .proc_name = "esp-cyberstormII", + .proc_info = esp_proc_info, + .name = "CyberStorm Mk II SCSI", + .detect = cyberII_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = cyberII_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/dc395x.c b/trunk/drivers/scsi/dc395x.c index e351db6c0077..22ef3716e786 100644 --- a/trunk/drivers/scsi/dc395x.c +++ b/trunk/drivers/scsi/dc395x.c @@ -4267,7 +4267,7 @@ static int __devinit adapter_sg_tables_alloc(struct AdapterCtlBlk *acb) const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN; int srb_idx = 0; unsigned i = 0; - struct SGentry *uninitialized_var(ptr); + struct SGentry *ptr; for (i = 0; i < DC395x_MAX_SRB_CNT; i++) acb->srb_array[i].segment_x = NULL; diff --git a/trunk/drivers/scsi/dec_esp.c b/trunk/drivers/scsi/dec_esp.c new file mode 100644 index 000000000000..d42ad663ffee --- /dev/null +++ b/trunk/drivers/scsi/dec_esp.c @@ -0,0 +1,687 @@ +/* + * dec_esp.c: Driver for SCSI chips on IOASIC based TURBOchannel DECstations + * and TURBOchannel PMAZ-A cards + * + * TURBOchannel changes by Harald Koerfgen + * PMAZ-A support by David Airlie + * + * based on jazz_esp.c: + * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * + * jazz_esp is based on David S. Miller's ESP driver and cyber_esp + * + * 20000819 - Small PMAZ-AA fixes by Florian Lohoff + * Be warned the PMAZ-AA works currently as a single card. + * Dont try to put multiple cards in one machine - They are + * both detected but it may crash under high load garbling your + * data. + * 20001005 - Initialization fixes for 2.4.0-test9 + * Florian Lohoff + * + * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define DEC_SCSI_SREG 0 +#define DEC_SCSI_DMAREG 0x40000 +#define DEC_SCSI_SRAM 0x80000 +#define DEC_SCSI_DIAG 0xC0000 + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static void dma_drain(struct NCR_ESP *esp); +static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length); +static void dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write); +static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp); +static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp); +static void dma_advance_sg(struct scsi_cmnd * sp); + +static void pmaz_dma_drain(struct NCR_ESP *esp); +static void pmaz_dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length); +static void pmaz_dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length); +static void pmaz_dma_ints_off(struct NCR_ESP *esp); +static void pmaz_dma_ints_on(struct NCR_ESP *esp); +static void pmaz_dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write); +static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp); + +#define TC_ESP_RAM_SIZE 0x20000 +#define ESP_TGT_DMA_SIZE ((TC_ESP_RAM_SIZE/7) & ~(sizeof(int)-1)) +#define ESP_NCMD 7 + +#define TC_ESP_DMAR_MASK 0x1ffff +#define TC_ESP_DMAR_WRITE 0x80000000 +#define TC_ESP_DMA_ADDR(x) ((unsigned)(x) & TC_ESP_DMAR_MASK) + +u32 esp_virt_buffer; +int scsi_current_length; + +volatile unsigned char cmd_buffer[16]; +volatile unsigned char pmaz_cmd_buffer[16]; + /* This is where all commands are put + * before they are trasfered to the ESP chip + * via PIO. + */ + +static irqreturn_t scsi_dma_merr_int(int, void *); +static irqreturn_t scsi_dma_err_int(int, void *); +static irqreturn_t scsi_dma_int(int, void *); + +static struct scsi_host_template dec_esp_template = { + .module = THIS_MODULE, + .name = "NCR53C94", + .info = esp_info, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .proc_info = esp_proc_info, + .proc_name = "dec_esp", + .can_queue = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING, +}; + +static struct NCR_ESP *dec_esp_platform; + +/***************************************************************** Detection */ +static int dec_esp_platform_probe(void) +{ + struct NCR_ESP *esp; + int err = 0; + + if (IOASIC) { + esp = esp_allocate(&dec_esp_template, NULL, 1); + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = &dma_drain; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_poll = 0; + esp->dma_reset = 0; + esp->dma_led_off = 0; + esp->dma_led_on = 0; + + /* virtual DMA functions */ + esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; + esp->dma_mmu_release_scsi_one = 0; + esp->dma_mmu_release_scsi_sgl = 0; + esp->dma_advance_sg = &dma_advance_sg; + + + /* SCSI chip speed */ + esp->cfreq = 25000000; + + esp->dregs = 0; + + /* ESP register base */ + esp->eregs = (void *)CKSEG1ADDR(dec_kn_slot_base + + IOASIC_SCSI); + + /* Set the command buffer */ + esp->esp_command = (volatile unsigned char *) cmd_buffer; + + /* get virtual dma address for command buffer */ + esp->esp_command_dvma = virt_to_phys(cmd_buffer); + + esp->irq = dec_interrupt[DEC_IRQ_ASC]; + + esp->scsi_id = 7; + + /* Check for differential SCSI-bus */ + esp->diff = 0; + + err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, + "ncr53c94", esp->ehost); + if (err) + goto err_alloc; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_MERR], + scsi_dma_merr_int, IRQF_DISABLED, + "ncr53c94 error", esp->ehost); + if (err) + goto err_irq; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_ERR], + scsi_dma_err_int, IRQF_DISABLED, + "ncr53c94 overrun", esp->ehost); + if (err) + goto err_irq_merr; + err = request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], scsi_dma_int, + IRQF_DISABLED, "ncr53c94 dma", esp->ehost); + if (err) + goto err_irq_err; + + esp_initialize(esp); + + err = scsi_add_host(esp->ehost, NULL); + if (err) { + printk(KERN_ERR "ESP: Unable to register adapter\n"); + goto err_irq_dma; + } + + scsi_scan_host(esp->ehost); + + dec_esp_platform = esp; + } + + return 0; + +err_irq_dma: + free_irq(dec_interrupt[DEC_IRQ_ASC_DMA], esp->ehost); +err_irq_err: + free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], esp->ehost); +err_irq_merr: + free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], esp->ehost); +err_irq: + free_irq(esp->irq, esp->ehost); +err_alloc: + esp_deallocate(esp); + scsi_host_put(esp->ehost); + return err; +} + +static int __init dec_esp_probe(struct device *dev) +{ + struct NCR_ESP *esp; + resource_size_t start, len; + int err; + + esp = esp_allocate(&dec_esp_template, NULL, 1); + + dev_set_drvdata(dev, esp); + + start = to_tc_dev(dev)->resource.start; + len = to_tc_dev(dev)->resource.end - start + 1; + + if (!request_mem_region(start, len, dev->bus_id)) { + printk(KERN_ERR "%s: Unable to reserve MMIO resource\n", + dev->bus_id); + err = -EBUSY; + goto err_alloc; + } + + /* Store base addr into esp struct. */ + esp->slot = start; + + esp->dregs = 0; + esp->eregs = (void *)CKSEG1ADDR(start + DEC_SCSI_SREG); + esp->do_pio_cmds = 1; + + /* Set the command buffer. */ + esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer; + + /* Get virtual dma address for command buffer. */ + esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer); + + esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus); + + esp->irq = to_tc_dev(dev)->interrupt; + + /* Required functions. */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &pmaz_dma_init_read; + esp->dma_init_write = &pmaz_dma_init_write; + esp->dma_ints_off = &pmaz_dma_ints_off; + esp->dma_ints_on = &pmaz_dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &pmaz_dma_setup; + + /* Optional functions. */ + esp->dma_barrier = 0; + esp->dma_drain = &pmaz_dma_drain; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_poll = 0; + esp->dma_reset = 0; + esp->dma_led_off = 0; + esp->dma_led_on = 0; + + esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = 0; + esp->dma_mmu_release_scsi_one = 0; + esp->dma_mmu_release_scsi_sgl = 0; + esp->dma_advance_sg = 0; + + err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, "PMAZ_AA", + esp->ehost); + if (err) { + printk(KERN_ERR "%s: Unable to get IRQ %d\n", + dev->bus_id, esp->irq); + goto err_resource; + } + + esp->scsi_id = 7; + esp->diff = 0; + esp_initialize(esp); + + err = scsi_add_host(esp->ehost, dev); + if (err) { + printk(KERN_ERR "%s: Unable to register adapter\n", + dev->bus_id); + goto err_irq; + } + + scsi_scan_host(esp->ehost); + + return 0; + +err_irq: + free_irq(esp->irq, esp->ehost); + +err_resource: + release_mem_region(start, len); + +err_alloc: + esp_deallocate(esp); + scsi_host_put(esp->ehost); + return err; +} + +static void __exit dec_esp_platform_remove(void) +{ + struct NCR_ESP *esp = dec_esp_platform; + + free_irq(esp->irq, esp->ehost); + esp_deallocate(esp); + scsi_host_put(esp->ehost); + dec_esp_platform = NULL; +} + +static void __exit dec_esp_remove(struct device *dev) +{ + struct NCR_ESP *esp = dev_get_drvdata(dev); + + free_irq(esp->irq, esp->ehost); + esp_deallocate(esp); + scsi_host_put(esp->ehost); +} + + +/************************************************************* DMA Functions */ +static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id) +{ + printk("Got unexpected SCSI DMA Interrupt! < "); + printk("SCSI_DMA_MEMRDERR "); + printk(">\n"); + + return IRQ_HANDLED; +} + +static irqreturn_t scsi_dma_err_int(int irq, void *dev_id) +{ + /* empty */ + + return IRQ_HANDLED; +} + +static irqreturn_t scsi_dma_int(int irq, void *dev_id) +{ + u32 scsi_next_ptr; + + scsi_next_ptr = ioasic_read(IO_REG_SCSI_DMA_P); + + /* next page */ + scsi_next_ptr = (((scsi_next_ptr >> 3) + PAGE_SIZE) & PAGE_MASK) << 3; + ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr); + fast_iob(); + + return IRQ_HANDLED; +} + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + return fifo_count; +} + +static void dma_drain(struct NCR_ESP *esp) +{ + u32 nw, data0, data1, scsi_data_ptr; + u16 *p; + + nw = ioasic_read(IO_REG_SCSI_SCR); + + /* + * Is there something in the dma buffers left? + */ + if (nw) { + scsi_data_ptr = ioasic_read(IO_REG_SCSI_DMA_P) >> 3; + p = phys_to_virt(scsi_data_ptr); + switch (nw) { + case 1: + data0 = ioasic_read(IO_REG_SCSI_SDR0); + p[0] = data0 & 0xffff; + break; + case 2: + data0 = ioasic_read(IO_REG_SCSI_SDR0); + p[0] = data0 & 0xffff; + p[1] = (data0 >> 16) & 0xffff; + break; + case 3: + data0 = ioasic_read(IO_REG_SCSI_SDR0); + data1 = ioasic_read(IO_REG_SCSI_SDR1); + p[0] = data0 & 0xffff; + p[1] = (data0 >> 16) & 0xffff; + p[2] = data1 & 0xffff; + break; + default: + printk("Strange: %d words in dma buffer left\n", nw); + break; + } + } +} + +static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd * sp) +{ + return sp->SCp.this_residual; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ +} + +static void dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length) +{ + u32 scsi_next_ptr, ioasic_ssr; + unsigned long flags; + + if (vaddress & 3) + panic("dec_esp.c: unable to handle partial word transfers, yet..."); + + dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length); + + spin_lock_irqsave(&ioasic_ssr_lock, flags); + + fast_mb(); + ioasic_ssr = ioasic_read(IO_REG_SSR); + + ioasic_ssr &= ~IO_SSR_SCSI_DMA_EN; + ioasic_write(IO_REG_SSR, ioasic_ssr); + + fast_wmb(); + ioasic_write(IO_REG_SCSI_SCR, 0); + ioasic_write(IO_REG_SCSI_DMA_P, vaddress << 3); + + /* prepare for next page */ + scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; + ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr); + + ioasic_ssr |= (IO_SSR_SCSI_DMA_DIR | IO_SSR_SCSI_DMA_EN); + fast_wmb(); + ioasic_write(IO_REG_SSR, ioasic_ssr); + + fast_iob(); + spin_unlock_irqrestore(&ioasic_ssr_lock, flags); +} + +static void dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length) +{ + u32 scsi_next_ptr, ioasic_ssr; + unsigned long flags; + + if (vaddress & 3) + panic("dec_esp.c: unable to handle partial word transfers, yet..."); + + dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length); + + spin_lock_irqsave(&ioasic_ssr_lock, flags); + + fast_mb(); + ioasic_ssr = ioasic_read(IO_REG_SSR); + + ioasic_ssr &= ~(IO_SSR_SCSI_DMA_DIR | IO_SSR_SCSI_DMA_EN); + ioasic_write(IO_REG_SSR, ioasic_ssr); + + fast_wmb(); + ioasic_write(IO_REG_SCSI_SCR, 0); + ioasic_write(IO_REG_SCSI_DMA_P, vaddress << 3); + + /* prepare for next page */ + scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; + ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr); + + ioasic_ssr |= IO_SSR_SCSI_DMA_EN; + fast_wmb(); + ioasic_write(IO_REG_SSR, ioasic_ssr); + + fast_iob(); + spin_unlock_irqrestore(&ioasic_ssr_lock, flags); +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + return (esp->eregs->esp_status & ESP_STAT_INTR); +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + /* + * FIXME: what's this good for? + */ + return 1; +} + +static void dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write) +{ + /* + * DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if (write) + dma_init_read(esp, addr, count); + else + dma_init_write(esp, addr, count); +} + +static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp) +{ + sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer); +} + +static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp) +{ + int sz = sp->SCp.buffers_residual; + struct scatterlist *sg = sp->SCp.buffer; + + while (sz >= 0) { + sg[sz].dma_address = page_to_phys(sg[sz].page) + sg[sz].offset; + sz--; + } + sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address); +} + +static void dma_advance_sg(struct scsi_cmnd * sp) +{ + sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address); +} + +static void pmaz_dma_drain(struct NCR_ESP *esp) +{ + memcpy(phys_to_virt(esp_virt_buffer), + (void *)CKSEG1ADDR(esp->slot + DEC_SCSI_SRAM + + ESP_TGT_DMA_SIZE), + scsi_current_length); +} + +static void pmaz_dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length) +{ + volatile u32 *dmareg = + (volatile u32 *)CKSEG1ADDR(esp->slot + DEC_SCSI_DMAREG); + + if (length > ESP_TGT_DMA_SIZE) + length = ESP_TGT_DMA_SIZE; + + *dmareg = TC_ESP_DMA_ADDR(ESP_TGT_DMA_SIZE); + + iob(); + + esp_virt_buffer = vaddress; + scsi_current_length = length; +} + +static void pmaz_dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length) +{ + volatile u32 *dmareg = + (volatile u32 *)CKSEG1ADDR(esp->slot + DEC_SCSI_DMAREG); + + memcpy((void *)CKSEG1ADDR(esp->slot + DEC_SCSI_SRAM + + ESP_TGT_DMA_SIZE), + phys_to_virt(vaddress), length); + + wmb(); + *dmareg = TC_ESP_DMAR_WRITE | TC_ESP_DMA_ADDR(ESP_TGT_DMA_SIZE); + + iob(); +} + +static void pmaz_dma_ints_off(struct NCR_ESP *esp) +{ +} + +static void pmaz_dma_ints_on(struct NCR_ESP *esp) +{ +} + +static void pmaz_dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write) +{ + /* + * DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if (write) + pmaz_dma_init_read(esp, addr, count); + else + pmaz_dma_init_write(esp, addr, count); +} + +static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp) +{ + sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer); +} + + +#ifdef CONFIG_TC +static int __init dec_esp_tc_probe(struct device *dev); +static int __exit dec_esp_tc_remove(struct device *dev); + +static const struct tc_device_id dec_esp_tc_table[] = { + { "DEC ", "PMAZ-AA " }, + { } +}; +MODULE_DEVICE_TABLE(tc, dec_esp_tc_table); + +static struct tc_driver dec_esp_tc_driver = { + .id_table = dec_esp_tc_table, + .driver = { + .name = "dec_esp", + .bus = &tc_bus_type, + .probe = dec_esp_tc_probe, + .remove = __exit_p(dec_esp_tc_remove), + }, +}; + +static int __init dec_esp_tc_probe(struct device *dev) +{ + int status = dec_esp_probe(dev); + if (!status) + get_device(dev); + return status; +} + +static int __exit dec_esp_tc_remove(struct device *dev) +{ + put_device(dev); + dec_esp_remove(dev); + return 0; +} +#endif + +static int __init dec_esp_init(void) +{ + int status; + + status = tc_register_driver(&dec_esp_tc_driver); + if (!status) + dec_esp_platform_probe(); + + if (nesps) { + pr_info("ESP: Total of %d ESP hosts found, " + "%d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + } + + return status; +} + +static void __exit dec_esp_exit(void) +{ + dec_esp_platform_remove(); + tc_unregister_driver(&dec_esp_tc_driver); +} + + +module_init(dec_esp_init); +module_exit(dec_esp_exit); diff --git a/trunk/drivers/scsi/fastlane.c b/trunk/drivers/scsi/fastlane.c new file mode 100644 index 000000000000..4266a2139b5f --- /dev/null +++ b/trunk/drivers/scsi/fastlane.c @@ -0,0 +1,421 @@ +/* fastlane.c: Driver for Phase5's Fastlane SCSI Controller. + * + * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) + * + * This driver is based on the CyberStorm driver, hence the occasional + * reference to CyberStorm. + * + * Betatesting & crucial adjustments by + * Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz) + * + */ + +/* TODO: + * + * o According to the doc from laire, it is required to reset the DMA when + * the transfer is done. ATM we reset DMA just before every new + * dma_init_(read|write). + * + * 1) Figure out how to make a cleaner merge with the sparc driver with regard + * to the caches and the Sparc MMU mapping. + * 2) Make as few routines required outside the generic driver. A lot of the + * routines in this file used to be inline! + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include + +#include +#include + +#include + +/* Such day has just come... */ +#if 0 +/* Let this defined unless you really need to enable DMA IRQ one day */ +#define NODMAIRQ +#endif + +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define FASTLANE_ESP_ADDR 0x1000001 +#define FASTLANE_DMA_ADDR 0x1000041 + + +/* The Fastlane DMA interface */ +struct fastlane_dma_registers { + volatile unsigned char cond_reg; /* DMA status (ro) [0x0000] */ +#define ctrl_reg cond_reg /* DMA control (wo) [0x0000] */ + unsigned char dmapad1[0x3f]; + volatile unsigned char clear_strobe; /* DMA clear (wo) [0x0040] */ +}; + + +/* DMA status bits */ +#define FASTLANE_DMA_MINT 0x80 +#define FASTLANE_DMA_IACT 0x40 +#define FASTLANE_DMA_CREQ 0x20 + +/* DMA control bits */ +#define FASTLANE_DMA_FCODE 0xa0 +#define FASTLANE_DMA_MASK 0xf3 +#define FASTLANE_DMA_LED 0x10 /* HD led control 1 = on */ +#define FASTLANE_DMA_WRITE 0x08 /* 1 = write */ +#define FASTLANE_DMA_ENABLE 0x04 /* Enable DMA */ +#define FASTLANE_DMA_EDI 0x02 /* Enable DMA IRQ ? */ +#define FASTLANE_DMA_ESI 0x01 /* Enable SCSI IRQ */ + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddr, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static void dma_irq_exit(struct NCR_ESP *esp); +static void dma_led_off(struct NCR_ESP *esp); +static void dma_led_on(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); + +static unsigned char ctrl_data = 0; /* Keep backup of the stuff written + * to ctrl_reg. Always write a copy + * to this register when writing to + * the hardware register! + */ + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are transferred to the ESP chip + * via PIO. + */ + +static inline void dma_clear(struct NCR_ESP *esp) +{ + struct fastlane_dma_registers *dregs = + (struct fastlane_dma_registers *) (esp->dregs); + unsigned long *t; + + ctrl_data = (ctrl_data & FASTLANE_DMA_MASK); + dregs->ctrl_reg = ctrl_data; + + t = (unsigned long *)(esp->edev); + + dregs->clear_strobe = 0; + *t = 0 ; +} + +/***************************************************************** Detection */ +int __init fastlane_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct zorro_dev *z = NULL; + unsigned long address; + + if ((z = zorro_find_device(ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060, z))) { + unsigned long board = z->resource.start; + if (request_mem_region(board+FASTLANE_ESP_ADDR, + sizeof(struct ESP_regs), "NCR53C9x")) { + /* Check if this is really a fastlane controller. The problem + * is that also the cyberstorm and blizzard controllers use + * this ID value. Fortunately only Fastlane maps in Z3 space + */ + if (board < 0x1000000) { + goto err_release; + } + esp = esp_allocate(tpnt, (void *)board + FASTLANE_ESP_ADDR, 0); + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = 0; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = &dma_irq_exit; + esp->dma_led_on = &dma_led_on; + esp->dma_led_off = &dma_led_off; + esp->dma_poll = 0; + esp->dma_reset = 0; + + /* Initialize the portBits (enable IRQs) */ + ctrl_data = (FASTLANE_DMA_FCODE | +#ifndef NODMAIRQ + FASTLANE_DMA_EDI | +#endif + FASTLANE_DMA_ESI); + + + /* SCSI chip clock */ + esp->cfreq = 40000000; + + + /* Map the physical address space into virtual kernel space */ + address = (unsigned long) + z_ioremap(board, z->resource.end-board+1); + + if(!address){ + printk("Could not remap Fastlane controller memory!"); + goto err_unregister; + } + + + /* The DMA registers on the Fastlane are mapped + * relative to the device (i.e. in the same Zorro + * I/O block). + */ + esp->dregs = (void *)(address + FASTLANE_DMA_ADDR); + + /* ESP register base */ + esp->eregs = (struct ESP_regs *)(address + FASTLANE_ESP_ADDR); + + /* Board base */ + esp->edev = (void *) address; + + /* Set the command buffer */ + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); + + esp->irq = IRQ_AMIGA_PORTS; + esp->slot = board+FASTLANE_ESP_ADDR; + if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, + "Fastlane SCSI", esp->ehost)) { + printk(KERN_WARNING "Fastlane: Could not get IRQ%d, aborting.\n", IRQ_AMIGA_PORTS); + goto err_unmap; + } + + /* Controller ID */ + esp->scsi_id = 7; + + /* We don't have a differential SCSI-bus. */ + esp->diff = 0; + + dma_clear(esp); + esp_initialize(esp); + + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + return esps_in_use; + } + } + return 0; + + err_unmap: + z_iounmap((void *)address); + err_unregister: + scsi_unregister (esp->ehost); + err_release: + release_mem_region(z->resource.start+FASTLANE_ESP_ADDR, + sizeof(struct ESP_regs)); + return 0; +} + + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Since the Fastlane DMA is fully dedicated to the ESP chip, + * the number of bytes sent (to the ESP chip) equals the number + * of bytes in the FIFO - there is no buffering in the DMA controller. + * XXXX Do I read this right? It is from host to ESP, right? + */ + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + unsigned long sz = sp->SCp.this_residual; + if(sz > 0xfffc) + sz = 0xfffc; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ + ESPLOG(("esp%d: dma -- cond_reg<%02x>\n", + esp->esp_id, ((struct fastlane_dma_registers *) + (esp->dregs))->cond_reg)); + ESPLOG(("intreq:<%04x>, intena:<%04x>\n", + amiga_custom.intreqr, amiga_custom.intenar)); +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct fastlane_dma_registers *dregs = + (struct fastlane_dma_registers *) (esp->dregs); + unsigned long *t; + + cache_clear(addr, length); + + dma_clear(esp); + + t = (unsigned long *)((addr & 0x00ffffff) + esp->edev); + + dregs->clear_strobe = 0; + *t = addr; + + ctrl_data = (ctrl_data & FASTLANE_DMA_MASK) | FASTLANE_DMA_ENABLE; + dregs->ctrl_reg = ctrl_data; +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) +{ + struct fastlane_dma_registers *dregs = + (struct fastlane_dma_registers *) (esp->dregs); + unsigned long *t; + + cache_push(addr, length); + + dma_clear(esp); + + t = (unsigned long *)((addr & 0x00ffffff) + (esp->edev)); + + dregs->clear_strobe = 0; + *t = addr; + + ctrl_data = ((ctrl_data & FASTLANE_DMA_MASK) | + FASTLANE_DMA_ENABLE | + FASTLANE_DMA_WRITE); + dregs->ctrl_reg = ctrl_data; +} + + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(esp->irq); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(esp->irq); +} + +static void dma_irq_exit(struct NCR_ESP *esp) +{ + struct fastlane_dma_registers *dregs = + (struct fastlane_dma_registers *) (esp->dregs); + + dregs->ctrl_reg = ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI); +#ifdef __mc68000__ + nop(); +#endif + dregs->ctrl_reg = ctrl_data; +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + struct fastlane_dma_registers *dregs = + (struct fastlane_dma_registers *) (esp->dregs); + unsigned char dma_status; + + dma_status = dregs->cond_reg; + + if(dma_status & FASTLANE_DMA_IACT) + return 0; /* not our IRQ */ + + /* Return non-zero if ESP requested IRQ */ + return ( +#ifndef NODMAIRQ + (dma_status & FASTLANE_DMA_CREQ) && +#endif + (!(dma_status & FASTLANE_DMA_MINT)) && + (esp_read(((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR)); +} + +static void dma_led_off(struct NCR_ESP *esp) +{ + ctrl_data &= ~FASTLANE_DMA_LED; + ((struct fastlane_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data; +} + +static void dma_led_on(struct NCR_ESP *esp) +{ + ctrl_data |= FASTLANE_DMA_LED; + ((struct fastlane_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data; +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + return ((amiga_custom.intenar) & IF_PORTS); +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if(write){ + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +#define HOSTS_C + +int fastlane_esp_release(struct Scsi_Host *instance) +{ +#ifdef MODULE + unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; + esp_deallocate((struct NCR_ESP *)instance->hostdata); + esp_release(); + release_mem_region(address, sizeof(struct ESP_regs)); + free_irq(IRQ_AMIGA_PORTS, esp_intr); +#endif + return 1; +} + + +static struct scsi_host_template driver_template = { + .proc_name = "esp-fastlane", + .proc_info = esp_proc_info, + .name = "Fastlane SCSI", + .detect = fastlane_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = fastlane_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/iscsi_tcp.c b/trunk/drivers/scsi/iscsi_tcp.c index 8a178674cb18..b6f99dfbb038 100644 --- a/trunk/drivers/scsi/iscsi_tcp.c +++ b/trunk/drivers/scsi/iscsi_tcp.c @@ -629,9 +629,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) int rc; if (tcp_conn->in.datalen) { - iscsi_conn_printk(KERN_ERR, conn, - "invalid R2t with datalen %d\n", - tcp_conn->in.datalen); + printk(KERN_ERR "iscsi_tcp: invalid R2t with datalen %d\n", + tcp_conn->in.datalen); return ISCSI_ERR_DATALEN; } @@ -645,9 +644,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) { - iscsi_conn_printk(KERN_INFO, conn, - "dropping R2T itt %d in recovery.\n", - ctask->itt); + printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " + "recovery...\n", ctask->itt); return 0; } @@ -657,8 +655,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->exp_statsn = rhdr->statsn; r2t->data_length = be32_to_cpu(rhdr->data_length); if (r2t->data_length == 0) { - iscsi_conn_printk(KERN_ERR, conn, - "invalid R2T with zero data len\n"); + printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n"); __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); return ISCSI_ERR_DATALEN; @@ -671,10 +668,9 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_offset = be32_to_cpu(rhdr->data_offset); if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) { - iscsi_conn_printk(KERN_ERR, conn, - "invalid R2T with data len %u at offset %u " - "and total length %d\n", r2t->data_length, - r2t->data_offset, scsi_bufflen(ctask->sc)); + printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at " + "offset %u and total length %d\n", r2t->data_length, + r2t->data_offset, scsi_bufflen(ctask->sc)); __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); return ISCSI_ERR_DATALEN; @@ -740,9 +736,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) /* verify PDU length */ tcp_conn->in.datalen = ntoh24(hdr->dlength); if (tcp_conn->in.datalen > conn->max_recv_dlength) { - iscsi_conn_printk(KERN_ERR, conn, - "iscsi_tcp: datalen %d > %d\n", - tcp_conn->in.datalen, conn->max_recv_dlength); + printk(KERN_ERR "iscsi_tcp: datalen %d > %d\n", + tcp_conn->in.datalen, conn->max_recv_dlength); return ISCSI_ERR_DATALEN; } @@ -824,12 +819,10 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) * For now we fail until we find a vendor that needs it */ if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) { - iscsi_conn_printk(KERN_ERR, conn, - "iscsi_tcp: received buffer of " - "len %u but conn buffer is only %u " - "(opcode %0x)\n", - tcp_conn->in.datalen, - ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); + printk(KERN_ERR "iscsi_tcp: received buffer of len %u " + "but conn buffer is only %u (opcode %0x)\n", + tcp_conn->in.datalen, + ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); rc = ISCSI_ERR_PROTO; break; } @@ -1503,25 +1496,30 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); tcp_conn->tx_hash.flags = 0; - if (IS_ERR(tcp_conn->tx_hash.tfm)) + if (IS_ERR(tcp_conn->tx_hash.tfm)) { + printk(KERN_ERR "Could not create connection due to crc32c " + "loading error %ld. Make sure the crc32c module is " + "built as a module or into the kernel\n", + PTR_ERR(tcp_conn->tx_hash.tfm)); goto free_tcp_conn; + } tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); tcp_conn->rx_hash.flags = 0; - if (IS_ERR(tcp_conn->rx_hash.tfm)) + if (IS_ERR(tcp_conn->rx_hash.tfm)) { + printk(KERN_ERR "Could not create connection due to crc32c " + "loading error %ld. Make sure the crc32c module is " + "built as a module or into the kernel\n", + PTR_ERR(tcp_conn->rx_hash.tfm)); goto free_tx_tfm; + } return cls_conn; free_tx_tfm: crypto_free_hash(tcp_conn->tx_hash.tfm); free_tcp_conn: - iscsi_conn_printk(KERN_ERR, conn, - "Could not create connection due to crc32c " - "loading error. Make sure the crc32c " - "module is built as a module or into the " - "kernel\n"); kfree(tcp_conn); tcp_conn_alloc_fail: iscsi_conn_teardown(cls_conn); @@ -1629,8 +1627,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, /* lookup for existing socket */ sock = sockfd_lookup((int)transport_eph, &err); if (!sock) { - iscsi_conn_printk(KERN_ERR, conn, - "sockfd_lookup failed %d\n", err); + printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err); return -EEXIST; } /* diff --git a/trunk/drivers/scsi/libiscsi.c b/trunk/drivers/scsi/libiscsi.c index 59f8445eab0d..553168ae44f1 100644 --- a/trunk/drivers/scsi/libiscsi.c +++ b/trunk/drivers/scsi/libiscsi.c @@ -160,7 +160,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) hdr->opcode = ISCSI_OP_SCSI_CMD; hdr->flags = ISCSI_ATTR_SIMPLE; int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); - hdr->itt = build_itt(ctask->itt, session->age); + hdr->itt = build_itt(ctask->itt, conn->id, session->age); hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); hdr->cmdsn = cpu_to_be32(session->cmdsn); session->cmdsn++; @@ -416,9 +416,8 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (datalen < 2) { invalid_datalen: - iscsi_conn_printk(KERN_ERR, conn, - "Got CHECK_CONDITION but invalid data " - "buffer size of %d\n", datalen); + printk(KERN_ERR "iscsi: Got CHECK_CONDITION but " + "invalid data buffer size of %d\n", datalen); sc->result = DID_BAD_TARGET << 16; goto out; } @@ -495,7 +494,7 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); if (!mtask) { - iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n"); + printk(KERN_ERR "Could not send nopout\n"); return; } @@ -523,10 +522,9 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); itt = get_itt(rejected_pdu.itt); - iscsi_conn_printk(KERN_ERR, conn, - "itt 0x%x had pdu (op 0x%x) rejected " - "due to DataDigest error.\n", itt, - rejected_pdu.opcode); + printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected " + "due to DataDigest error.\n", itt, + rejected_pdu.opcode); } } return 0; @@ -543,8 +541,8 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, * queuecommand or send generic. session lock must be held and verify * itt must have been called. */ -static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, - char *data, int datalen) +int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + char *data, int datalen) { struct iscsi_session *session = conn->session; int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; @@ -674,6 +672,7 @@ static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, return rc; } +EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, char *data, int datalen) @@ -698,13 +697,18 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (hdr->itt != RESERVED_ITT) { if (((__force u32)hdr->itt & ISCSI_AGE_MASK) != (session->age << ISCSI_AGE_SHIFT)) { - iscsi_conn_printk(KERN_ERR, conn, - "received itt %x expected session " - "age (%x)\n", (__force u32)hdr->itt, - session->age & ISCSI_AGE_MASK); + printk(KERN_ERR "iscsi: received itt %x expected " + "session age (%x)\n", (__force u32)hdr->itt, + session->age & ISCSI_AGE_MASK); return ISCSI_ERR_BAD_ITT; } + if (((__force u32)hdr->itt & ISCSI_CID_MASK) != + (conn->id << ISCSI_CID_SHIFT)) { + printk(KERN_ERR "iscsi: received itt %x, expected " + "CID (%x)\n", (__force u32)hdr->itt, conn->id); + return ISCSI_ERR_BAD_ITT; + } itt = get_itt(hdr->itt); } else itt = ~0U; @@ -713,17 +717,16 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, ctask = session->cmds[itt]; if (!ctask->sc) { - iscsi_conn_printk(KERN_INFO, conn, "dropping ctask " - "with itt 0x%x\n", ctask->itt); + printk(KERN_INFO "iscsi: dropping ctask with " + "itt 0x%x\n", ctask->itt); /* force drop */ return ISCSI_ERR_NO_SCSI_CMD; } if (ctask->sc->SCp.phase != session->age) { - iscsi_conn_printk(KERN_ERR, conn, - "iscsi: ctask's session age %d, " - "expected %d\n", ctask->sc->SCp.phase, - session->age); + printk(KERN_ERR "iscsi: ctask's session age %d, " + "expected %d\n", ctask->sc->SCp.phase, + session->age); return ISCSI_ERR_SESSION_FAILED; } } @@ -768,7 +771,7 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn, */ nop->cmdsn = cpu_to_be32(session->cmdsn); if (hdr->itt != RESERVED_ITT) { - hdr->itt = build_itt(mtask->itt, session->age); + hdr->itt = build_itt(mtask->itt, conn->id, session->age); /* * TODO: We always use immediate, so we never hit this. * If we start to send tmfs or nops as non-immediate then @@ -994,7 +997,6 @@ enum { FAILURE_SESSION_IN_RECOVERY, FAILURE_SESSION_RECOVERY_TIMEOUT, FAILURE_SESSION_LOGGING_OUT, - FAILURE_SESSION_NOT_READY, }; int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) @@ -1015,12 +1017,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) session = iscsi_hostdata(host->hostdata); spin_lock(&session->lock); - reason = iscsi_session_chkready(session_to_cls(session)); - if (reason) { - sc->result = reason; - goto fault; - } - /* * ISCSI_STATE_FAILED is a temp. state. The recovery * code will decide what is best to do with command queued @@ -1037,23 +1033,18 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) switch (session->state) { case ISCSI_STATE_IN_RECOVERY: reason = FAILURE_SESSION_IN_RECOVERY; - sc->result = DID_IMM_RETRY << 16; - break; + goto reject; case ISCSI_STATE_LOGGING_OUT: reason = FAILURE_SESSION_LOGGING_OUT; - sc->result = DID_IMM_RETRY << 16; - break; + goto reject; case ISCSI_STATE_RECOVERY_FAILED: reason = FAILURE_SESSION_RECOVERY_TIMEOUT; - sc->result = DID_NO_CONNECT << 16; break; case ISCSI_STATE_TERMINATE: reason = FAILURE_SESSION_TERMINATE; - sc->result = DID_NO_CONNECT << 16; break; default: reason = FAILURE_SESSION_FREED; - sc->result = DID_NO_CONNECT << 16; } goto fault; } @@ -1061,7 +1052,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) conn = session->leadconn; if (!conn) { reason = FAILURE_SESSION_FREED; - sc->result = DID_NO_CONNECT << 16; goto fault; } @@ -1101,7 +1091,9 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) fault: spin_unlock(&session->lock); - debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); + printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n", + sc->cmnd[0], reason); + sc->result = (DID_NO_CONNECT << 16); scsi_set_resid(sc, scsi_bufflen(sc)); sc->scsi_done(sc); spin_lock(host->host_lock); @@ -1168,8 +1160,7 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc) mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_LOGGED_IN) - iscsi_session_printk(KERN_INFO, session, - "host reset succeeded\n"); + printk(KERN_INFO "iscsi: host reset succeeded\n"); else goto failed; spin_unlock_bh(&session->lock); @@ -1248,8 +1239,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, * Fail commands. session lock held and recv side suspended and xmit * thread flushed */ -static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, - int error) +static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) { struct iscsi_cmd_task *ctask, *tmp; @@ -1261,7 +1251,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, if (lun == ctask->sc->device->lun || lun == -1) { debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, ctask->itt); - fail_command(conn, ctask, error << 16); + fail_command(conn, ctask, DID_BUS_BUSY << 16); } } @@ -1269,7 +1259,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, if (lun == ctask->sc->device->lun || lun == -1) { debug_scsi("failing requeued sc %p itt 0x%x\n", ctask->sc, ctask->itt); - fail_command(conn, ctask, error << 16); + fail_command(conn, ctask, DID_BUS_BUSY << 16); } } @@ -1367,10 +1357,10 @@ static void iscsi_check_transport_timeouts(unsigned long data) last_recv = conn->last_recv; if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ), jiffies)) { - iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs " - "expired, last rx %lu, last ping %lu, " - "now %lu\n", conn->ping_timeout, last_recv, - conn->last_ping, jiffies); + printk(KERN_ERR "ping timeout of %d secs expired, " + "last rx %lu, last ping %lu, now %lu\n", + conn->ping_timeout, last_recv, + conn->last_ping, jiffies); spin_unlock(&session->lock); iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return; @@ -1383,11 +1373,14 @@ static void iscsi_check_transport_timeouts(unsigned long data) iscsi_send_nopout(conn, NULL); } next_timeout = last_recv + timeout + (conn->ping_timeout * HZ); - } else + } else { next_timeout = last_recv + timeout; + } - debug_scsi("Setting next tmo %lu\n", next_timeout); - mod_timer(&conn->transport_timer, next_timeout); + if (next_timeout) { + debug_scsi("Setting next tmo %lu\n", next_timeout); + mod_timer(&conn->transport_timer, next_timeout); + } done: spin_unlock(&session->lock); } @@ -1580,7 +1573,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) /* need to grab the recv lock then session lock */ write_lock_bh(conn->recv_lock); spin_lock(&session->lock); - fail_all_commands(conn, sc->device->lun, DID_ERROR); + fail_all_commands(conn, sc->device->lun); conn->tmf_state = TMF_INITIAL; spin_unlock(&session->lock); write_unlock_bh(conn->recv_lock); @@ -1951,10 +1944,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) } spin_unlock_irqrestore(session->host->host_lock, flags); msleep_interruptible(500); - iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): " - "host_busy %d host_failed %d\n", - session->host->host_busy, - session->host->host_failed); + printk(KERN_INFO "iscsi: scsi conn_destroy(): host_busy %d " + "host_failed %d\n", session->host->host_busy, + session->host->host_failed); /* * force eh_abort() to unblock */ @@ -1983,28 +1975,27 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) struct iscsi_session *session = conn->session; if (!session) { - iscsi_conn_printk(KERN_ERR, conn, - "can't start unbound connection\n"); + printk(KERN_ERR "iscsi: can't start unbound connection\n"); return -EPERM; } if ((session->imm_data_en || !session->initial_r2t_en) && session->first_burst > session->max_burst) { - iscsi_conn_printk(KERN_INFO, conn, "invalid burst lengths: " - "first_burst %d max_burst %d\n", - session->first_burst, session->max_burst); + printk("iscsi: invalid burst lengths: " + "first_burst %d max_burst %d\n", + session->first_burst, session->max_burst); return -EINVAL; } if (conn->ping_timeout && !conn->recv_timeout) { - iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of " - "zero. Using 5 seconds\n."); + printk(KERN_ERR "iscsi: invalid recv timeout of zero " + "Using 5 seconds\n."); conn->recv_timeout = 5; } if (conn->recv_timeout && !conn->ping_timeout) { - iscsi_conn_printk(KERN_ERR, conn, "invalid ping timeout of " - "zero. Using 5 seconds.\n"); + printk(KERN_ERR "iscsi: invalid ping timeout of zero " + "Using 5 seconds.\n"); conn->ping_timeout = 5; } @@ -2028,9 +2019,11 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) conn->stop_stage = 0; conn->tmf_state = TMF_INITIAL; session->age++; - if (session->age == 16) - session->age = 0; - break; + spin_unlock_bh(&session->lock); + + iscsi_unblock_session(session_to_cls(session)); + wake_up(&conn->ehwait); + return 0; case STOP_CONN_TERM: conn->stop_stage = 0; break; @@ -2039,8 +2032,6 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) } spin_unlock_bh(&session->lock); - iscsi_unblock_session(session_to_cls(session)); - wake_up(&conn->ehwait); return 0; } EXPORT_SYMBOL_GPL(iscsi_conn_start); @@ -2132,8 +2123,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, * flush queues. */ spin_lock_bh(&session->lock); - fail_all_commands(conn, -1, - STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR); + fail_all_commands(conn, -1); flush_control_queues(session, conn); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); @@ -2150,8 +2140,7 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) iscsi_start_session_recovery(session, conn, flag); break; default: - iscsi_conn_printk(KERN_ERR, conn, - "invalid stop flag %d\n", flag); + printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); } } EXPORT_SYMBOL_GPL(iscsi_conn_stop); diff --git a/trunk/drivers/scsi/mac_esp.c b/trunk/drivers/scsi/mac_esp.c new file mode 100644 index 000000000000..bcb49021b7e2 --- /dev/null +++ b/trunk/drivers/scsi/mac_esp.c @@ -0,0 +1,751 @@ +/* + * 68k mac 53c9[46] scsi driver + * + * copyright (c) 1998, David Weis weisd3458@uni.edu + * + * debugging on Quadra 800 and 660AV Michael Schmitz, Dave Kilzer 7/98 + * + * based loosely on cyber_esp.c + */ + +/* these are unused for now */ +#define myreadl(addr) (*(volatile unsigned int *) (addr)) +#define mywritel(b, addr) ((*(volatile unsigned int *) (addr)) = (b)) + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +/* #define DEBUG_MAC_ESP */ + +extern void esp_handle(struct NCR_ESP *esp); +extern void mac_esp_intr(int irq, void *dev_id); + +static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP * esp); +static void dma_init_read(struct NCR_ESP * esp, char * vaddress, int length); +static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length); +static void dma_ints_off(struct NCR_ESP * esp); +static void dma_ints_on(struct NCR_ESP * esp); +static int dma_irq_p(struct NCR_ESP * esp); +static int dma_irq_p_quick(struct NCR_ESP * esp); +static void dma_led_off(struct NCR_ESP * esp); +static void dma_led_on(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP * esp, __u32 addr, int count, int write); +static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int write); + +static int esp_dafb_dma_irq_p(struct NCR_ESP * espdev); +static int esp_iosb_dma_irq_p(struct NCR_ESP * espdev); + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are transferred to the ESP chip + * via PIO. + */ + +static int esp_initialized = 0; + +static int setup_num_esps = -1; +static int setup_disconnect = -1; +static int setup_nosync = -1; +static int setup_can_queue = -1; +static int setup_cmd_per_lun = -1; +static int setup_sg_tablesize = -1; +#ifdef SUPPORT_TAGS +static int setup_use_tagged_queuing = -1; +#endif +static int setup_hostid = -1; + +/* + * Experimental ESP inthandler; check macints.c to make sure dev_id is + * set up properly! + */ + +void mac_esp_intr(int irq, void *dev_id) +{ + struct NCR_ESP *esp = (struct NCR_ESP *) dev_id; + int irq_p = 0; + + /* Handle the one ESP interrupt showing at this IRQ level. */ + if(((esp)->irq & 0xff) == irq) { + /* + * Debug .. + */ + irq_p = esp->dma_irq_p(esp); + printk("mac_esp: irq_p %x current %p disconnected %p\n", + irq_p, esp->current_SC, esp->disconnected_SC); + + /* + * Mac: if we're here, it's an ESP interrupt for sure! + */ + if((esp->current_SC || esp->disconnected_SC)) { + esp->dma_ints_off(esp); + + ESPIRQ(("I%d(", esp->esp_id)); + esp_handle(esp); + ESPIRQ((")")); + + esp->dma_ints_on(esp); + } + } +} + +/* + * Debug hooks; use for playing with the interrupt flag testing and interrupt + * acknowledge on the various machines + */ + +void scsi_esp_polled(int irq, void *dev_id) +{ + if (esp_initialized == 0) + return; + + mac_esp_intr(irq, dev_id); +} + +void fake_intr(int irq, void *dev_id) +{ +#ifdef DEBUG_MAC_ESP + printk("mac_esp: got irq\n"); +#endif + + mac_esp_intr(irq, dev_id); +} + +irqreturn_t fake_drq(int irq, void *dev_id) +{ + printk("mac_esp: got drq\n"); + return IRQ_HANDLED; +} + +#define DRIVER_SETUP + +/* + * Function : mac_esp_setup(char *str) + * + * Purpose : booter command line initialization of the overrides array, + * + * Inputs : str - parameters, separated by commas. + * + * Currently unused in the new driver; need to add settable parameters to the + * detect function. + * + */ + +static int __init mac_esp_setup(char *str) { +#ifdef DRIVER_SETUP + /* Format of mac53c9x parameter is: + * mac53c9x=,,,,,,, + * Negative values mean don't change. + */ + + char *this_opt; + long opt; + + this_opt = strsep (&str, ","); + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + if (opt >= 0 && opt <= 2) + setup_num_esps = opt; + else if (opt > 2) + printk( "mac_esp_setup: invalid number of hosts %ld !\n", opt ); + + this_opt = strsep (&str, ","); + } + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + if (opt > 0) + setup_disconnect = opt; + + this_opt = strsep (&str, ","); + } + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + if (opt >= 0) + setup_nosync = opt; + + this_opt = strsep (&str, ","); + } + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + if (opt > 0) + setup_can_queue = opt; + + this_opt = strsep (&str, ","); + } + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + if (opt > 0) + setup_cmd_per_lun = opt; + + this_opt = strsep (&str, ","); + } + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + if (opt >= 0) { + setup_sg_tablesize = opt; + /* Must be <= SG_ALL (255) */ + if (setup_sg_tablesize > SG_ALL) + setup_sg_tablesize = SG_ALL; + } + + this_opt = strsep (&str, ","); + } + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + + /* Must be between 0 and 7 */ + if (opt >= 0 && opt <= 7) + setup_hostid = opt; + else if (opt > 7) + printk( "mac_esp_setup: invalid host ID %ld !\n", opt); + + this_opt = strsep (&str, ","); + } +#ifdef SUPPORT_TAGS + if(this_opt) { + opt = simple_strtol( this_opt, NULL, 0 ); + if (opt >= 0) + setup_use_tagged_queuing = !!opt; + } +#endif +#endif + return 1; +} + +__setup("mac53c9x=", mac_esp_setup); + + +/* + * ESP address 'detection' + */ + +unsigned long get_base(int chip_num) +{ + /* + * using the chip_num and mac model, figure out where the + * chips are mapped + */ + + unsigned long io_base = 0x50f00000; + unsigned int second_offset = 0x402; + unsigned long scsi_loc = 0; + + switch (macintosh_config->scsi_type) { + + /* 950, 900, 700 */ + case MAC_SCSI_QUADRA2: + scsi_loc = io_base + 0xf000 + ((chip_num == 0) ? 0 : second_offset); + break; + + /* av's */ + case MAC_SCSI_QUADRA3: + scsi_loc = io_base + 0x18000 + ((chip_num == 0) ? 0 : second_offset); + break; + + /* most quadra/centris models are like this */ + case MAC_SCSI_QUADRA: + scsi_loc = io_base + 0x10000; + break; + + default: + printk("mac_esp: get_base: hit default!\n"); + scsi_loc = io_base + 0x10000; + break; + + } /* switch */ + + printk("mac_esp: io base at 0x%lx\n", scsi_loc); + + return scsi_loc; +} + +/* + * Model dependent ESP setup + */ + +int mac_esp_detect(struct scsi_host_template * tpnt) +{ + int quick = 0; + int chipnum, chipspresent = 0; +#if 0 + unsigned long timeout; +#endif + + if (esp_initialized > 0) + return -ENODEV; + + /* what do we have in this machine... */ + if (MACHW_PRESENT(MAC_SCSI_96)) { + chipspresent ++; + } + + if (MACHW_PRESENT(MAC_SCSI_96_2)) { + chipspresent ++; + } + + /* number of ESPs present ? */ + if (setup_num_esps >= 0) { + if (chipspresent >= setup_num_esps) + chipspresent = setup_num_esps; + else + printk("mac_esp_detect: num_hosts detected %d setup %d \n", + chipspresent, setup_num_esps); + } + + /* TODO: add disconnect / nosync flags */ + + /* setup variables */ + tpnt->can_queue = + (setup_can_queue > 0) ? setup_can_queue : 7; + tpnt->cmd_per_lun = + (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : 1; + tpnt->sg_tablesize = + (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_ALL; + + if (setup_hostid >= 0) + tpnt->this_id = setup_hostid; + else { + /* use 7 as default */ + tpnt->this_id = 7; + } + +#ifdef SUPPORT_TAGS + if (setup_use_tagged_queuing < 0) + setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING; +#endif + + for (chipnum = 0; chipnum < chipspresent; chipnum ++) { + struct NCR_ESP * esp; + + esp = esp_allocate(tpnt, NULL, 0); + esp->eregs = (struct ESP_regs *) get_base(chipnum); + + esp->dma_irq_p = &esp_dafb_dma_irq_p; + if (chipnum == 0) { + + if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) { + /* most machines except those below :-) */ + quick = 1; + esp->dma_irq_p = &esp_iosb_dma_irq_p; + } else if (macintosh_config->scsi_type == MAC_SCSI_QUADRA3) { + /* mostly av's */ + quick = 0; + } else { + /* q950, 900, 700 */ + quick = 1; + out_be32(0xf9800024, 0x1d1); + esp->dregs = (void *) 0xf9800024; + } + + } else { /* chipnum */ + + quick = 1; + out_be32(0xf9800028, 0x1d1); + esp->dregs = (void *) 0xf9800028; + + } /* chipnum == 0 */ + + /* use pio for command bytes; pio for message/data: TBI */ + esp->do_pio_cmds = 1; + + /* Set the command buffer */ + esp->esp_command = (volatile unsigned char*) cmd_buffer; + esp->esp_command_dvma = (__u32) cmd_buffer; + + /* various functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = NULL; + esp->dma_init_write = NULL; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + + esp->dma_ports_p = &dma_ports_p; + + + /* Optional functions */ + esp->dma_barrier = NULL; + esp->dma_drain = NULL; + esp->dma_invalidate = NULL; + esp->dma_irq_entry = NULL; + esp->dma_irq_exit = NULL; + esp->dma_led_on = NULL; + esp->dma_led_off = NULL; + esp->dma_poll = NULL; + esp->dma_reset = NULL; + + /* SCSI chip speed */ + /* below esp->cfreq = 40000000; */ + + + if (quick) { + /* 'quick' means there's handshake glue logic like in the 5380 case */ + esp->dma_setup = &dma_setup_quick; + } else { + esp->dma_setup = &dma_setup; + } + + if (chipnum == 0) { + + esp->irq = IRQ_MAC_SCSI; + + request_irq(IRQ_MAC_SCSI, esp_intr, 0, "Mac ESP SCSI", esp->ehost); +#if 0 /* conflicts with IOP ADB */ + request_irq(IRQ_MAC_SCSIDRQ, fake_drq, 0, "Mac ESP DRQ", esp->ehost); +#endif + + if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) { + esp->cfreq = 16500000; + } else { + esp->cfreq = 25000000; + } + + + } else { /* chipnum == 1 */ + + esp->irq = IRQ_MAC_SCSIDRQ; +#if 0 /* conflicts with IOP ADB */ + request_irq(IRQ_MAC_SCSIDRQ, esp_intr, 0, "Mac ESP SCSI 2", esp->ehost); +#endif + + esp->cfreq = 25000000; + + } + + if (quick) { + printk("esp: using quick version\n"); + } + + printk("esp: addr at 0x%p\n", esp->eregs); + + esp->scsi_id = 7; + esp->diff = 0; + + esp_initialize(esp); + + } /* for chipnum */ + + if (chipspresent) + printk("\nmac_esp: %d esp controllers found\n", chipspresent); + + esp_initialized = chipspresent; + + return chipspresent; +} + +static int mac_esp_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + +/* + * I've been wondering what this is supposed to do, for some time. Talking + * to Allen Briggs: These machines have an extra register someplace where the + * DRQ pin of the ESP can be monitored. That isn't useful for determining + * anything else (such as reselect interrupt or other magic) though. + * Maybe make the semantics should be changed like + * if (esp->current_SC) + * ... check DRQ flag ... + * else + * ... disconnected, check pending VIA interrupt ... + * + * There's a problem with using the dabf flag or mac_irq_pending() here: both + * seem to return 1 even though no interrupt is currently pending, resulting + * in esp_exec_cmd() holding off the next command, and possibly infinite loops + * in esp_intr(). + * Short term fix: just use esp_status & ESP_STAT_INTR here, as long as we + * use simple PIO. The DRQ status will be important when implementing pseudo + * DMA mode (set up ESP transfer count, return, do a batch of bytes in PIO or + * 'hardware handshake' mode upon DRQ). + * If you plan on changing this (i.e. to save the esp_status register access in + * favor of a VIA register access or a shadow register for the IFR), make sure + * to try a debug version of this first to monitor what registers would be a good + * indicator of the ESP interrupt. + */ + +static int esp_dafb_dma_irq_p(struct NCR_ESP * esp) +{ + unsigned int ret; + int sreg = esp_read(esp->eregs->esp_status); + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: esp_dafb_dma_irq_p dafb %d irq %d\n", + readl(esp->dregs), mac_irq_pending(IRQ_MAC_SCSI)); +#endif + + sreg &= ESP_STAT_INTR; + + /* + * maybe working; this is essentially what's used for iosb_dma_irq_p + */ + if (sreg) + return 1; + else + return 0; + + /* + * didn't work ... + */ +#if 0 + if (esp->current_SC) + ret = readl(esp->dregs) & 0x200; + else if (esp->disconnected_SC) + ret = 1; /* sreg ?? */ + else + ret = mac_irq_pending(IRQ_MAC_SCSI); + + return(ret); +#endif + +} + +/* + * See above: testing mac_irq_pending always returned 8 (SCSI IRQ) regardless + * of the actual ESP status. + */ + +static int esp_iosb_dma_irq_p(struct NCR_ESP * esp) +{ + int ret = mac_irq_pending(IRQ_MAC_SCSI) || mac_irq_pending(IRQ_MAC_SCSIDRQ); + int sreg = esp_read(esp->eregs->esp_status); + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_irq_p drq %d irq %d sreg %x curr %p disc %p\n", + mac_irq_pending(IRQ_MAC_SCSIDRQ), mac_irq_pending(IRQ_MAC_SCSI), + sreg, esp->current_SC, esp->disconnected_SC); +#endif + + sreg &= ESP_STAT_INTR; + + if (sreg) + return (sreg); + else + return 0; +} + +/* + * This seems to be OK for PIO at least ... usually 0 after PIO. + */ + +static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count) +{ + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma bytes sent = %x\n", fifo_count); +#endif + + return fifo_count; +} + +/* + * dma_can_transfer is used to switch between DMA and PIO, if DMA (pseudo) + * is ever implemented. Returning 0 here will use PIO. + */ + +static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd * sp) +{ + unsigned long sz = sp->SCp.this_residual; +#if 0 /* no DMA yet; make conditional */ + if (sz > 0x10000000) { + sz = 0x10000000; + } + printk("mac_esp: dma can transfer = 0lx%x\n", sz); +#else + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: pio to transfer = %ld\n", sz); +#endif + + sz = 0; +#endif + return sz; +} + +/* + * Not yet ... + */ + +static void dma_dump_state(struct NCR_ESP * esp) +{ +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_dump_state: called\n"); +#endif +#if 0 + ESPLOG(("esp%d: dma -- cond_reg<%02x>\n", + esp->esp_id, ((struct mac_dma_registers *) + (esp->dregs))->cond_reg)); +#endif +} + +/* + * DMA setup: should be used to set up the ESP transfer count for pseudo + * DMA transfers; need a DRQ transfer function to do the actual transfer + */ + +static void dma_init_read(struct NCR_ESP * esp, char * vaddress, int length) +{ + printk("mac_esp: dma_init_read\n"); +} + + +static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length) +{ + printk("mac_esp: dma_init_write\n"); +} + + +static void dma_ints_off(struct NCR_ESP * esp) +{ + disable_irq(esp->irq); +} + + +static void dma_ints_on(struct NCR_ESP * esp) +{ + enable_irq(esp->irq); +} + +/* + * generic dma_irq_p(), unused + */ + +static int dma_irq_p(struct NCR_ESP * esp) +{ + int i = esp_read(esp->eregs->esp_status); + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_irq_p status %d\n", i); +#endif + + return (i & ESP_STAT_INTR); +} + +static int dma_irq_p_quick(struct NCR_ESP * esp) +{ + /* + * Copied from iosb_dma_irq_p() + */ + int ret = mac_irq_pending(IRQ_MAC_SCSI) || mac_irq_pending(IRQ_MAC_SCSIDRQ); + int sreg = esp_read(esp->eregs->esp_status); + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_irq_p drq %d irq %d sreg %x curr %p disc %p\n", + mac_irq_pending(IRQ_MAC_SCSIDRQ), mac_irq_pending(IRQ_MAC_SCSI), + sreg, esp->current_SC, esp->disconnected_SC); +#endif + + sreg &= ESP_STAT_INTR; + + if (sreg) + return (sreg); + else + return 0; + +} + +static void dma_led_off(struct NCR_ESP * esp) +{ +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_led_off: called\n"); +#endif +} + + +static void dma_led_on(struct NCR_ESP * esp) +{ +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_led_on: called\n"); +#endif +} + + +static int dma_ports_p(struct NCR_ESP * esp) +{ + return 0; +} + + +static void dma_setup(struct NCR_ESP * esp, __u32 addr, int count, int write) +{ + +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_setup\n"); +#endif + + if (write) { + dma_init_read(esp, (char *) addr, count); + } else { + dma_init_write(esp, (char *) addr, count); + } +} + + +static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int write) +{ +#ifdef DEBUG_MAC_ESP + printk("mac_esp: dma_setup_quick\n"); +#endif +} + +static struct scsi_host_template driver_template = { + .proc_name = "mac_esp", + .name = "Mac 53C9x SCSI", + .detect = mac_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = mac_esp_release, + .info = esp_info, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/mca_53c9x.c b/trunk/drivers/scsi/mca_53c9x.c new file mode 100644 index 000000000000..d693d0f21395 --- /dev/null +++ b/trunk/drivers/scsi/mca_53c9x.c @@ -0,0 +1,520 @@ +/* mca_53c9x.c: Driver for the SCSI adapter found on NCR 35xx + * (and maybe some other) Microchannel machines + * + * Code taken mostly from Cyberstorm SCSI drivers + * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) + * + * Hacked to work with the NCR MCA stuff by Tymm Twillman (tymm@computer.org) + * + * The CyberStorm SCSI driver (and this driver) is based on David S. Miller's + * ESP driver * for the Sparc computers. + * + * Special thanks to Ken Stewart at Symbios (LSI) for helping with info on + * the 86C01. I was on the brink of going ga-ga... + * + * Also thanks to Jesper Skov for helping me with info on how the Amiga + * does things... + */ + +/* + * This is currently only set up to use one 53c9x card at a time; it could be + * changed fairly easily to detect/use more than one, but I'm not too sure how + * many cards that use the 53c9x on MCA systems there are (if, in fact, there + * are cards that use them, other than the one built into some NCR systems)... + * If anyone requests this, I'll throw it in, otherwise it's not worth the + * effort. + */ + +/* + * Info on the 86C01 MCA interface chip at the bottom, if you care enough to + * look. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include + +/* + * From ibmmca.c (IBM scsi controller card driver) -- used for turning PS2 disk + * activity LED on and off + */ + +#define PS2_SYS_CTR 0x92 + +/* Ports the ncr's 53c94 can be put at; indexed by pos register value */ + +#define MCA_53C9X_IO_PORTS { \ + 0x0000, 0x0240, 0x0340, 0x0400, \ + 0x0420, 0x3240, 0x8240, 0xA240, \ + } + +/* + * Supposedly there were some cards put together with the 'c9x and 86c01. If + * they have different ID's from the ones on the 3500 series machines, + * you can add them here and hopefully things will work out. + */ + +#define MCA_53C9X_IDS { \ + 0x7F4C, \ + 0x0000, \ + } + +static int dma_bytes_sent(struct NCR_ESP *, int); +static int dma_can_transfer(struct NCR_ESP *, Scsi_Cmnd *); +static void dma_dump_state(struct NCR_ESP *); +static void dma_init_read(struct NCR_ESP *, __u32, int); +static void dma_init_write(struct NCR_ESP *, __u32, int); +static void dma_ints_off(struct NCR_ESP *); +static void dma_ints_on(struct NCR_ESP *); +static int dma_irq_p(struct NCR_ESP *); +static int dma_ports_p(struct NCR_ESP *); +static void dma_setup(struct NCR_ESP *, __u32, int, int); +static void dma_led_on(struct NCR_ESP *); +static void dma_led_off(struct NCR_ESP *); + +/* This is where all commands are put before they are trasfered to the + * 53c9x via PIO. + */ + +static volatile unsigned char cmd_buffer[16]; + +/* + * We keep the structure that is used to access the registers on the 53c9x + * here. + */ + +static struct ESP_regs eregs; + +/***************************************************************** Detection */ +static int mca_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + static int io_port_by_pos[] = MCA_53C9X_IO_PORTS; + int mca_53c9x_ids[] = MCA_53C9X_IDS; + int *id_to_check = mca_53c9x_ids; + int slot; + int pos[3]; + unsigned int tmp_io_addr; + unsigned char tmp_byte; + + + if (!MCA_bus) + return 0; + + while (*id_to_check) { + if ((slot = mca_find_adapter(*id_to_check, 0)) != + MCA_NOTFOUND) + { + esp = esp_allocate(tpnt, NULL, 0); + + pos[0] = mca_read_stored_pos(slot, 2); + pos[1] = mca_read_stored_pos(slot, 3); + pos[2] = mca_read_stored_pos(slot, 4); + + esp->eregs = &eregs; + + /* + * IO port base is given in the first (non-ID) pos + * register, like so: + * + * Bits 3 2 1 IO base + * ---------------------------- + * 0 0 0 + * 0 0 1 0x0240 + * 0 1 0 0x0340 + * 0 1 1 0x0400 + * 1 0 0 0x0420 + * 1 0 1 0x3240 + * 1 1 0 0x8240 + * 1 1 1 0xA240 + */ + + tmp_io_addr = + io_port_by_pos[(pos[0] & 0x0E) >> 1]; + + esp->eregs->io_addr = tmp_io_addr + 0x10; + + if (esp->eregs->io_addr == 0x0000) { + printk("Adapter is disabled.\n"); + break; + } + + /* + * IRQ is specified in bits 4 and 5: + * + * Bits 4 5 IRQ + * ----------------------- + * 0 0 3 + * 0 1 5 + * 1 0 7 + * 1 1 9 + */ + + esp->irq = ((pos[0] & 0x30) >> 3) + 3; + + /* + * DMA channel is in the low 3 bits of the second + * POS register + */ + + esp->dma = pos[1] & 7; + esp->slot = slot; + + if (request_irq(esp->irq, esp_intr, 0, + "NCR 53c9x SCSI", esp->ehost)) + { + printk("Unable to request IRQ %d.\n", esp->irq); + esp_deallocate(esp); + scsi_unregister(esp->ehost); + return 0; + } + + if (request_dma(esp->dma, "NCR 53c9x SCSI")) { + printk("Unable to request DMA channel %d.\n", + esp->dma); + free_irq(esp->irq, esp_intr); + esp_deallocate(esp); + scsi_unregister(esp->ehost); + return 0; + } + + request_region(tmp_io_addr, 32, "NCR 53c9x SCSI"); + + /* + * 86C01 handles DMA, IO mode, from address + * (base + 0x0a) + */ + + mca_disable_dma(esp->dma); + mca_set_dma_io(esp->dma, tmp_io_addr + 0x0a); + mca_enable_dma(esp->dma); + + /* Tell the 86C01 to give us interrupts */ + + tmp_byte = inb(tmp_io_addr + 0x02) | 0x40; + outb(tmp_byte, tmp_io_addr + 0x02); + + /* + * Scsi ID -- general purpose register, hi + * 2 bits; add 4 to this number to get the + * ID + */ + + esp->scsi_id = ((pos[2] & 0xC0) >> 6) + 4; + + /* Do command transfer with programmed I/O */ + + esp->do_pio_cmds = 1; + + /* Required functions */ + + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + + esp->dma_barrier = NULL; + esp->dma_drain = NULL; + esp->dma_invalidate = NULL; + esp->dma_irq_entry = NULL; + esp->dma_irq_exit = NULL; + esp->dma_led_on = dma_led_on; + esp->dma_led_off = dma_led_off; + esp->dma_poll = NULL; + esp->dma_reset = NULL; + + /* Set the command buffer */ + + esp->esp_command = (volatile unsigned char*) + cmd_buffer; + esp->esp_command_dvma = isa_virt_to_bus(cmd_buffer); + + /* SCSI chip speed */ + + esp->cfreq = 25000000; + + /* Differential SCSI? I think not. */ + + esp->diff = 0; + + esp_initialize(esp); + + printk(" Adapter found in slot %2d: io port 0x%x " + "irq %d dma channel %d\n", slot + 1, tmp_io_addr, + esp->irq, esp->dma); + + mca_set_adapter_name(slot, "NCR 53C9X SCSI Adapter"); + mca_mark_as_used(slot); + + break; + } + + id_to_check++; + } + + return esps_in_use; +} + + +/******************************************************************* Release */ + +static int mca_esp_release(struct Scsi_Host *host) +{ + struct NCR_ESP *esp = (struct NCR_ESP *)host->hostdata; + unsigned char tmp_byte; + + esp_deallocate(esp); + /* + * Tell the 86C01 to stop sending interrupts + */ + + tmp_byte = inb(esp->eregs->io_addr - 0x0E); + tmp_byte &= ~0x40; + outb(tmp_byte, esp->eregs->io_addr - 0x0E); + + free_irq(esp->irq, esp_intr); + free_dma(esp->dma); + + mca_mark_as_unused(esp->slot); + + return 0; +} + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Ask the 53c9x. It knows. */ + + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + /* + * The MCA dma channels can only do up to 128K bytes at a time. + * (16 bit mode) + */ + + unsigned long sz = sp->SCp.this_residual; + if(sz > 0x20000) + sz = 0x20000; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ + /* + * Doesn't quite match up to the other drivers, but we do what we + * can. + */ + + ESPLOG(("esp%d: dma channel <%d>\n", esp->esp_id, esp->dma)); + ESPLOG(("bytes left to dma: %d\n", mca_get_dma_residue(esp->dma))); +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) +{ + unsigned long flags; + + + save_flags(flags); + cli(); + + mca_disable_dma(esp->dma); + mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_16 | + MCA_DMA_MODE_IO); + mca_set_dma_addr(esp->dma, addr); + mca_set_dma_count(esp->dma, length / 2); /* !!! */ + mca_enable_dma(esp->dma); + + restore_flags(flags); +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) +{ + unsigned long flags; + + + save_flags(flags); + cli(); + + mca_disable_dma(esp->dma); + mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_WRITE | + MCA_DMA_MODE_16 | MCA_DMA_MODE_IO); + mca_set_dma_addr(esp->dma, addr); + mca_set_dma_count(esp->dma, length / 2); /* !!! */ + mca_enable_dma(esp->dma); + + restore_flags(flags); +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + /* + * Tell the 'C01 to shut up. All interrupts are routed through it. + */ + + outb(inb(esp->eregs->io_addr - 0x0E) & ~0x40, + esp->eregs->io_addr - 0x0E); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + /* + * Ok. You can speak again. + */ + + outb(inb(esp->eregs->io_addr - 0x0E) | 0x40, + esp->eregs->io_addr - 0x0E); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + /* + * DaveM says that this should return a "yes" if there is an interrupt + * or a DMA error occurred. I copied the Amiga driver's semantics, + * though, because it seems to work and we can't really tell if + * a DMA error happened. This gives the "yes" if the scsi chip + * is sending an interrupt and no DMA activity is taking place + */ + + return (!(inb(esp->eregs->io_addr - 0x04) & 1) && + !(inb(esp->eregs->io_addr - 0x04) & 2) ); +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + /* + * Check to see if interrupts are enabled on the 'C01 (in case abort + * is entered multiple times, so we only do the abort once) + */ + + return (inb(esp->eregs->io_addr - 0x0E) & 0x40) ? 1:0; +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + if(write){ + dma_init_write(esp, addr, count); + } else { + dma_init_read(esp, addr, count); + } +} + +/* + * These will not play nicely with other disk controllers that try to use the + * disk active LED... but what can you do? Don't answer that. + * + * Stolen shamelessly from ibmmca.c -- IBM Microchannel SCSI adapter driver + * + */ + +static void dma_led_on(struct NCR_ESP *esp) +{ + outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); +} + +static void dma_led_off(struct NCR_ESP *esp) +{ + outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); +} + +static struct scsi_host_template driver_template = { + .proc_name = "mca_53c9x", + .name = "NCR 53c9x SCSI", + .detect = mca_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = mca_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .unchecked_isa_dma = 1, + .use_clustering = DISABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +/* + * OK, here's the goods I promised. The NCR 86C01 is an MCA interface chip + * that handles enabling/diabling IRQ, dma interfacing, IO port selection + * and other fun stuff. It takes up 16 addresses, and the chip it is + * connnected to gets the following 16. Registers are as follows: + * + * Offsets 0-1 : Card ID + * + * Offset 2 : Mode enable register -- + * Bit 7 : Data Word width (1 = 16, 0 = 8) + * Bit 6 : IRQ enable (1 = enabled) + * Bits 5,4 : IRQ select + * 0 0 : IRQ 3 + * 0 1 : IRQ 5 + * 1 0 : IRQ 7 + * 1 1 : IRQ 9 + * Bits 3-1 : Base Address + * 0 0 0 : + * 0 0 1 : 0x0240 + * 0 1 0 : 0x0340 + * 0 1 1 : 0x0400 + * 1 0 0 : 0x0420 + * 1 0 1 : 0x3240 + * 1 1 0 : 0x8240 + * 1 1 1 : 0xA240 + * Bit 0 : Card enable (1 = enabled) + * + * Offset 3 : DMA control register -- + * Bit 7 : DMA enable (1 = enabled) + * Bits 6,5 : Preemt Count Select (transfers to complete after + * 'C01 has been preempted on MCA bus) + * 0 0 : 0 + * 0 1 : 1 + * 1 0 : 3 + * 1 1 : 7 + * (all these wacky numbers; I'm sure there's a reason somewhere) + * Bit 4 : Fairness enable (1 = fair bus priority) + * Bits 3-0 : Arbitration level (0-15 consecutive) + * + * Offset 4 : General purpose register + * Bits 7-3 : User definable (here, 7,6 are SCSI ID) + * Bits 2-0 : reserved + * + * Offset 10 : DMA decode register (used for IO based DMA; also can do + * PIO through this port) + * + * Offset 12 : Status + * Bits 7-2 : reserved + * Bit 1 : DMA pending (1 = pending) + * Bit 0 : IRQ pending (0 = pending) + * + * Exciting, huh? + * + */ diff --git a/trunk/drivers/scsi/oktagon_esp.c b/trunk/drivers/scsi/oktagon_esp.c new file mode 100644 index 000000000000..8e5eadbd5c51 --- /dev/null +++ b/trunk/drivers/scsi/oktagon_esp.c @@ -0,0 +1,606 @@ +/* + * Oktagon_esp.c -- Driver for bsc Oktagon + * + * Written by Carsten Pluntke 1998 + * + * Based on cyber_esp.c + */ + + +#if defined(CONFIG_AMIGA) || defined(CONFIG_APUS) +#define USE_BOTTOM_HALF +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "scsi.h" +#include +#include "NCR53C9x.h" + +#include +#include +#include +#include + +#ifdef USE_BOTTOM_HALF +#include +#include +#endif + +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define OKTAGON_ESP_ADDR 0x03000 +#define OKTAGON_DMA_ADDR 0x01000 + + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static void dma_led_off(struct NCR_ESP *esp); +static void dma_led_on(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); + +static void dma_irq_exit(struct NCR_ESP *esp); +static void dma_invalidate(struct NCR_ESP *esp); + +static void dma_mmu_get_scsi_one(struct NCR_ESP *,Scsi_Cmnd *); +static void dma_mmu_get_scsi_sgl(struct NCR_ESP *,Scsi_Cmnd *); +static void dma_mmu_release_scsi_one(struct NCR_ESP *,Scsi_Cmnd *); +static void dma_mmu_release_scsi_sgl(struct NCR_ESP *,Scsi_Cmnd *); +static void dma_advance_sg(Scsi_Cmnd *); +static int oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x); + +#ifdef USE_BOTTOM_HALF +static void dma_commit(struct work_struct *unused); + +long oktag_to_io(long *paddr, long *addr, long len); +long oktag_from_io(long *addr, long *paddr, long len); + +static DECLARE_WORK(tq_fake_dma, dma_commit); + +#define DMA_MAXTRANSFER 0x8000 + +#else + +/* + * No bottom half. Use transfer directly from IRQ. Find a narrow path + * between too much IRQ overhead and clogging the IRQ for too long. + */ + +#define DMA_MAXTRANSFER 0x1000 + +#endif + +static struct notifier_block oktagon_notifier = { + oktagon_notify_reboot, + NULL, + 0 +}; + +static long *paddress; +static long *address; +static long len; +static long dma_on; +static int direction; +static struct NCR_ESP *current_esp; + + +static volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are trasfered to the ESP chip + * via PIO. + */ + +/***************************************************************** Detection */ +int oktagon_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct zorro_dev *z = NULL; + unsigned long address; + struct ESP_regs *eregs; + + while ((z = zorro_find_device(ZORRO_PROD_BSC_OKTAGON_2008, z))) { + unsigned long board = z->resource.start; + if (request_mem_region(board+OKTAGON_ESP_ADDR, + sizeof(struct ESP_regs), "NCR53C9x")) { + /* + * It is a SCSI controller. + * Hardwire Host adapter to SCSI ID 7 + */ + + address = (unsigned long)ZTWO_VADDR(board); + eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR); + + /* This line was 5 lines lower */ + esp = esp_allocate(tpnt, (void *)board + OKTAGON_ESP_ADDR, 0); + + /* we have to shift the registers only one bit for oktagon */ + esp->shift = 1; + + esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); + udelay(5); + if (esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)) + return 0; /* Bail out if address did not hold data */ + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = 0; + esp->dma_invalidate = &dma_invalidate; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = &dma_irq_exit; + esp->dma_led_on = &dma_led_on; + esp->dma_led_off = &dma_led_off; + esp->dma_poll = 0; + esp->dma_reset = 0; + + esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; + esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one; + esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl; + esp->dma_advance_sg = &dma_advance_sg; + + /* SCSI chip speed */ + /* Looking at the quartz of the SCSI board... */ + esp->cfreq = 25000000; + + /* The DMA registers on the CyberStorm are mapped + * relative to the device (i.e. in the same Zorro + * I/O block). + */ + esp->dregs = (void *)(address + OKTAGON_DMA_ADDR); + + paddress = (long *) esp->dregs; + + /* ESP register base */ + esp->eregs = eregs; + + /* Set the command buffer */ + esp->esp_command = (volatile unsigned char*) cmd_buffer; + + /* Yes, the virtual address. See below. */ + esp->esp_command_dvma = (__u32) cmd_buffer; + + esp->irq = IRQ_AMIGA_PORTS; + request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, + "BSC Oktagon SCSI", esp->ehost); + + /* Figure out our scsi ID on the bus */ + esp->scsi_id = 7; + + /* We don't have a differential SCSI-bus. */ + esp->diff = 0; + + esp_initialize(esp); + + printk("ESP_Oktagon Driver 1.1" +#ifdef USE_BOTTOM_HALF + " [BOTTOM_HALF]" +#else + " [IRQ]" +#endif + " registered.\n"); + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,esps_in_use); + esps_running = esps_in_use; + current_esp = esp; + register_reboot_notifier(&oktagon_notifier); + return esps_in_use; + } + } + return 0; +} + + +/* + * On certain configurations the SCSI equipment gets confused on reboot, + * so we have to reset it then. + */ + +static int +oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x) +{ + struct NCR_ESP *esp; + + if((code == SYS_DOWN || code == SYS_HALT) && (esp = current_esp)) + { + esp_bootup_reset(esp,esp->eregs); + udelay(500); /* Settle time. Maybe unnecessary. */ + } + return NOTIFY_DONE; +} + + + +#ifdef USE_BOTTOM_HALF + + +/* + * The bsc Oktagon controller has no real DMA, so we have to do the 'DMA + * transfer' in the interrupt (Yikes!) or use a bottom half to not to clutter + * IRQ's for longer-than-good. + * + * FIXME + * BIG PROBLEM: 'len' is usually the buffer length, not the expected length + * of the data. So DMA may finish prematurely, further reads lead to + * 'machine check' on APUS systems (don't know about m68k systems, AmigaOS + * deliberately ignores the bus faults) and a normal copy-loop can't + * be exited prematurely just at the right moment by the dma_invalidate IRQ. + * So do it the hard way, write an own copier in assembler and + * catch the exception. + * -- Carsten + */ + + +static void dma_commit(struct work_struct *unused) +{ + long wait,len2,pos; + struct NCR_ESP *esp; + + ESPDATA(("Transfer: %ld bytes, Address 0x%08lX, Direction: %d\n", + len,(long) address,direction)); + dma_ints_off(current_esp); + + pos = 0; + wait = 1; + if(direction) /* write? (memory to device) */ + { + while(len > 0) + { + len2 = oktag_to_io(paddress, address+pos, len); + if(!len2) + { + if(wait > 1000) + { + printk("Expedited DMA exit (writing) %ld\n",len); + break; + } + mdelay(wait); + wait *= 2; + } + pos += len2; + len -= len2*sizeof(long); + } + } else { + while(len > 0) + { + len2 = oktag_from_io(address+pos, paddress, len); + if(!len2) + { + if(wait > 1000) + { + printk("Expedited DMA exit (reading) %ld\n",len); + break; + } + mdelay(wait); + wait *= 2; + } + pos += len2; + len -= len2*sizeof(long); + } + } + + /* to make esp->shift work */ + esp=current_esp; + +#if 0 + len2 = (esp_read(current_esp->eregs->esp_tclow) & 0xff) | + ((esp_read(current_esp->eregs->esp_tcmed) & 0xff) << 8); + + /* + * Uh uh. If you see this, len and transfer count registers were out of + * sync. That means really serious trouble. + */ + + if(len2) + printk("Eeeek!! Transfer count still %ld!\n",len2); +#endif + + /* + * Normally we just need to exit and wait for the interrupt to come. + * But at least one device (my Microtek ScanMaker 630) regularly mis- + * calculates the bytes it should send which is really ugly because + * it locks up the SCSI bus if not accounted for. + */ + + if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR)) + { + long len = 100; + long trash[10]; + + /* + * Interrupt bit was not set. Either the device is just plain lazy + * so we give it a 10 ms chance or... + */ + while(len-- && (!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR))) + udelay(100); + + + if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR)) + { + /* + * So we think that the transfer count is out of sync. Since we + * have all we want we are happy and can ditch the trash. + */ + + len = DMA_MAXTRANSFER; + + while(len-- && (!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR))) + oktag_from_io(trash,paddress,2); + + if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR)) + { + /* + * Things really have gone wrong. If we leave the system in that + * state, the SCSI bus is locked forever. I hope that this will + * turn the system in a more or less running state. + */ + printk("Device is bolixed, trying bus reset...\n"); + esp_bootup_reset(current_esp,current_esp->eregs); + } + } + } + + ESPDATA(("Transfer_finale: do_data_finale should come\n")); + + len = 0; + dma_on = 0; + dma_ints_on(current_esp); +} + +#endif + +/************************************************************* DMA Functions */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + /* Since the CyberStorm DMA is fully dedicated to the ESP chip, + * the number of bytes sent (to the ESP chip) equals the number + * of bytes in the FIFO - there is no buffering in the DMA controller. + * XXXX Do I read this right? It is from host to ESP, right? + */ + return fifo_count; +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + unsigned long sz = sp->SCp.this_residual; + if(sz > DMA_MAXTRANSFER) + sz = DMA_MAXTRANSFER; + return sz; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ +} + +/* + * What the f$@& is this? + * + * Some SCSI devices (like my Microtek ScanMaker 630 scanner) want to transfer + * more data than requested. How much? Dunno. So ditch the bogus data into + * the sink, hoping the device will advance to the next phase sooner or later. + * + * -- Carsten + */ + +static long oktag_eva_buffer[16]; /* The data sink */ + +static void oktag_check_dma(void) +{ + struct NCR_ESP *esp; + + esp=current_esp; + if(!len) + { + address = oktag_eva_buffer; + len = 2; + /* esp_do_data sets them to zero like len */ + esp_write(current_esp->eregs->esp_tclow,2); + esp_write(current_esp->eregs->esp_tcmed,0); + } +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) +{ + /* Zorro is noncached, everything else done using processor. */ + /* cache_clear(addr, length); */ + + if(dma_on) + panic("dma_init_read while dma process is initialized/running!\n"); + direction = 0; + address = (long *) vaddress; + current_esp = esp; + len = length; + oktag_check_dma(); + dma_on = 1; +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length) +{ + /* cache_push(addr, length); */ + + if(dma_on) + panic("dma_init_write while dma process is initialized/running!\n"); + direction = 1; + address = (long *) vaddress; + current_esp = esp; + len = length; + oktag_check_dma(); + dma_on = 1; +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(esp->irq); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(esp->irq); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + /* It's important to check the DMA IRQ bit in the correct way! */ + return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR); +} + +static void dma_led_off(struct NCR_ESP *esp) +{ +} + +static void dma_led_on(struct NCR_ESP *esp) +{ +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ + return ((amiga_custom.intenar) & IF_PORTS); +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if(write){ + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +/* + * IRQ entry when DMA transfer is ready to be started + */ + +static void dma_irq_exit(struct NCR_ESP *esp) +{ +#ifdef USE_BOTTOM_HALF + if(dma_on) + { + schedule_work(&tq_fake_dma); + } +#else + while(len && !dma_irq_p(esp)) + { + if(direction) + *paddress = *address++; + else + *address++ = *paddress; + len -= (sizeof(long)); + } + len = 0; + dma_on = 0; +#endif +} + +/* + * IRQ entry when DMA has just finished + */ + +static void dma_invalidate(struct NCR_ESP *esp) +{ +} + +/* + * Since the processor does the data transfer we have to use the custom + * mmu interface to pass the virtual address, not the physical. + */ + +void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + sp->SCp.ptr = + sp->request_buffer; +} + +void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + sp->SCp.ptr = sg_virt(sp->SCp.buffer); +} + +void dma_mmu_release_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ +} + +void dma_mmu_release_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ +} + +void dma_advance_sg(Scsi_Cmnd *sp) +{ + sp->SCp.ptr = sg_virt(sp->SCp.buffer); +} + + +#define HOSTS_C + +int oktagon_esp_release(struct Scsi_Host *instance) +{ +#ifdef MODULE + unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; + esp_release(); + release_mem_region(address, sizeof(struct ESP_regs)); + free_irq(IRQ_AMIGA_PORTS, esp_intr); + unregister_reboot_notifier(&oktagon_notifier); +#endif + return 1; +} + + +static struct scsi_host_template driver_template = { + .proc_name = "esp-oktagon", + .proc_info = &esp_proc_info, + .name = "BSC Oktagon SCSI", + .detect = oktagon_esp_detect, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .release = oktagon_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/oktagon_io.S b/trunk/drivers/scsi/oktagon_io.S new file mode 100644 index 000000000000..8a7340b02707 --- /dev/null +++ b/trunk/drivers/scsi/oktagon_io.S @@ -0,0 +1,194 @@ +/* -*- mode: asm -*- + * Due to problems while transferring data I've put these routines as assembly + * code. + * Since I'm no PPC assembler guru, the code is just the assembler version of + +int oktag_to_io(long *paddr,long *addr,long len) +{ + long *addr2 = addr; + for(len=(len+sizeof(long)-1)/sizeof(long);len--;) + *paddr = *addr2++; + return addr2 - addr; +} + +int oktag_from_io(long *addr,long *paddr,long len) +{ + long *addr2 = addr; + for(len=(len+sizeof(long)-1)/sizeof(long);len--;) + *addr2++ = *paddr; + return addr2 - addr; +} + + * assembled using gcc -O2 -S, with two exception catch points where data + * is moved to/from the IO register. + */ + + +#ifdef CONFIG_APUS + + .file "oktagon_io.c" + +gcc2_compiled.: +/* + .section ".text" +*/ + .align 2 + .globl oktag_to_io + .type oktag_to_io,@function +oktag_to_io: + addi 5,5,3 + srwi 5,5,2 + cmpwi 1,5,0 + mr 9,3 + mr 3,4 + addi 5,5,-1 + bc 12,6,.L3 +.L5: + cmpwi 1,5,0 + lwz 0,0(3) + addi 3,3,4 + addi 5,5,-1 +exp1: stw 0,0(9) + bc 4,6,.L5 +.L3: +ret1: subf 3,4,3 + srawi 3,3,2 + blr +.Lfe1: + .size oktag_to_io,.Lfe1-oktag_to_io + .align 2 + .globl oktag_from_io + .type oktag_from_io,@function +oktag_from_io: + addi 5,5,3 + srwi 5,5,2 + cmpwi 1,5,0 + mr 9,3 + addi 5,5,-1 + bc 12,6,.L9 +.L11: + cmpwi 1,5,0 +exp2: lwz 0,0(4) + addi 5,5,-1 + stw 0,0(3) + addi 3,3,4 + bc 4,6,.L11 +.L9: +ret2: subf 3,9,3 + srawi 3,3,2 + blr +.Lfe2: + .size oktag_from_io,.Lfe2-oktag_from_io + .ident "GCC: (GNU) egcs-2.90.29 980515 (egcs-1.0.3 release)" + +/* + * Exception table. + * Second longword shows where to jump when an exception at the addr the first + * longword is pointing to is caught. + */ + +.section __ex_table,"a" + .align 2 +oktagon_except: + .long exp1,ret1 + .long exp2,ret2 + +#else + +/* +The code which follows is for 680x0 based assembler and is meant for +Linux/m68k. It was created by cross compiling the code using the +instructions given above. I then added the four labels used in the +exception handler table at the bottom of this file. +- Kevin +*/ + +#ifdef CONFIG_AMIGA + + .file "oktagon_io.c" + .version "01.01" +gcc2_compiled.: +.text + .align 2 +.globl oktag_to_io + .type oktag_to_io,@function +oktag_to_io: + link.w %a6,#0 + move.l %d2,-(%sp) + move.l 8(%a6),%a1 + move.l 12(%a6),%d1 + move.l %d1,%a0 + move.l 16(%a6),%d0 + addq.l #3,%d0 + lsr.l #2,%d0 + subq.l #1,%d0 + moveq.l #-1,%d2 + cmp.l %d0,%d2 + jbeq .L3 +.L5: +exp1: + move.l (%a0)+,(%a1) + dbra %d0,.L5 + clr.w %d0 + subq.l #1,%d0 + jbcc .L5 +.L3: +ret1: + move.l %a0,%d0 + sub.l %d1,%d0 + asr.l #2,%d0 + move.l -4(%a6),%d2 + unlk %a6 + rts + +.Lfe1: + .size oktag_to_io,.Lfe1-oktag_to_io + .align 2 +.globl oktag_from_io + .type oktag_from_io,@function +oktag_from_io: + link.w %a6,#0 + move.l %d2,-(%sp) + move.l 8(%a6),%d1 + move.l 12(%a6),%a1 + move.l %d1,%a0 + move.l 16(%a6),%d0 + addq.l #3,%d0 + lsr.l #2,%d0 + subq.l #1,%d0 + moveq.l #-1,%d2 + cmp.l %d0,%d2 + jbeq .L9 +.L11: +exp2: + move.l (%a1),(%a0)+ + dbra %d0,.L11 + clr.w %d0 + subq.l #1,%d0 + jbcc .L11 +.L9: +ret2: + move.l %a0,%d0 + sub.l %d1,%d0 + asr.l #2,%d0 + move.l -4(%a6),%d2 + unlk %a6 + rts +.Lfe2: + .size oktag_from_io,.Lfe2-oktag_from_io + .ident "GCC: (GNU) 2.7.2.1" + +/* + * Exception table. + * Second longword shows where to jump when an exception at the addr the first + * longword is pointing to is caught. + */ + +.section __ex_table,"a" + .align 2 +oktagon_except: + .long exp1,ret1 + .long exp2,ret2 + +#endif +#endif diff --git a/trunk/drivers/scsi/ps3rom.c b/trunk/drivers/scsi/ps3rom.c index 0cd614a0fa73..17b4a7c4618c 100644 --- a/trunk/drivers/scsi/ps3rom.c +++ b/trunk/drivers/scsi/ps3rom.c @@ -35,7 +35,7 @@ #define BOUNCE_SIZE (64*1024) -#define PS3ROM_MAX_SECTORS (BOUNCE_SIZE >> 9) +#define PS3ROM_MAX_SECTORS (BOUNCE_SIZE / CD_FRAMESIZE) struct ps3rom_private { diff --git a/trunk/drivers/scsi/qla2xxx/qla_attr.c b/trunk/drivers/scsi/qla2xxx/qla_attr.c index 4894dc886b62..adf97320574b 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_attr.c +++ b/trunk/drivers/scsi/qla2xxx/qla_attr.c @@ -428,19 +428,6 @@ qla2x00_sysfs_read_sfp(struct kobject *kobj, if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2) return 0; - if (ha->sfp_data) - goto do_read; - - ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, - &ha->sfp_data_dma); - if (!ha->sfp_data) { - qla_printk(KERN_WARNING, ha, - "Unable to allocate memory for SFP read-data.\n"); - return 0; - } - -do_read: - memset(ha->sfp_data, 0, SFP_BLOCK_SIZE); addr = 0xa0; for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE; iter++, offset += SFP_BLOCK_SIZE) { @@ -848,7 +835,7 @@ qla2x00_get_host_port_id(struct Scsi_Host *shost) static void qla2x00_get_host_speed(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); + scsi_qla_host_t *ha = shost_priv(shost); uint32_t speed = 0; switch (ha->link_data_rate) { @@ -861,9 +848,6 @@ qla2x00_get_host_speed(struct Scsi_Host *shost) case PORT_SPEED_4GB: speed = 4; break; - case PORT_SPEED_8GB: - speed = 8; - break; } fc_host_speed(shost) = speed; } @@ -871,7 +855,7 @@ qla2x00_get_host_speed(struct Scsi_Host *shost) static void qla2x00_get_host_port_type(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); + scsi_qla_host_t *ha = shost_priv(shost); uint32_t port_type = FC_PORTTYPE_UNKNOWN; switch (ha->current_topology) { @@ -981,7 +965,7 @@ qla2x00_issue_lip(struct Scsi_Host *shost) static struct fc_host_statistics * qla2x00_get_fc_host_stats(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); + scsi_qla_host_t *ha = shost_priv(shost); int rval; struct link_statistics *stats; dma_addr_t stats_dma; @@ -1065,7 +1049,7 @@ qla2x00_get_host_fabric_name(struct Scsi_Host *shost) static void qla2x00_get_host_port_state(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); + scsi_qla_host_t *ha = shost_priv(shost); if (!ha->flags.online) fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; diff --git a/trunk/drivers/scsi/qla2xxx/qla_def.h b/trunk/drivers/scsi/qla2xxx/qla_def.h index 3750319f4968..b72c7f170854 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_def.h +++ b/trunk/drivers/scsi/qla2xxx/qla_def.h @@ -2041,6 +2041,8 @@ typedef struct vport_params { #define VP_RET_CODE_NO_MEM 5 #define VP_RET_CODE_NOT_FOUND 6 +#define to_qla_parent(x) (((x)->parent) ? (x)->parent : (x)) + /* * ISP operations */ diff --git a/trunk/drivers/scsi/qla2xxx/qla_gbl.h b/trunk/drivers/scsi/qla2xxx/qla_gbl.h index 193f688ec3d7..ba35fc26ce6b 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_gbl.h +++ b/trunk/drivers/scsi/qla2xxx/qla_gbl.h @@ -66,7 +66,6 @@ extern int ql2xqfullrampup; extern int num_hosts; extern int qla2x00_loop_reset(scsi_qla_host_t *); -extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); /* * Global Functions in qla_mid.c source file. diff --git a/trunk/drivers/scsi/qla2xxx/qla_init.c b/trunk/drivers/scsi/qla2xxx/qla_init.c index d5c7853e7eba..d0633ca894be 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_init.c +++ b/trunk/drivers/scsi/qla2xxx/qla_init.c @@ -925,16 +925,6 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) { int rval; uint32_t srisc_address = 0; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - unsigned long flags; - - if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) { - /* Disable SRAM, Instruction RAM and GP RAM parity. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - WRT_REG_WORD(®->hccr, (HCCR_ENABLE_PARITY + 0x0)); - RD_REG_WORD(®->hccr); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } /* Load firmware sequences */ rval = ha->isp_ops->load_risc(ha, &srisc_address); @@ -978,19 +968,6 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) } } - if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) { - /* Enable proper parity. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - if (IS_QLA2300(ha)) - /* SRAM parity */ - WRT_REG_WORD(®->hccr, HCCR_ENABLE_PARITY + 0x1); - else - /* SRAM, Instruction RAM and GP RAM parity */ - WRT_REG_WORD(®->hccr, HCCR_ENABLE_PARITY + 0x7); - RD_REG_WORD(®->hccr); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } - if (rval) { DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n", ha->host_no)); @@ -3236,6 +3213,9 @@ int qla2x00_abort_isp(scsi_qla_host_t *ha) { int rval; + unsigned long flags = 0; + uint16_t cnt; + srb_t *sp; uint8_t status = 0; if (ha->flags.online) { @@ -3256,8 +3236,19 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) LOOP_DOWN_TIME); } + spin_lock_irqsave(&ha->hardware_lock, flags); /* Requeue all commands in outstanding command list. */ - qla2x00_abort_all_cmds(ha, DID_RESET << 16); + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + sp = ha->outstanding_cmds[cnt]; + if (sp) { + ha->outstanding_cmds[cnt] = NULL; + sp->flags = 0; + sp->cmd->result = DID_RESET << 16; + sp->cmd->host_scribble = (unsigned char *)NULL; + qla2x00_sp_compl(ha, sp); + } + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); ha->isp_ops->get_flash_version(ha, ha->request_ring); @@ -3282,7 +3273,6 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags); if (ha->eft) { - memset(ha->eft, 0, EFT_SIZE); rval = qla2x00_enable_eft_trace(ha, ha->eft_dma, EFT_NUM_BUFFERS); if (rval) { @@ -3367,15 +3357,60 @@ static int qla2x00_restart_isp(scsi_qla_host_t *ha) { uint8_t status = 0; + struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + unsigned long flags = 0; uint32_t wait_time; /* If firmware needs to be loaded */ if (qla2x00_isp_firmware(ha)) { ha->flags.online = 0; - if (!(status = ha->isp_ops->chip_diag(ha))) + if (!(status = ha->isp_ops->chip_diag(ha))) { + if (IS_QLA2100(ha) || IS_QLA2200(ha)) { + status = qla2x00_setup_chip(ha); + goto done; + } + + spin_lock_irqsave(&ha->hardware_lock, flags); + + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha) && + !IS_QLA25XX(ha)) { + /* + * Disable SRAM, Instruction RAM and GP RAM + * parity. + */ + WRT_REG_WORD(®->hccr, + (HCCR_ENABLE_PARITY + 0x0)); + RD_REG_WORD(®->hccr); + } + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + status = qla2x00_setup_chip(ha); + + spin_lock_irqsave(&ha->hardware_lock, flags); + + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha) && + !IS_QLA25XX(ha)) { + /* Enable proper parity */ + if (IS_QLA2300(ha)) + /* SRAM parity */ + WRT_REG_WORD(®->hccr, + (HCCR_ENABLE_PARITY + 0x1)); + else + /* + * SRAM, Instruction RAM and GP RAM + * parity. + */ + WRT_REG_WORD(®->hccr, + (HCCR_ENABLE_PARITY + 0x7)); + RD_REG_WORD(®->hccr); + } + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } } + done: if (!status && !(status = qla2x00_init_rings(ha))) { clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); if (!(status = qla2x00_fw_ready(ha))) { diff --git a/trunk/drivers/scsi/qla2xxx/qla_inline.h b/trunk/drivers/scsi/qla2xxx/qla_inline.h index 5d1a3f7c408f..8e3b04464cff 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_inline.h +++ b/trunk/drivers/scsi/qla2xxx/qla_inline.h @@ -119,13 +119,6 @@ static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *ha) qla2x00_get_firmware_state(ha, &fw_state); } -static __inline__ scsi_qla_host_t * to_qla_parent(scsi_qla_host_t *); -static __inline__ scsi_qla_host_t * -to_qla_parent(scsi_qla_host_t *ha) -{ - return ha->parent ? ha->parent : ha; -} - /** * qla2x00_issue_marker() - Issue a Marker IOCB if necessary. * @ha: HA context diff --git a/trunk/drivers/scsi/qla2xxx/qla_isr.c b/trunk/drivers/scsi/qla2xxx/qla_isr.c index 14e6f22944b7..642a0c3f09c6 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_isr.c +++ b/trunk/drivers/scsi/qla2xxx/qla_isr.c @@ -1815,8 +1815,6 @@ int qla2x00_request_irqs(scsi_qla_host_t *ha) { int ret; - device_reg_t __iomem *reg = ha->iobase; - unsigned long flags; /* If possible, enable MSI-X. */ if (!IS_QLA2432(ha) && !IS_QLA2532(ha)) @@ -1848,7 +1846,7 @@ qla2x00_request_irqs(scsi_qla_host_t *ha) DEBUG2(qla_printk(KERN_INFO, ha, "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision, ha->fw_attributes)); - goto clear_risc_ints; + return ret; } qla_printk(KERN_WARNING, ha, "MSI-X: Falling back-to INTa mode -- %d.\n", ret); @@ -1866,30 +1864,15 @@ qla2x00_request_irqs(scsi_qla_host_t *ha) ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler, IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha); - if (ret) { + if (!ret) { + ha->flags.inta_enabled = 1; + ha->host->irq = ha->pdev->irq; + } else { qla_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d already in use.\n", ha->pdev->irq); - goto fail; - } - ha->flags.inta_enabled = 1; - ha->host->irq = ha->pdev->irq; -clear_risc_ints: - - ha->isp_ops->disable_intrs(ha); - spin_lock_irqsave(&ha->hardware_lock, flags); - if (IS_FWI2_CAPABLE(ha)) { - WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_HOST_INT); - WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_RISC_INT); - } else { - WRT_REG_WORD(®->isp.semaphore, 0); - WRT_REG_WORD(®->isp.hccr, HCCR_CLR_RISC_INT); - WRT_REG_WORD(®->isp.hccr, HCCR_CLR_HOST_INT); } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - ha->isp_ops->enable_intrs(ha); -fail: return ret; } diff --git a/trunk/drivers/scsi/qla2xxx/qla_mbx.c b/trunk/drivers/scsi/qla2xxx/qla_mbx.c index 99d29fff836d..0c10c0b0fb73 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_mbx.c +++ b/trunk/drivers/scsi/qla2xxx/qla_mbx.c @@ -980,7 +980,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size) DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n", ha->host_no)); - if (ha->flags.npiv_supported) + if (ha->fw_attributes & BIT_2) mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE; else mcp->mb[0] = MBC_INITIALIZE_FIRMWARE; diff --git a/trunk/drivers/scsi/qla2xxx/qla_os.c b/trunk/drivers/scsi/qla2xxx/qla_os.c index 3c1b43356adb..8f69caf83272 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_os.c +++ b/trunk/drivers/scsi/qla2xxx/qla_os.c @@ -204,8 +204,10 @@ static int qla2x00_do_dpc(void *data); static void qla2x00_rst_aen(scsi_qla_host_t *); -static int qla2x00_mem_alloc(scsi_qla_host_t *); +static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *); static void qla2x00_mem_free(scsi_qla_host_t *ha); +static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha); +static void qla2x00_free_sp_pool(scsi_qla_host_t *ha); static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *); /* -------------------------------------------------------------------------- */ @@ -1115,27 +1117,6 @@ qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport) return ha->isp_ops->abort_target(reset_fcport); } -void -qla2x00_abort_all_cmds(scsi_qla_host_t *ha, int res) -{ - int cnt; - unsigned long flags; - srb_t *sp; - - spin_lock_irqsave(&ha->hardware_lock, flags); - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = ha->outstanding_cmds[cnt]; - if (sp) { - ha->outstanding_cmds[cnt] = NULL; - sp->flags = 0; - sp->cmd->result = res; - sp->cmd->host_scribble = (unsigned char *)NULL; - qla2x00_sp_compl(ha, sp); - } - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - static int qla2xxx_slave_alloc(struct scsi_device *sdev) { @@ -1576,8 +1557,10 @@ static int __devinit qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { int ret = -ENODEV; + device_reg_t __iomem *reg; struct Scsi_Host *host; scsi_qla_host_t *ha; + unsigned long flags = 0; char pci_info[30]; char fw_str[30]; struct scsi_host_template *sht; @@ -1625,7 +1608,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->parent = NULL; ha->bars = bars; ha->mem_only = mem_only; - spin_lock_init(&ha->hardware_lock); /* Set ISP-type information. */ qla2x00_set_isp_flags(ha); @@ -1639,6 +1621,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) "Found an ISP%04X, irq %d, iobase 0x%p\n", pdev->device, pdev->irq, ha->iobase); + spin_lock_init(&ha->hardware_lock); + ha->prev_topology = 0; ha->init_cb_size = sizeof(init_cb_t); ha->mgmt_svr_loop_id = MANAGEMENT_SERVER + ha->vp_idx; @@ -1767,6 +1751,34 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n", ha->host_no, ha)); + ha->isp_ops->disable_intrs(ha); + + spin_lock_irqsave(&ha->hardware_lock, flags); + reg = ha->iobase; + if (IS_FWI2_CAPABLE(ha)) { + WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_HOST_INT); + WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_RISC_INT); + } else { + WRT_REG_WORD(®->isp.semaphore, 0); + WRT_REG_WORD(®->isp.hccr, HCCR_CLR_RISC_INT); + WRT_REG_WORD(®->isp.hccr, HCCR_CLR_HOST_INT); + + /* Enable proper parity */ + if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) { + if (IS_QLA2300(ha)) + /* SRAM parity */ + WRT_REG_WORD(®->isp.hccr, + (HCCR_ENABLE_PARITY + 0x1)); + else + /* SRAM, Instruction RAM and GP RAM parity */ + WRT_REG_WORD(®->isp.hccr, + (HCCR_ENABLE_PARITY + 0x7)); + } + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + ha->isp_ops->enable_intrs(ha); + pci_set_drvdata(pdev, ha); ha->flags.init_done = 1; @@ -1836,14 +1848,10 @@ qla2x00_remove_one(struct pci_dev *pdev) static void qla2x00_free_device(scsi_qla_host_t *ha) { - qla2x00_abort_all_cmds(ha, DID_NO_CONNECT << 16); - /* Disable timer */ if (ha->timer_active) qla2x00_stop_timer(ha); - ha->flags.online = 0; - /* Kill the kernel thread for this host */ if (ha->dpc_thread) { struct task_struct *t = ha->dpc_thread; @@ -1862,6 +1870,8 @@ qla2x00_free_device(scsi_qla_host_t *ha) if (ha->eft) qla2x00_disable_eft_trace(ha); + ha->flags.online = 0; + /* Stop currently executing firmware. */ qla2x00_try_to_stop_firmware(ha); @@ -2000,109 +2010,196 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer) * * Returns: * 0 = success. -* !0 = failure. +* 1 = failure. */ -static int +static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *ha) { char name[16]; + uint8_t status = 1; + int retry= 10; - ha->request_ring = dma_alloc_coherent(&ha->pdev->dev, - (ha->request_q_length + 1) * sizeof(request_t), &ha->request_dma, - GFP_KERNEL); - if (!ha->request_ring) - goto fail; - - ha->response_ring = dma_alloc_coherent(&ha->pdev->dev, - (ha->response_q_length + 1) * sizeof(response_t), - &ha->response_dma, GFP_KERNEL); - if (!ha->response_ring) - goto fail_free_request_ring; - - ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE, - &ha->gid_list_dma, GFP_KERNEL); - if (!ha->gid_list) - goto fail_free_response_ring; - - ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, ha->init_cb_size, - &ha->init_cb_dma, GFP_KERNEL); - if (!ha->init_cb) - goto fail_free_gid_list; - - snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME, - ha->host_no); - ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev, - DMA_POOL_SIZE, 8, 0); - if (!ha->s_dma_pool) - goto fail_free_init_cb; + do { + /* + * This will loop only once if everything goes well, else some + * number of retries will be performed to get around a kernel + * bug where available mem is not allocated until after a + * little delay and a retry. + */ + ha->request_ring = dma_alloc_coherent(&ha->pdev->dev, + (ha->request_q_length + 1) * sizeof(request_t), + &ha->request_dma, GFP_KERNEL); + if (ha->request_ring == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - request_ring\n"); - ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep); - if (!ha->srb_mempool) - goto fail_free_s_dma_pool; - - /* Get memory for cached NVRAM */ - ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL); - if (!ha->nvram) - goto fail_free_srb_mempool; - - /* Allocate memory for SNS commands */ - if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - /* Get consistent memory allocated for SNS commands */ - ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, GFP_KERNEL); - if (!ha->sns_cmd) - goto fail_free_nvram; - } else { - /* Get consistent memory allocated for MS IOCB */ - ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, - &ha->ms_iocb_dma); - if (!ha->ms_iocb) - goto fail_free_nvram; + qla2x00_mem_free(ha); + msleep(100); - /* Get consistent memory allocated for CT SNS commands */ - ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL); - if (!ha->ct_sns) - goto fail_free_ms_iocb; - } + continue; + } - return 0; + ha->response_ring = dma_alloc_coherent(&ha->pdev->dev, + (ha->response_q_length + 1) * sizeof(response_t), + &ha->response_dma, GFP_KERNEL); + if (ha->response_ring == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - response_ring\n"); -fail_free_ms_iocb: - dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); - ha->ms_iocb = NULL; - ha->ms_iocb_dma = 0; -fail_free_nvram: - kfree(ha->nvram); - ha->nvram = NULL; -fail_free_srb_mempool: - mempool_destroy(ha->srb_mempool); - ha->srb_mempool = NULL; -fail_free_s_dma_pool: - dma_pool_destroy(ha->s_dma_pool); - ha->s_dma_pool = NULL; -fail_free_init_cb: - dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, - ha->init_cb_dma); - ha->init_cb = NULL; - ha->init_cb_dma = 0; -fail_free_gid_list: - dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list, - ha->gid_list_dma); - ha->gid_list = NULL; - ha->gid_list_dma = 0; -fail_free_response_ring: - dma_free_coherent(&ha->pdev->dev, (ha->response_q_length + 1) * - sizeof(response_t), ha->response_ring, ha->response_dma); - ha->response_ring = NULL; - ha->response_dma = 0; -fail_free_request_ring: - dma_free_coherent(&ha->pdev->dev, (ha->request_q_length + 1) * - sizeof(request_t), ha->request_ring, ha->request_dma); - ha->request_ring = NULL; - ha->request_dma = 0; -fail: - return -ENOMEM; + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + + ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE, + &ha->gid_list_dma, GFP_KERNEL); + if (ha->gid_list == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - gid_list\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + + /* get consistent memory allocated for init control block */ + ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, + ha->init_cb_size, &ha->init_cb_dma, GFP_KERNEL); + if (ha->init_cb == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - init_cb\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + memset(ha->init_cb, 0, ha->init_cb_size); + + snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME, + ha->host_no); + ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev, + DMA_POOL_SIZE, 8, 0); + if (ha->s_dma_pool == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - s_dma_pool\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + + if (qla2x00_allocate_sp_pool(ha)) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - " + "qla2x00_allocate_sp_pool()\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + + /* Allocate memory for SNS commands */ + if (IS_QLA2100(ha) || IS_QLA2200(ha)) { + /* Get consistent memory allocated for SNS commands */ + ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, + GFP_KERNEL); + if (ha->sns_cmd == NULL) { + /* error */ + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - sns_cmd\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + memset(ha->sns_cmd, 0, sizeof(struct sns_cmd_pkt)); + } else { + /* Get consistent memory allocated for MS IOCB */ + ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, + &ha->ms_iocb_dma); + if (ha->ms_iocb == NULL) { + /* error */ + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - ms_iocb\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + memset(ha->ms_iocb, 0, sizeof(ms_iocb_entry_t)); + + /* + * Get consistent memory allocated for CT SNS + * commands + */ + ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, + GFP_KERNEL); + if (ha->ct_sns == NULL) { + /* error */ + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - ct_sns\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt)); + + if (IS_FWI2_CAPABLE(ha)) { + /* + * Get consistent memory allocated for SFP + * block. + */ + ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, + GFP_KERNEL, &ha->sfp_data_dma); + if (ha->sfp_data == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - " + "sfp_data\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + memset(ha->sfp_data, 0, SFP_BLOCK_SIZE); + } + } + + /* Get memory for cached NVRAM */ + ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL); + if (ha->nvram == NULL) { + /* error */ + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - nvram cache\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + + /* Done all allocations without any error. */ + status = 0; + + } while (retry-- && status != 0); + + if (status) { + printk(KERN_WARNING + "%s(): **** FAILED ****\n", __func__); + } + + return(status); } /* @@ -2118,8 +2215,14 @@ qla2x00_mem_free(scsi_qla_host_t *ha) struct list_head *fcpl, *fcptemp; fc_port_t *fcport; - if (ha->srb_mempool) - mempool_destroy(ha->srb_mempool); + if (ha == NULL) { + /* error */ + DEBUG2(printk("%s(): ERROR invalid ha pointer.\n", __func__)); + return; + } + + /* free sp pool */ + qla2x00_free_sp_pool(ha); if (ha->fce) dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce, @@ -2167,7 +2270,6 @@ qla2x00_mem_free(scsi_qla_host_t *ha) (ha->request_q_length + 1) * sizeof(request_t), ha->request_ring, ha->request_dma); - ha->srb_mempool = NULL; ha->eft = NULL; ha->eft_dma = 0; ha->sns_cmd = NULL; @@ -2206,6 +2308,44 @@ qla2x00_mem_free(scsi_qla_host_t *ha) kfree(ha->nvram); } +/* + * qla2x00_allocate_sp_pool + * This routine is called during initialization to allocate + * memory for local srb_t. + * + * Input: + * ha = adapter block pointer. + * + * Context: + * Kernel context. + */ +static int +qla2x00_allocate_sp_pool(scsi_qla_host_t *ha) +{ + int rval; + + rval = QLA_SUCCESS; + ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep); + if (ha->srb_mempool == NULL) { + qla_printk(KERN_INFO, ha, "Unable to allocate SRB mempool.\n"); + rval = QLA_FUNCTION_FAILED; + } + return (rval); +} + +/* + * This routine frees all adapter allocated memory. + * + */ +static void +qla2x00_free_sp_pool( scsi_qla_host_t *ha) +{ + if (ha->srb_mempool) { + mempool_destroy(ha->srb_mempool); + ha->srb_mempool = NULL; + } +} + /************************************************************************** * qla2x00_do_dpc * This kernel thread is a task that is schedule by the interrupt handler @@ -2227,9 +2367,6 @@ qla2x00_do_dpc(void *data) fc_port_t *fcport; uint8_t status; uint16_t next_loopid; - struct scsi_qla_host *vha; - int i; - ha = (scsi_qla_host_t *)data; @@ -2272,18 +2409,6 @@ qla2x00_do_dpc(void *data) } clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); } - - for_each_mapped_vp_idx(ha, i) { - list_for_each_entry(vha, &ha->vp_list, - vp_list) { - if (i == vha->vp_idx) { - set_bit(ISP_ABORT_NEEDED, - &vha->dpc_flags); - break; - } - } - } - DEBUG(printk("scsi(%ld): dpc: qla2x00_abort_isp end\n", ha->host_no)); } @@ -2904,4 +3029,3 @@ MODULE_FIRMWARE(FW_FILE_ISP22XX); MODULE_FIRMWARE(FW_FILE_ISP2300); MODULE_FIRMWARE(FW_FILE_ISP2322); MODULE_FIRMWARE(FW_FILE_ISP24XX); -MODULE_FIRMWARE(FW_FILE_ISP25XX); diff --git a/trunk/drivers/scsi/qla2xxx/qla_sup.c b/trunk/drivers/scsi/qla2xxx/qla_sup.c index 26822c8807ee..b68fb73613ed 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_sup.c +++ b/trunk/drivers/scsi/qla2xxx/qla_sup.c @@ -893,8 +893,6 @@ qla2x00_flip_colors(scsi_qla_host_t *ha, uint16_t *pflags) } } -#define PIO_REG(h, r) ((h)->pio_address + offsetof(struct device_reg_2xxx, r)) - void qla2x00_beacon_blink(struct scsi_qla_host *ha) { @@ -904,12 +902,15 @@ qla2x00_beacon_blink(struct scsi_qla_host *ha) unsigned long flags; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + if (ha->pio_address) + reg = (struct device_reg_2xxx __iomem *)ha->pio_address; + spin_lock_irqsave(&ha->hardware_lock, flags); /* Save the Original GPIOE. */ if (ha->pio_address) { - gpio_enable = RD_REG_WORD_PIO(PIO_REG(ha, gpioe)); - gpio_data = RD_REG_WORD_PIO(PIO_REG(ha, gpiod)); + gpio_enable = RD_REG_WORD_PIO(®->gpioe); + gpio_data = RD_REG_WORD_PIO(®->gpiod); } else { gpio_enable = RD_REG_WORD(®->gpioe); gpio_data = RD_REG_WORD(®->gpiod); @@ -919,7 +920,7 @@ qla2x00_beacon_blink(struct scsi_qla_host *ha) gpio_enable |= GPIO_LED_MASK; if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, gpioe), gpio_enable); + WRT_REG_WORD_PIO(®->gpioe, gpio_enable); } else { WRT_REG_WORD(®->gpioe, gpio_enable); RD_REG_WORD(®->gpioe); @@ -935,7 +936,7 @@ qla2x00_beacon_blink(struct scsi_qla_host *ha) /* Set the modified gpio_data values */ if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, gpiod), gpio_data); + WRT_REG_WORD_PIO(®->gpiod, gpio_data); } else { WRT_REG_WORD(®->gpiod, gpio_data); RD_REG_WORD(®->gpiod); @@ -961,11 +962,14 @@ qla2x00_beacon_on(struct scsi_qla_host *ha) return QLA_FUNCTION_FAILED; } + if (ha->pio_address) + reg = (struct device_reg_2xxx __iomem *)ha->pio_address; + /* Turn off LEDs. */ spin_lock_irqsave(&ha->hardware_lock, flags); if (ha->pio_address) { - gpio_enable = RD_REG_WORD_PIO(PIO_REG(ha, gpioe)); - gpio_data = RD_REG_WORD_PIO(PIO_REG(ha, gpiod)); + gpio_enable = RD_REG_WORD_PIO(®->gpioe); + gpio_data = RD_REG_WORD_PIO(®->gpiod); } else { gpio_enable = RD_REG_WORD(®->gpioe); gpio_data = RD_REG_WORD(®->gpiod); @@ -974,7 +978,7 @@ qla2x00_beacon_on(struct scsi_qla_host *ha) /* Set the modified gpio_enable values. */ if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, gpioe), gpio_enable); + WRT_REG_WORD_PIO(®->gpioe, gpio_enable); } else { WRT_REG_WORD(®->gpioe, gpio_enable); RD_REG_WORD(®->gpioe); @@ -983,7 +987,7 @@ qla2x00_beacon_on(struct scsi_qla_host *ha) /* Clear out previously set LED colour. */ gpio_data &= ~GPIO_LED_MASK; if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, gpiod), gpio_data); + WRT_REG_WORD_PIO(®->gpiod, gpio_data); } else { WRT_REG_WORD(®->gpiod, gpio_data); RD_REG_WORD(®->gpiod); @@ -1240,12 +1244,13 @@ qla2x00_read_flash_byte(scsi_qla_host_t *ha, uint32_t addr) if (ha->pio_address) { uint16_t data2; - WRT_REG_WORD_PIO(PIO_REG(ha, flash_address), (uint16_t)addr); + reg = (struct device_reg_2xxx __iomem *)ha->pio_address; + WRT_REG_WORD_PIO(®->flash_address, (uint16_t)addr); do { - data = RD_REG_WORD_PIO(PIO_REG(ha, flash_data)); + data = RD_REG_WORD_PIO(®->flash_data); barrier(); cpu_relax(); - data2 = RD_REG_WORD_PIO(PIO_REG(ha, flash_data)); + data2 = RD_REG_WORD_PIO(®->flash_data); } while (data != data2); } else { WRT_REG_WORD(®->flash_address, (uint16_t)addr); @@ -1299,8 +1304,9 @@ qla2x00_write_flash_byte(scsi_qla_host_t *ha, uint32_t addr, uint8_t data) /* Always perform IO mapped accesses to the FLASH registers. */ if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, flash_address), (uint16_t)addr); - WRT_REG_WORD_PIO(PIO_REG(ha, flash_data), (uint16_t)data); + reg = (struct device_reg_2xxx __iomem *)ha->pio_address; + WRT_REG_WORD_PIO(®->flash_address, (uint16_t)addr); + WRT_REG_WORD_PIO(®->flash_data, (uint16_t)data); } else { WRT_REG_WORD(®->flash_address, (uint16_t)addr); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ diff --git a/trunk/drivers/scsi/qla2xxx/qla_version.h b/trunk/drivers/scsi/qla2xxx/qla_version.h index c5742cc15abb..2c2f6b4697c7 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_version.h +++ b/trunk/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.02.00-k8" +#define QLA2XXX_VERSION "8.02.00-k7" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 2 diff --git a/trunk/drivers/scsi/qla4xxx/ql4_init.c b/trunk/drivers/scsi/qla4xxx/ql4_init.c index 10b3b9a620f3..49925f92555e 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_init.c +++ b/trunk/drivers/scsi/qla4xxx/ql4_init.c @@ -1306,7 +1306,6 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, atomic_set(&ddb_entry->relogin_timer, 0); clear_bit(DF_RELOGIN, &ddb_entry->flags); clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); - iscsi_unblock_session(ddb_entry->sess); iscsi_session_event(ddb_entry->sess, ISCSI_KEVENT_CREATE_SESSION); /* diff --git a/trunk/drivers/scsi/qla4xxx/ql4_os.c b/trunk/drivers/scsi/qla4xxx/ql4_os.c index c3c59d763037..2e2b9fedffcc 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_os.c +++ b/trunk/drivers/scsi/qla4xxx/ql4_os.c @@ -63,6 +63,8 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, enum iscsi_param param, char *buf); static int qla4xxx_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf); +static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag); +static int qla4xxx_conn_start(struct iscsi_cls_conn *conn); static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session); /* @@ -89,8 +91,6 @@ static struct scsi_host_template qla4xxx_driver_template = { .slave_alloc = qla4xxx_slave_alloc, .slave_destroy = qla4xxx_slave_destroy, - .scan_finished = iscsi_scan_finished, - .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, @@ -116,6 +116,8 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { .get_conn_param = qla4xxx_conn_get_param, .get_session_param = qla4xxx_sess_get_param, .get_host_param = qla4xxx_host_get_param, + .start_conn = qla4xxx_conn_start, + .stop_conn = qla4xxx_conn_stop, .session_recovery_timedout = qla4xxx_recovery_timedout, }; @@ -126,19 +128,48 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) struct ddb_entry *ddb_entry = session->dd_data; struct scsi_qla_host *ha = ddb_entry->ha; - if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { - atomic_set(&ddb_entry->state, DDB_STATE_DEAD); + DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count of (%d) " + "secs exhausted, marking device DEAD.\n", ha->host_no, + __func__, ddb_entry->fw_ddb_index, + ha->port_down_retry_count)); - DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count " - "of (%d) secs exhausted, marking device DEAD.\n", - ha->host_no, __func__, ddb_entry->fw_ddb_index, - ha->port_down_retry_count)); + atomic_set(&ddb_entry->state, DDB_STATE_DEAD); - DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc " - "flags = 0x%lx\n", - ha->host_no, __func__, ha->dpc_flags)); - queue_work(ha->dpc_thread, &ha->dpc_work); - } + DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc flags = " + "0x%lx\n", ha->host_no, __func__, ha->dpc_flags)); + queue_work(ha->dpc_thread, &ha->dpc_work); +} + +static int qla4xxx_conn_start(struct iscsi_cls_conn *conn) +{ + struct iscsi_cls_session *session; + struct ddb_entry *ddb_entry; + + session = iscsi_dev_to_session(conn->dev.parent); + ddb_entry = session->dd_data; + + DEBUG2(printk("scsi%ld: %s: index [%d] starting conn\n", + ddb_entry->ha->host_no, __func__, + ddb_entry->fw_ddb_index)); + iscsi_unblock_session(session); + return 0; +} + +static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag) +{ + struct iscsi_cls_session *session; + struct ddb_entry *ddb_entry; + + session = iscsi_dev_to_session(conn->dev.parent); + ddb_entry = session->dd_data; + + DEBUG2(printk("scsi%ld: %s: index [%d] stopping conn\n", + ddb_entry->ha->host_no, __func__, + ddb_entry->fw_ddb_index)); + if (flag == STOP_CONN_RECOVER) + iscsi_block_session(session); + else + printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); } static int qla4xxx_host_get_param(struct Scsi_Host *shost, @@ -277,9 +308,6 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) DEBUG2(printk(KERN_ERR "Could not add connection.\n")); return -ENOMEM; } - - /* finally ready to go */ - iscsi_unblock_session(ddb_entry->sess); return 0; } @@ -336,7 +364,6 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n", ha->host_no, ddb_entry->bus, ddb_entry->target, ddb_entry->fw_ddb_index)); - iscsi_block_session(ddb_entry->sess); iscsi_conn_error(ddb_entry->conn, ISCSI_ERR_CONN_FAILED); } @@ -403,21 +430,9 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, { struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; - struct iscsi_cls_session *sess = ddb_entry->sess; struct srb *srb; int rval; - if (!sess) { - cmd->result = DID_IMM_RETRY << 16; - goto qc_fail_command; - } - - rval = iscsi_session_chkready(sess); - if (rval) { - cmd->result = rval; - goto qc_fail_command; - } - if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) { cmd->result = DID_NO_CONNECT << 16; @@ -1308,7 +1323,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), ha->host_no, ha->firmware_version[0], ha->firmware_version[1], ha->patch_number, ha->build_number); - scsi_scan_host(host); + return 0; remove_host: diff --git a/trunk/drivers/scsi/scsi.c b/trunk/drivers/scsi/scsi.c index fecba05b4e77..b35d19472caa 100644 --- a/trunk/drivers/scsi/scsi.c +++ b/trunk/drivers/scsi/scsi.c @@ -969,10 +969,9 @@ void starget_for_each_device(struct scsi_target *starget, void *data, EXPORT_SYMBOL(starget_for_each_device); /** - * __starget_for_each_device - helper to walk all devices of a target (UNLOCKED) + * __starget_for_each_device - helper to walk all devices of a target + * (UNLOCKED) * @starget: target whose devices we want to iterate over. - * @data: parameter for callback @fn() - * @fn: callback function that is invoked for each device * * This traverses over each device of @starget. It does _not_ * take a reference on the scsi_device, so the whole loop must be diff --git a/trunk/drivers/scsi/scsi_lib.c b/trunk/drivers/scsi/scsi_lib.c index 135c1d054701..f243fc30c908 100644 --- a/trunk/drivers/scsi/scsi_lib.c +++ b/trunk/drivers/scsi/scsi_lib.c @@ -301,6 +301,7 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, page = sg_page(sg); off = sg->offset; len = sg->length; + data_len += len; while (len > 0 && data_len > 0) { /* diff --git a/trunk/drivers/scsi/scsi_transport_iscsi.c b/trunk/drivers/scsi/scsi_transport_iscsi.c index fac7534f3ec4..0d7b4e79415c 100644 --- a/trunk/drivers/scsi/scsi_transport_iscsi.c +++ b/trunk/drivers/scsi/scsi_transport_iscsi.c @@ -30,10 +30,10 @@ #include #include -#define ISCSI_SESSION_ATTRS 19 -#define ISCSI_CONN_ATTRS 13 +#define ISCSI_SESSION_ATTRS 18 +#define ISCSI_CONN_ATTRS 11 #define ISCSI_HOST_ATTRS 4 -#define ISCSI_TRANSPORT_VERSION "2.0-868" +#define ISCSI_TRANSPORT_VERSION "2.0-867" struct iscsi_internal { int daemon_pid; @@ -127,13 +127,12 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, memset(ihost, 0, sizeof(*ihost)); INIT_LIST_HEAD(&ihost->sessions); mutex_init(&ihost->mutex); - atomic_set(&ihost->nr_scans, 0); - snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", + snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d", shost->host_no); - ihost->scan_workq = create_singlethread_workqueue( - ihost->scan_workq_name); - if (!ihost->scan_workq) + ihost->unbind_workq = create_singlethread_workqueue( + ihost->unbind_workq_name); + if (!ihost->unbind_workq) return -ENOMEM; return 0; } @@ -144,7 +143,7 @@ static int iscsi_remove_host(struct transport_container *tc, struct device *dev, struct Scsi_Host *shost = dev_to_shost(dev); struct iscsi_host *ihost = shost->shost_data; - destroy_workqueue(ihost->scan_workq); + destroy_workqueue(ihost->unbind_workq); return 0; } @@ -222,54 +221,6 @@ static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid) * The following functions can be used by LLDs that allocate * their own scsi_hosts or by software iscsi LLDs */ -static struct { - int value; - char *name; -} iscsi_session_state_names[] = { - { ISCSI_SESSION_LOGGED_IN, "LOGGED_IN" }, - { ISCSI_SESSION_FAILED, "FAILED" }, - { ISCSI_SESSION_FREE, "FREE" }, -}; - -const char *iscsi_session_state_name(int state) -{ - int i; - char *name = NULL; - - for (i = 0; i < ARRAY_SIZE(iscsi_session_state_names); i++) { - if (iscsi_session_state_names[i].value == state) { - name = iscsi_session_state_names[i].name; - break; - } - } - return name; -} - -int iscsi_session_chkready(struct iscsi_cls_session *session) -{ - unsigned long flags; - int err; - - spin_lock_irqsave(&session->lock, flags); - switch (session->state) { - case ISCSI_SESSION_LOGGED_IN: - err = 0; - break; - case ISCSI_SESSION_FAILED: - err = DID_IMM_RETRY << 16; - break; - case ISCSI_SESSION_FREE: - err = DID_NO_CONNECT << 16; - break; - default: - err = DID_NO_CONNECT << 16; - break; - } - spin_unlock_irqrestore(&session->lock, flags); - return err; -} -EXPORT_SYMBOL_GPL(iscsi_session_chkready); - static void iscsi_session_release(struct device *dev) { struct iscsi_cls_session *session = iscsi_dev_to_session(dev); @@ -285,25 +236,6 @@ static int iscsi_is_session_dev(const struct device *dev) return dev->release == iscsi_session_release; } -/** - * iscsi_scan_finished - helper to report when running scans are done - * @shost: scsi host - * @time: scan run time - * - * This function can be used by drives like qla4xxx to report to the scsi - * layer when the scans it kicked off at module load time are done. - */ -int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - struct iscsi_host *ihost = shost->shost_data; - /* - * qla4xxx will have kicked off some session unblocks before calling - * scsi_scan_host, so just wait for them to complete. - */ - return !atomic_read(&ihost->nr_scans); -} -EXPORT_SYMBOL_GPL(iscsi_scan_finished); - static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, uint id, uint lun) { @@ -322,50 +254,14 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, return 0; } -static void iscsi_scan_session(struct work_struct *work) -{ - struct iscsi_cls_session *session = - container_of(work, struct iscsi_cls_session, scan_work); - struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_host *ihost = shost->shost_data; - unsigned long flags; - - spin_lock_irqsave(&session->lock, flags); - if (session->state != ISCSI_SESSION_LOGGED_IN) { - spin_unlock_irqrestore(&session->lock, flags); - goto done; - } - spin_unlock_irqrestore(&session->lock, flags); - - scsi_scan_target(&session->dev, 0, session->target_id, - SCAN_WILD_CARD, 1); -done: - atomic_dec(&ihost->nr_scans); -} - static void session_recovery_timedout(struct work_struct *work) { struct iscsi_cls_session *session = container_of(work, struct iscsi_cls_session, recovery_work.work); - unsigned long flags; - - iscsi_cls_session_printk(KERN_INFO, session, - "session recovery timed out after %d secs\n", - session->recovery_tmo); - spin_lock_irqsave(&session->lock, flags); - switch (session->state) { - case ISCSI_SESSION_FAILED: - session->state = ISCSI_SESSION_FREE; - break; - case ISCSI_SESSION_LOGGED_IN: - case ISCSI_SESSION_FREE: - /* we raced with the unblock's flush */ - spin_unlock_irqrestore(&session->lock, flags); - return; - } - spin_unlock_irqrestore(&session->lock, flags); + dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed " + "out after %d secs\n", session->recovery_tmo); if (session->transport->session_recovery_timedout) session->transport->session_recovery_timedout(session); @@ -373,44 +269,16 @@ static void session_recovery_timedout(struct work_struct *work) scsi_target_unblock(&session->dev); } -void __iscsi_unblock_session(struct iscsi_cls_session *session) +void iscsi_unblock_session(struct iscsi_cls_session *session) { if (!cancel_delayed_work(&session->recovery_work)) flush_workqueue(iscsi_eh_timer_workq); scsi_target_unblock(&session->dev); } - -void iscsi_unblock_session(struct iscsi_cls_session *session) -{ - struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_host *ihost = shost->shost_data; - unsigned long flags; - - spin_lock_irqsave(&session->lock, flags); - session->state = ISCSI_SESSION_LOGGED_IN; - spin_unlock_irqrestore(&session->lock, flags); - - __iscsi_unblock_session(session); - /* - * Only do kernel scanning if the driver is properly hooked into - * the async scanning code (drivers like iscsi_tcp do login and - * scanning from userspace). - */ - if (shost->hostt->scan_finished) { - if (queue_work(ihost->scan_workq, &session->scan_work)) - atomic_inc(&ihost->nr_scans); - } -} EXPORT_SYMBOL_GPL(iscsi_unblock_session); void iscsi_block_session(struct iscsi_cls_session *session) { - unsigned long flags; - - spin_lock_irqsave(&session->lock, flags); - session->state = ISCSI_SESSION_FAILED; - spin_unlock_irqrestore(&session->lock, flags); - scsi_target_block(&session->dev); queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work, session->recovery_tmo * HZ); @@ -443,7 +311,7 @@ static int iscsi_unbind_session(struct iscsi_cls_session *session) struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_host *ihost = shost->shost_data; - return queue_work(ihost->scan_workq, &session->unbind_work); + return queue_work(ihost->unbind_workq, &session->unbind_work); } struct iscsi_cls_session * @@ -459,13 +327,10 @@ iscsi_alloc_session(struct Scsi_Host *shost, session->transport = transport; session->recovery_tmo = 120; - session->state = ISCSI_SESSION_FREE; INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); INIT_WORK(&session->unbind_work, __iscsi_unbind_session); - INIT_WORK(&session->scan_work, iscsi_scan_session); - spin_lock_init(&session->lock); /* this is released in the dev's release function */ scsi_host_get(shost); @@ -493,8 +358,8 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) session->sid); err = device_add(&session->dev); if (err) { - iscsi_cls_session_printk(KERN_ERR, session, - "could not register session's dev\n"); + dev_printk(KERN_ERR, &session->dev, "iscsi: could not " + "register session's dev\n"); goto release_host; } transport_register_device(&session->dev); @@ -579,28 +444,22 @@ void iscsi_remove_session(struct iscsi_cls_session *session) * If we are blocked let commands flow again. The lld or iscsi * layer should set up the queuecommand to fail commands. */ - spin_lock_irqsave(&session->lock, flags); - session->state = ISCSI_SESSION_FREE; - spin_unlock_irqrestore(&session->lock, flags); - __iscsi_unblock_session(session); - __iscsi_unbind_session(&session->unbind_work); - - /* flush running scans */ - flush_workqueue(ihost->scan_workq); + iscsi_unblock_session(session); + iscsi_unbind_session(session); /* * If the session dropped while removing devices then we need to make * sure it is not blocked */ if (!cancel_delayed_work(&session->recovery_work)) flush_workqueue(iscsi_eh_timer_workq); + flush_workqueue(ihost->unbind_workq); /* hw iscsi may not have removed all connections from session */ err = device_for_each_child(&session->dev, NULL, iscsi_iter_destroy_conn_fn); if (err) - iscsi_cls_session_printk(KERN_ERR, session, - "Could not delete all connections " - "for session. Error %d.\n", err); + dev_printk(KERN_ERR, &session->dev, "iscsi: Could not delete " + "all connections for session. Error %d.\n", err); transport_unregister_device(&session->dev); device_del(&session->dev); @@ -672,8 +531,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) conn->dev.release = iscsi_conn_release; err = device_register(&conn->dev); if (err) { - iscsi_cls_session_printk(KERN_ERR, session, "could not " - "register connection's dev\n"); + dev_printk(KERN_ERR, &conn->dev, "iscsi: could not register " + "connection's dev\n"); goto release_parent_ref; } transport_register_device(&conn->dev); @@ -780,8 +639,8 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { iscsi_conn_error(conn, ISCSI_ERR_CONN_FAILED); - iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver " - "control PDU: OOM\n"); + dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver " + "control PDU: OOM\n"); return -ENOMEM; } @@ -802,27 +661,20 @@ EXPORT_SYMBOL_GPL(iscsi_recv_pdu); void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) { - struct iscsi_cls_session *session = iscsi_conn_to_session(conn); struct nlmsghdr *nlh; struct sk_buff *skb; struct iscsi_uevent *ev; struct iscsi_internal *priv; int len = NLMSG_SPACE(sizeof(*ev)); - unsigned long flags; priv = iscsi_if_transport_lookup(conn->transport); if (!priv) return; - spin_lock_irqsave(&session->lock, flags); - if (session->state == ISCSI_SESSION_LOGGED_IN) - session->state = ISCSI_SESSION_FAILED; - spin_unlock_irqrestore(&session->lock, flags); - skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { - iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored " - "conn error (%d)\n", error); + dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored " + "conn error (%d)\n", error); return; } @@ -836,8 +688,8 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) iscsi_broadcast_skb(skb, GFP_ATOMIC); - iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n", - error); + dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", + error); } EXPORT_SYMBOL_GPL(iscsi_conn_error); @@ -892,8 +744,8 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) skbstat = alloc_skb(len, GFP_ATOMIC); if (!skbstat) { - iscsi_cls_conn_printk(KERN_ERR, conn, "can not " - "deliver stats: OOM\n"); + dev_printk(KERN_ERR, &conn->dev, "iscsi: can not " + "deliver stats: OOM\n"); return -ENOMEM; } @@ -949,9 +801,8 @@ int iscsi_session_event(struct iscsi_cls_session *session, skb = alloc_skb(len, GFP_KERNEL); if (!skb) { - iscsi_cls_session_printk(KERN_ERR, session, - "Cannot notify userspace of session " - "event %u\n", event); + dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace " + "of session event %u\n", event); return -ENOMEM; } @@ -974,8 +825,8 @@ int iscsi_session_event(struct iscsi_cls_session *session, ev->r.unbind_session.sid = session->sid; break; default: - iscsi_cls_session_printk(KERN_ERR, session, "Invalid event " - "%u.\n", event); + dev_printk(KERN_ERR, &session->dev, "Invalid event %u.\n", + event); kfree_skb(skb); return -EINVAL; } @@ -986,10 +837,8 @@ int iscsi_session_event(struct iscsi_cls_session *session, */ rc = iscsi_broadcast_skb(skb, GFP_KERNEL); if (rc < 0) - iscsi_cls_session_printk(KERN_ERR, session, - "Cannot notify userspace of session " - "event %u. Check iscsi daemon\n", - event); + dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace " + "of session event %u. Check iscsi daemon\n", event); return rc; } EXPORT_SYMBOL_GPL(iscsi_session_event); @@ -1022,15 +871,16 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) session = iscsi_session_lookup(ev->u.c_conn.sid); if (!session) { - printk(KERN_ERR "iscsi: invalid session %d.\n", + printk(KERN_ERR "iscsi: invalid session %d\n", ev->u.c_conn.sid); return -EINVAL; } conn = transport->create_conn(session, ev->u.c_conn.cid); if (!conn) { - iscsi_cls_session_printk(KERN_ERR, session, - "couldn't create a new connection."); + printk(KERN_ERR "iscsi: couldn't create a new " + "connection for session %d\n", + session->sid); return -ENOMEM; } @@ -1396,15 +1246,6 @@ iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0); iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); -static ssize_t -show_priv_session_state(struct class_device *cdev, char *buf) -{ - struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); - return sprintf(buf, "%s\n", iscsi_session_state_name(session->state)); -} -static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state, - NULL); - #define iscsi_priv_session_attr_show(field, format) \ static ssize_t \ show_priv_session_##field(struct class_device *cdev, char *buf) \ @@ -1631,7 +1472,6 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO); SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO); SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); - SETUP_PRIV_SESSION_RD_ATTR(state); BUG_ON(count > ISCSI_SESSION_ATTRS); priv->session_attrs[count] = NULL; diff --git a/trunk/drivers/scsi/sd.c b/trunk/drivers/scsi/sd.c index 37df8bbe7f46..51a5557f42dd 100644 --- a/trunk/drivers/scsi/sd.c +++ b/trunk/drivers/scsi/sd.c @@ -929,7 +929,6 @@ static int sd_done(struct scsi_cmnd *SCpnt) unsigned int xfer_size = scsi_bufflen(SCpnt); unsigned int good_bytes = result ? 0 : xfer_size; u64 start_lba = SCpnt->request->sector; - u64 end_lba = SCpnt->request->sector + (xfer_size / 512); u64 bad_lba; struct scsi_sense_hdr sshdr; int sense_valid = 0; @@ -968,23 +967,26 @@ static int sd_done(struct scsi_cmnd *SCpnt) goto out; if (xfer_size <= SCpnt->device->sector_size) goto out; - if (SCpnt->device->sector_size < 512) { - /* only legitimate sector_size here is 256 */ + switch (SCpnt->device->sector_size) { + case 256: start_lba <<= 1; - end_lba <<= 1; - } else { - /* be careful ... don't want any overflows */ - u64 factor = SCpnt->device->sector_size / 512; - do_div(start_lba, factor); - do_div(end_lba, factor); - } - - if (bad_lba < start_lba || bad_lba >= end_lba) - /* the bad lba was reported incorrectly, we have - * no idea where the error is - */ + break; + case 512: + break; + case 1024: + start_lba >>= 1; + break; + case 2048: + start_lba >>= 2; + break; + case 4096: + start_lba >>= 3; + break; + default: + /* Print something here with limiting frequency. */ goto out; - + break; + } /* This computation should always be done in terms of * the resolution of the device's medium. */ diff --git a/trunk/drivers/scsi/ses.c b/trunk/drivers/scsi/ses.c deleted file mode 100644 index 2a6e4f472eaa..000000000000 --- a/trunk/drivers/scsi/ses.c +++ /dev/null @@ -1,689 +0,0 @@ -/* - * SCSI Enclosure Services - * - * Copyright (C) 2008 James Bottomley - * -**----------------------------------------------------------------------------- -** -** This program is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License -** version 2 as published by the Free Software Foundation. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -**----------------------------------------------------------------------------- -*/ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -struct ses_device { - char *page1; - char *page2; - char *page10; - short page1_len; - short page2_len; - short page10_len; -}; - -struct ses_component { - u64 addr; - unsigned char *desc; -}; - -static int ses_probe(struct device *dev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - int err = -ENODEV; - - if (sdev->type != TYPE_ENCLOSURE) - goto out; - - err = 0; - sdev_printk(KERN_NOTICE, sdev, "Attached Enclosure device\n"); - - out: - return err; -} - -#define SES_TIMEOUT 30 -#define SES_RETRIES 3 - -static int ses_recv_diag(struct scsi_device *sdev, int page_code, - void *buf, int bufflen) -{ - char cmd[] = { - RECEIVE_DIAGNOSTIC, - 1, /* Set PCV bit */ - page_code, - bufflen >> 8, - bufflen & 0xff, - 0 - }; - - return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen, - NULL, SES_TIMEOUT, SES_RETRIES); -} - -static int ses_send_diag(struct scsi_device *sdev, int page_code, - void *buf, int bufflen) -{ - u32 result; - - char cmd[] = { - SEND_DIAGNOSTIC, - 0x10, /* Set PF bit */ - 0, - bufflen >> 8, - bufflen & 0xff, - 0 - }; - - result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, buf, bufflen, - NULL, SES_TIMEOUT, SES_RETRIES); - if (result) - sdev_printk(KERN_ERR, sdev, "SEND DIAGNOSTIC result: %8x\n", - result); - return result; -} - -static int ses_set_page2_descriptor(struct enclosure_device *edev, - struct enclosure_component *ecomp, - char *desc) -{ - int i, j, count = 0, descriptor = ecomp->number; - struct scsi_device *sdev = to_scsi_device(edev->cdev.dev); - struct ses_device *ses_dev = edev->scratch; - char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; - char *desc_ptr = ses_dev->page2 + 8; - - /* Clear everything */ - memset(desc_ptr, 0, ses_dev->page2_len - 8); - for (i = 0; i < ses_dev->page1[10]; i++, type_ptr += 4) { - for (j = 0; j < type_ptr[1]; j++) { - desc_ptr += 4; - if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && - type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) - continue; - if (count++ == descriptor) { - memcpy(desc_ptr, desc, 4); - /* set select */ - desc_ptr[0] |= 0x80; - /* clear reserved, just in case */ - desc_ptr[0] &= 0xf0; - } - } - } - - return ses_send_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); -} - -static char *ses_get_page2_descriptor(struct enclosure_device *edev, - struct enclosure_component *ecomp) -{ - int i, j, count = 0, descriptor = ecomp->number; - struct scsi_device *sdev = to_scsi_device(edev->cdev.dev); - struct ses_device *ses_dev = edev->scratch; - char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; - char *desc_ptr = ses_dev->page2 + 8; - - ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); - - for (i = 0; i < ses_dev->page1[10]; i++, type_ptr += 4) { - for (j = 0; j < type_ptr[1]; j++) { - desc_ptr += 4; - if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && - type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) - continue; - if (count++ == descriptor) - return desc_ptr; - } - } - return NULL; -} - -static void ses_get_fault(struct enclosure_device *edev, - struct enclosure_component *ecomp) -{ - char *desc; - - desc = ses_get_page2_descriptor(edev, ecomp); - ecomp->fault = (desc[3] & 0x60) >> 4; -} - -static int ses_set_fault(struct enclosure_device *edev, - struct enclosure_component *ecomp, - enum enclosure_component_setting val) -{ - char desc[4] = {0 }; - - switch (val) { - case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ - break; - case ENCLOSURE_SETTING_ENABLED: - desc[2] = 0x02; - break; - default: - /* SES doesn't do the SGPIO blink settings */ - return -EINVAL; - } - - return ses_set_page2_descriptor(edev, ecomp, desc); -} - -static void ses_get_status(struct enclosure_device *edev, - struct enclosure_component *ecomp) -{ - char *desc; - - desc = ses_get_page2_descriptor(edev, ecomp); - ecomp->status = (desc[0] & 0x0f); -} - -static void ses_get_locate(struct enclosure_device *edev, - struct enclosure_component *ecomp) -{ - char *desc; - - desc = ses_get_page2_descriptor(edev, ecomp); - ecomp->locate = (desc[2] & 0x02) ? 1 : 0; -} - -static int ses_set_locate(struct enclosure_device *edev, - struct enclosure_component *ecomp, - enum enclosure_component_setting val) -{ - char desc[4] = {0 }; - - switch (val) { - case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ - break; - case ENCLOSURE_SETTING_ENABLED: - desc[2] = 0x02; - break; - default: - /* SES doesn't do the SGPIO blink settings */ - return -EINVAL; - } - return ses_set_page2_descriptor(edev, ecomp, desc); -} - -static int ses_set_active(struct enclosure_device *edev, - struct enclosure_component *ecomp, - enum enclosure_component_setting val) -{ - char desc[4] = {0 }; - - switch (val) { - case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ - ecomp->active = 0; - break; - case ENCLOSURE_SETTING_ENABLED: - desc[2] = 0x80; - ecomp->active = 1; - break; - default: - /* SES doesn't do the SGPIO blink settings */ - return -EINVAL; - } - return ses_set_page2_descriptor(edev, ecomp, desc); -} - -static struct enclosure_component_callbacks ses_enclosure_callbacks = { - .get_fault = ses_get_fault, - .set_fault = ses_set_fault, - .get_status = ses_get_status, - .get_locate = ses_get_locate, - .set_locate = ses_set_locate, - .set_active = ses_set_active, -}; - -struct ses_host_edev { - struct Scsi_Host *shost; - struct enclosure_device *edev; -}; - -int ses_match_host(struct enclosure_device *edev, void *data) -{ - struct ses_host_edev *sed = data; - struct scsi_device *sdev; - - if (!scsi_is_sdev_device(edev->cdev.dev)) - return 0; - - sdev = to_scsi_device(edev->cdev.dev); - - if (sdev->host != sed->shost) - return 0; - - sed->edev = edev; - return 1; -} - -static void ses_process_descriptor(struct enclosure_component *ecomp, - unsigned char *desc) -{ - int eip = desc[0] & 0x10; - int invalid = desc[0] & 0x80; - enum scsi_protocol proto = desc[0] & 0x0f; - u64 addr = 0; - struct ses_component *scomp = ecomp->scratch; - unsigned char *d; - - scomp->desc = desc; - - if (invalid) - return; - - switch (proto) { - case SCSI_PROTOCOL_SAS: - if (eip) - d = desc + 8; - else - d = desc + 4; - /* only take the phy0 addr */ - addr = (u64)d[12] << 56 | - (u64)d[13] << 48 | - (u64)d[14] << 40 | - (u64)d[15] << 32 | - (u64)d[16] << 24 | - (u64)d[17] << 16 | - (u64)d[18] << 8 | - (u64)d[19]; - break; - default: - /* FIXME: Need to add more protocols than just SAS */ - break; - } - scomp->addr = addr; -} - -struct efd { - u64 addr; - struct device *dev; -}; - -static int ses_enclosure_find_by_addr(struct enclosure_device *edev, - void *data) -{ - struct efd *efd = data; - int i; - struct ses_component *scomp; - - if (!edev->component[0].scratch) - return 0; - - for (i = 0; i < edev->components; i++) { - scomp = edev->component[i].scratch; - if (scomp->addr != efd->addr) - continue; - - enclosure_add_device(edev, i, efd->dev); - return 1; - } - return 0; -} - -#define VPD_INQUIRY_SIZE 512 - -static void ses_match_to_enclosure(struct enclosure_device *edev, - struct scsi_device *sdev) -{ - unsigned char *buf = kmalloc(VPD_INQUIRY_SIZE, GFP_KERNEL); - unsigned char *desc; - int len; - struct efd efd = { - .addr = 0, - }; - unsigned char cmd[] = { - INQUIRY, - 1, - 0x83, - VPD_INQUIRY_SIZE >> 8, - VPD_INQUIRY_SIZE & 0xff, - 0 - }; - - if (!buf) - return; - - if (scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, - VPD_INQUIRY_SIZE, NULL, SES_TIMEOUT, SES_RETRIES)) - goto free; - - len = (buf[2] << 8) + buf[3]; - desc = buf + 4; - while (desc < buf + len) { - enum scsi_protocol proto = desc[0] >> 4; - u8 code_set = desc[0] & 0x0f; - u8 piv = desc[1] & 0x80; - u8 assoc = (desc[1] & 0x30) >> 4; - u8 type = desc[1] & 0x0f; - u8 len = desc[3]; - - if (piv && code_set == 1 && assoc == 1 && code_set == 1 - && proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8) - efd.addr = (u64)desc[4] << 56 | - (u64)desc[5] << 48 | - (u64)desc[6] << 40 | - (u64)desc[7] << 32 | - (u64)desc[8] << 24 | - (u64)desc[9] << 16 | - (u64)desc[10] << 8 | - (u64)desc[11]; - - desc += len + 4; - } - if (!efd.addr) - goto free; - - efd.dev = &sdev->sdev_gendev; - - enclosure_for_each_device(ses_enclosure_find_by_addr, &efd); - free: - kfree(buf); -} - -#define INIT_ALLOC_SIZE 32 - -static int ses_intf_add(struct class_device *cdev, - struct class_interface *intf) -{ - struct scsi_device *sdev = to_scsi_device(cdev->dev); - struct scsi_device *tmp_sdev; - unsigned char *buf = NULL, *hdr_buf, *type_ptr, *desc_ptr, - *addl_desc_ptr; - struct ses_device *ses_dev; - u32 result; - int i, j, types, len, components = 0; - int err = -ENOMEM; - struct enclosure_device *edev; - struct ses_component *scomp; - - if (!scsi_device_enclosure(sdev)) { - /* not an enclosure, but might be in one */ - edev = enclosure_find(&sdev->host->shost_gendev); - if (edev) { - ses_match_to_enclosure(edev, sdev); - class_device_put(&edev->cdev); - } - return -ENODEV; - } - - /* TYPE_ENCLOSURE prints a message in probe */ - if (sdev->type != TYPE_ENCLOSURE) - sdev_printk(KERN_NOTICE, sdev, "Embedded Enclosure Device\n"); - - ses_dev = kzalloc(sizeof(*ses_dev), GFP_KERNEL); - hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); - if (!hdr_buf || !ses_dev) - goto err_init_free; - - result = ses_recv_diag(sdev, 1, hdr_buf, INIT_ALLOC_SIZE); - if (result) - goto recv_failed; - - if (hdr_buf[1] != 0) { - /* FIXME: need subenclosure support; I've just never - * seen a device with subenclosures and it makes the - * traversal routines more complex */ - sdev_printk(KERN_ERR, sdev, - "FIXME driver has no support for subenclosures (%d)\n", - buf[1]); - goto err_free; - } - - len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; - buf = kzalloc(len, GFP_KERNEL); - if (!buf) - goto err_free; - - ses_dev->page1 = buf; - ses_dev->page1_len = len; - - result = ses_recv_diag(sdev, 1, buf, len); - if (result) - goto recv_failed; - - types = buf[10]; - len = buf[11]; - - type_ptr = buf + 12 + len; - - for (i = 0; i < types; i++, type_ptr += 4) { - if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || - type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) - components += type_ptr[1]; - } - - result = ses_recv_diag(sdev, 2, hdr_buf, INIT_ALLOC_SIZE); - if (result) - goto recv_failed; - - len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; - buf = kzalloc(len, GFP_KERNEL); - if (!buf) - goto err_free; - - /* make sure getting page 2 actually works */ - result = ses_recv_diag(sdev, 2, buf, len); - if (result) - goto recv_failed; - ses_dev->page2 = buf; - ses_dev->page2_len = len; - - /* The additional information page --- allows us - * to match up the devices */ - result = ses_recv_diag(sdev, 10, hdr_buf, INIT_ALLOC_SIZE); - if (result) - goto no_page10; - - len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; - buf = kzalloc(len, GFP_KERNEL); - if (!buf) - goto err_free; - - result = ses_recv_diag(sdev, 10, buf, len); - if (result) - goto recv_failed; - ses_dev->page10 = buf; - ses_dev->page10_len = len; - - no_page10: - scomp = kmalloc(sizeof(struct ses_component) * components, GFP_KERNEL); - if (!scomp) - goto err_free; - - edev = enclosure_register(cdev->dev, sdev->sdev_gendev.bus_id, - components, &ses_enclosure_callbacks); - if (IS_ERR(edev)) { - err = PTR_ERR(edev); - goto err_free; - } - - edev->scratch = ses_dev; - for (i = 0; i < components; i++) - edev->component[i].scratch = scomp++; - - /* Page 7 for the descriptors is optional */ - buf = NULL; - result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE); - if (result) - goto simple_populate; - - len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; - /* add 1 for trailing '\0' we'll use */ - buf = kzalloc(len + 1, GFP_KERNEL); - result = ses_recv_diag(sdev, 7, buf, len); - if (result) { - simple_populate: - kfree(buf); - buf = NULL; - desc_ptr = NULL; - addl_desc_ptr = NULL; - } else { - desc_ptr = buf + 8; - len = (desc_ptr[2] << 8) + desc_ptr[3]; - /* skip past overall descriptor */ - desc_ptr += len + 4; - addl_desc_ptr = ses_dev->page10 + 8; - } - type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; - components = 0; - for (i = 0; i < types; i++, type_ptr += 4) { - for (j = 0; j < type_ptr[1]; j++) { - char *name = NULL; - struct enclosure_component *ecomp; - - if (desc_ptr) { - len = (desc_ptr[2] << 8) + desc_ptr[3]; - desc_ptr += 4; - /* Add trailing zero - pushes into - * reserved space */ - desc_ptr[len] = '\0'; - name = desc_ptr; - } - if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && - type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) - continue; - ecomp = enclosure_component_register(edev, - components++, - type_ptr[0], - name); - if (desc_ptr) { - desc_ptr += len; - if (!IS_ERR(ecomp)) - ses_process_descriptor(ecomp, - addl_desc_ptr); - - if (addl_desc_ptr) - addl_desc_ptr += addl_desc_ptr[1] + 2; - } - } - } - kfree(buf); - kfree(hdr_buf); - - /* see if there are any devices matching before - * we found the enclosure */ - shost_for_each_device(tmp_sdev, sdev->host) { - if (tmp_sdev->lun != 0 || scsi_device_enclosure(tmp_sdev)) - continue; - ses_match_to_enclosure(edev, tmp_sdev); - } - - return 0; - - recv_failed: - sdev_printk(KERN_ERR, sdev, "Failed to get diagnostic page 0x%x\n", - result); - err = -ENODEV; - err_free: - kfree(buf); - kfree(ses_dev->page10); - kfree(ses_dev->page2); - kfree(ses_dev->page1); - err_init_free: - kfree(ses_dev); - kfree(hdr_buf); - sdev_printk(KERN_ERR, sdev, "Failed to bind enclosure %d\n", err); - return err; -} - -static int ses_remove(struct device *dev) -{ - return 0; -} - -static void ses_intf_remove(struct class_device *cdev, - struct class_interface *intf) -{ - struct scsi_device *sdev = to_scsi_device(cdev->dev); - struct enclosure_device *edev; - struct ses_device *ses_dev; - - if (!scsi_device_enclosure(sdev)) - return; - - edev = enclosure_find(cdev->dev); - if (!edev) - return; - - ses_dev = edev->scratch; - edev->scratch = NULL; - - kfree(ses_dev->page1); - kfree(ses_dev->page2); - kfree(ses_dev); - - kfree(edev->component[0].scratch); - - class_device_put(&edev->cdev); - enclosure_unregister(edev); -} - -static struct class_interface ses_interface = { - .add = ses_intf_add, - .remove = ses_intf_remove, -}; - -static struct scsi_driver ses_template = { - .owner = THIS_MODULE, - .gendrv = { - .name = "ses", - .probe = ses_probe, - .remove = ses_remove, - }, -}; - -static int __init ses_init(void) -{ - int err; - - err = scsi_register_interface(&ses_interface); - if (err) - return err; - - err = scsi_register_driver(&ses_template.gendrv); - if (err) - goto out_unreg; - - return 0; - - out_unreg: - scsi_unregister_interface(&ses_interface); - return err; -} - -static void __exit ses_exit(void) -{ - scsi_unregister_driver(&ses_template.gendrv); - scsi_unregister_interface(&ses_interface); -} - -module_init(ses_init); -module_exit(ses_exit); - -MODULE_ALIAS_SCSI_DEVICE(TYPE_ENCLOSURE); - -MODULE_AUTHOR("James Bottomley"); -MODULE_DESCRIPTION("SCSI Enclosure Services (ses) driver"); -MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/scsi/sg.c b/trunk/drivers/scsi/sg.c index e5156aa6dd20..aba28f335b88 100644 --- a/trunk/drivers/scsi/sg.c +++ b/trunk/drivers/scsi/sg.c @@ -1160,22 +1160,23 @@ sg_fasync(int fd, struct file *filp, int mode) return (retval < 0) ? retval : 0; } -static int -sg_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +static struct page * +sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type) { 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 VM_FAULT_SIGBUS; + return page; rsv_schp = &sfp->reserve; - offset = vmf->pgoff << PAGE_SHIFT; + offset = addr - vma->vm_start; if (offset >= rsv_schp->bufflen) - return VM_FAULT_SIGBUS; - SCSI_LOG_TIMEOUT(3, printk("sg_vma_fault: offset=%lu, scatg=%d\n", + return page; + SCSI_LOG_TIMEOUT(3, printk("sg_vma_nopage: offset=%lu, scatg=%d\n", offset, rsv_schp->k_use_sg)); sg = rsv_schp->buffer; sa = vma->vm_start; @@ -1184,21 +1185,21 @@ sg_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 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 */ - vmf->page = page; - return 0; /* success */ + break; } sa += len; offset -= len; } - return VM_FAULT_SIGBUS; + if (type) + *type = VM_FAULT_MINOR; + return page; } static struct vm_operations_struct sg_mmap_vm_ops = { - .fault = sg_vma_fault, + .nopage = sg_vma_nopage, }; static int diff --git a/trunk/drivers/scsi/sr.c b/trunk/drivers/scsi/sr.c index 208565bdbe8e..50ba49250203 100644 --- a/trunk/drivers/scsi/sr.c +++ b/trunk/drivers/scsi/sr.c @@ -163,29 +163,6 @@ static void scsi_cd_put(struct scsi_cd *cd) mutex_unlock(&sr_ref_mutex); } -/* identical to scsi_test_unit_ready except that it doesn't - * eat the NOT_READY returns for removable media */ -int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr) -{ - int retries = MAX_RETRIES; - int the_result; - u8 cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0 }; - - /* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION - * conditions are gone, or a timeout happens - */ - do { - the_result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, - 0, sshdr, SR_TIMEOUT, - retries--); - - } while (retries > 0 && - (!scsi_status_is_good(the_result) || - (scsi_sense_valid(sshdr) && - sshdr->sense_key == UNIT_ATTENTION))); - return the_result; -} - /* * This function checks to see if the media has been changed in the * CDROM drive. It is possible that we have already sensed a change, @@ -208,7 +185,8 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot) } sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); - retval = sr_test_unit_ready(cd->device, sshdr); + retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, + sshdr); if (retval || (scsi_sense_valid(sshdr) && /* 0x3a is medium not present */ sshdr->asc == 0x3a)) { @@ -755,8 +733,10 @@ static void get_capabilities(struct scsi_cd *cd) { unsigned char *buffer; struct scsi_mode_data data; + unsigned char cmd[MAX_COMMAND_SIZE]; struct scsi_sense_hdr sshdr; - int rc, n; + unsigned int the_result; + int retries, rc, n; static const char *loadmech[] = { @@ -778,8 +758,23 @@ static void get_capabilities(struct scsi_cd *cd) return; } - /* eat unit attentions */ - sr_test_unit_ready(cd->device, &sshdr); + /* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION + * conditions are gone, or a timeout happens + */ + retries = 0; + do { + memset((void *)cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = TEST_UNIT_READY; + + the_result = scsi_execute_req (cd->device, cmd, DMA_NONE, NULL, + 0, &sshdr, SR_TIMEOUT, + MAX_RETRIES); + + retries++; + } while (retries < 5 && + (!scsi_status_is_good(the_result) || + (scsi_sense_valid(&sshdr) && + sshdr.sense_key == UNIT_ATTENTION))); /* ask for mode page 0x2a */ rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, diff --git a/trunk/drivers/scsi/sr.h b/trunk/drivers/scsi/sr.h index 1e144dfdbd4b..81fbc0b78a52 100644 --- a/trunk/drivers/scsi/sr.h +++ b/trunk/drivers/scsi/sr.h @@ -61,7 +61,6 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed); int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); int sr_is_xa(Scsi_CD *); -int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr); /* sr_vendor.c */ void sr_vendor_init(Scsi_CD *); diff --git a/trunk/drivers/scsi/sr_ioctl.c b/trunk/drivers/scsi/sr_ioctl.c index ae87d08df588..d5cebff1d646 100644 --- a/trunk/drivers/scsi/sr_ioctl.c +++ b/trunk/drivers/scsi/sr_ioctl.c @@ -306,7 +306,8 @@ int sr_drive_status(struct cdrom_device_info *cdi, int slot) /* we have no changer support */ return -EINVAL; } - if (0 == sr_test_unit_ready(cd->device, &sshdr)) + if (0 == scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, + &sshdr)) return CDS_DISC_OK; if (!cdrom_get_media_event(cdi, &med)) { diff --git a/trunk/drivers/scsi/sun3x_esp.c b/trunk/drivers/scsi/sun3x_esp.c index 06152c7fa689..1bc41907a038 100644 --- a/trunk/drivers/scsi/sun3x_esp.c +++ b/trunk/drivers/scsi/sun3x_esp.c @@ -1,316 +1,392 @@ -/* sun3x_esp.c: ESP front-end for Sun3x systems. +/* sun3x_esp.c: EnhancedScsiProcessor Sun3x SCSI driver code. * - * Copyright (C) 2007,2008 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * + * Based on David S. Miller's esp driver */ #include #include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include #include +#include "scsi.h" +#include +#include "NCR53C9x.h" + #include -#include -#include #include +#include + +static void dma_barrier(struct NCR_ESP *esp); +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_drain(struct NCR_ESP *esp); +static void dma_invalidate(struct NCR_ESP *esp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static void dma_poll(struct NCR_ESP *esp, unsigned char *vaddr); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_reset(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); +static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp); +static void dma_advance_sg (Scsi_Cmnd *sp); + +/* Detecting ESP chips on the machine. This is the simple and easy + * version. + */ +int sun3x_esp_detect(struct scsi_host_template *tpnt) +{ + struct NCR_ESP *esp; + struct ConfigDev *esp_dev; + + esp_dev = 0; + esp = esp_allocate(tpnt, esp_dev, 0); + + /* Do command transfer with DMA */ + esp->do_pio_cmds = 0; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = &dma_barrier; + esp->dma_invalidate = &dma_invalidate; + esp->dma_drain = &dma_drain; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_led_on = 0; + esp->dma_led_off = 0; + esp->dma_poll = &dma_poll; + esp->dma_reset = &dma_reset; + + /* virtual DMA functions */ + esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; + esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one; + esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl; + esp->dma_advance_sg = &dma_advance_sg; + + /* SCSI chip speed */ + esp->cfreq = 20000000; + esp->eregs = (struct ESP_regs *)(SUN3X_ESP_BASE); + esp->dregs = (void *)SUN3X_ESP_DMA; -/* DMA controller reg offsets */ -#define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */ -#define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */ -#define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */ -#define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */ + esp->esp_command = (volatile unsigned char *)dvma_malloc(DVMA_PAGE_SIZE); + esp->esp_command_dvma = dvma_vtob((unsigned long)esp->esp_command); -#include + esp->irq = 2; + if (request_irq(esp->irq, esp_intr, IRQF_DISABLED, + "SUN3X SCSI", esp->ehost)) { + esp_deallocate(esp); + return 0; + } -#include "esp_scsi.h" + esp->scsi_id = 7; + esp->diff = 0; -#define DRV_MODULE_NAME "sun3x_esp" -#define PFX DRV_MODULE_NAME ": " -#define DRV_VERSION "1.000" -#define DRV_MODULE_RELDATE "Nov 1, 2007" + esp_initialize(esp); -/* - * m68k always assumes readl/writel operate on little endian - * mmio space; this is wrong at least for Sun3x, so we - * need to workaround this until a proper way is found - */ -#if 0 -#define dma_read32(REG) \ - readl(esp->dma_regs + (REG)) -#define dma_write32(VAL, REG) \ - writel((VAL), esp->dma_regs + (REG)) -#else -#define dma_read32(REG) \ - *(volatile u32 *)(esp->dma_regs + (REG)) -#define dma_write32(VAL, REG) \ - do { *(volatile u32 *)(esp->dma_regs + (REG)) = (VAL); } while (0) -#endif - -static void sun3x_esp_write8(struct esp *esp, u8 val, unsigned long reg) -{ - writeb(val, esp->regs + (reg * 4UL)); -} + /* for reasons beyond my knowledge (and which should likely be fixed) + sync mode doesn't work on a 3/80 at 5mhz. but it does at 4. */ + esp->sync_defp = 0x3f; -static u8 sun3x_esp_read8(struct esp *esp, unsigned long reg) -{ - return readb(esp->regs + (reg * 4UL)); + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, + esps_in_use); + esps_running = esps_in_use; + return esps_in_use; } -static dma_addr_t sun3x_esp_map_single(struct esp *esp, void *buf, - size_t sz, int dir) +static void dma_do_drain(struct NCR_ESP *esp) { - return dma_map_single(esp->dev, buf, sz, dir); + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + + int count = 500000; + + while((dregs->cond_reg & DMA_PEND_READ) && (--count > 0)) + udelay(1); + + if(!count) { + printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); + } + + dregs->cond_reg |= DMA_FIFO_STDRAIN; + + count = 500000; + + while((dregs->cond_reg & DMA_FIFO_ISDRAIN) && (--count > 0)) + udelay(1); + + if(!count) { + printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); + } + } - -static int sun3x_esp_map_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) + +static void dma_barrier(struct NCR_ESP *esp) { - return dma_map_sg(esp->dev, sg, num_sg, dir); + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + int count = 500000; + + while((dregs->cond_reg & DMA_PEND_READ) && (--count > 0)) + udelay(1); + + if(!count) { + printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); + } + + dregs->cond_reg &= ~(DMA_ENABLE); } -static void sun3x_esp_unmap_single(struct esp *esp, dma_addr_t addr, - size_t sz, int dir) +/* This uses various DMA csr fields and the fifo flags count value to + * determine how many bytes were successfully sent/received by the ESP. + */ +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) { - dma_unmap_single(esp->dev, addr, sz, dir); -} + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; -static void sun3x_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - dma_unmap_sg(esp->dev, sg, num_sg, dir); + int rval = dregs->st_addr - esp->esp_command_dvma; + + return rval - fifo_count; } -static int sun3x_esp_irq_pending(struct esp *esp) +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) { - if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) - return 1; - return 0; + return sp->SCp.this_residual; } -static void sun3x_esp_reset_dma(struct esp *esp) +static void dma_drain(struct NCR_ESP *esp) { - u32 val; - - val = dma_read32(DMA_CSR); - dma_write32(val | DMA_RST_SCSI, DMA_CSR); - dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + int count = 500000; + + if(dregs->cond_reg & DMA_FIFO_ISDRAIN) { + dregs->cond_reg |= DMA_FIFO_STDRAIN; + while((dregs->cond_reg & DMA_FIFO_ISDRAIN) && (--count > 0)) + udelay(1); + if(!count) { + printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); + } - /* Enable interrupts. */ - val = dma_read32(DMA_CSR); - dma_write32(val | DMA_INT_ENAB, DMA_CSR); + } } -static void sun3x_esp_dma_drain(struct esp *esp) +static void dma_invalidate(struct NCR_ESP *esp) { - u32 csr; - int lim; - - csr = dma_read32(DMA_CSR); - if (!(csr & DMA_FIFO_ISDRAIN)) - return; + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; - dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR); + __u32 tmp; + int count = 500000; - lim = 1000; - while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n", - esp->host->unique_id); - break; - } + while(((tmp = dregs->cond_reg) & DMA_PEND_READ) && (--count > 0)) udelay(1); + + if(!count) { + printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); } + + dregs->cond_reg = tmp | DMA_FIFO_INV; + dregs->cond_reg &= ~DMA_FIFO_INV; + } -static void sun3x_esp_dma_invalidate(struct esp *esp) +static void dma_dump_state(struct NCR_ESP *esp) { - u32 val; - int lim; - - lim = 1000; - while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: DMA will not " - "invalidate!\n", esp->host->unique_id); - break; - } - udelay(1); - } + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; - val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); - val |= DMA_FIFO_INV; - dma_write32(val, DMA_CSR); - val &= ~DMA_FIFO_INV; - dma_write32(val, DMA_CSR); + ESPLOG(("esp%d: dma -- cond_reg<%08lx> addr<%08lx>\n", + esp->esp_id, dregs->cond_reg, dregs->st_addr)); } -static void sun3x_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, - u32 dma_count, int write, u8 cmd) +static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) { - u32 csr; - - BUG_ON(!(cmd & ESP_CMD_DMA)); - - sun3x_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); - sun3x_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); - csr = dma_read32(DMA_CSR); - csr |= DMA_ENABLE; - if (write) - csr |= DMA_ST_WRITE; - else - csr &= ~DMA_ST_WRITE; - dma_write32(csr, DMA_CSR); - dma_write32(addr, DMA_ADDR); - - scsi_esp_cmd(esp, cmd); + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + + dregs->st_addr = vaddress; + dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE); } -static int sun3x_esp_dma_error(struct esp *esp) +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length) { - u32 csr = dma_read32(DMA_CSR); + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; - if (csr & DMA_HNDL_ERROR) - return 1; + /* Set up the DMA counters */ - return 0; + dregs->st_addr = vaddress; + dregs->cond_reg = ((dregs->cond_reg & ~(DMA_ST_WRITE)) | DMA_ENABLE); } -static const struct esp_driver_ops sun3x_esp_ops = { - .esp_write8 = sun3x_esp_write8, - .esp_read8 = sun3x_esp_read8, - .map_single = sun3x_esp_map_single, - .map_sg = sun3x_esp_map_sg, - .unmap_single = sun3x_esp_unmap_single, - .unmap_sg = sun3x_esp_unmap_sg, - .irq_pending = sun3x_esp_irq_pending, - .reset_dma = sun3x_esp_reset_dma, - .dma_drain = sun3x_esp_dma_drain, - .dma_invalidate = sun3x_esp_dma_invalidate, - .send_dma_cmd = sun3x_esp_send_dma_cmd, - .dma_error = sun3x_esp_dma_error, -}; - -static int __devinit esp_sun3x_probe(struct platform_device *dev) +static void dma_ints_off(struct NCR_ESP *esp) { - struct scsi_host_template *tpnt = &scsi_esp_template; - struct Scsi_Host *host; - struct esp *esp; - struct resource *res; - int err = -ENOMEM; - - host = scsi_host_alloc(tpnt, sizeof(struct esp)); - if (!host) - goto fail; - - host->max_id = 8; - esp = shost_priv(host); + DMA_INTSOFF((struct sparc_dma_registers *) esp->dregs); +} - esp->host = host; - esp->dev = dev; - esp->ops = &sun3x_esp_ops; +static void dma_ints_on(struct NCR_ESP *esp) +{ + DMA_INTSON((struct sparc_dma_registers *) esp->dregs); +} - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res && !res->start) - goto fail_unlink; +static int dma_irq_p(struct NCR_ESP *esp) +{ + return DMA_IRQ_P((struct sparc_dma_registers *) esp->dregs); +} - esp->regs = ioremap_nocache(res->start, 0x20); - if (!esp->regs) - goto fail_unmap_regs; +static void dma_poll(struct NCR_ESP *esp, unsigned char *vaddr) +{ + int count = 50; + dma_do_drain(esp); - res = platform_get_resource(dev, IORESOURCE_MEM, 1); - if (!res && !res->start) - goto fail_unmap_regs; + /* Wait till the first bits settle. */ + while((*(volatile unsigned char *)vaddr == 0xff) && (--count > 0)) + udelay(1); - esp->dma_regs = ioremap_nocache(res->start, 0x10); + if(!count) { +// printk("%s:%d timeout expire (data %02x)\n", __FILE__, __LINE__, +// esp_read(esp->eregs->esp_fdata)); + //mach_halt(); + vaddr[0] = esp_read(esp->eregs->esp_fdata); + vaddr[1] = esp_read(esp->eregs->esp_fdata); + } - esp->command_block = dma_alloc_coherent(esp->dev, 16, - &esp->command_block_dma, - GFP_KERNEL); - if (!esp->command_block) - goto fail_unmap_regs_dma; +} - host->irq = platform_get_irq(dev, 0); - err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, - "SUN3X ESP", esp); - if (err < 0) - goto fail_unmap_command_block; +static int dma_ports_p(struct NCR_ESP *esp) +{ + return (((struct sparc_dma_registers *) esp->dregs)->cond_reg + & DMA_INT_ENAB); +} - esp->scsi_id = 7; - esp->host->this_id = esp->scsi_id; - esp->scsi_id_mask = (1 << esp->scsi_id); - esp->cfreq = 20000000; +/* Resetting various pieces of the ESP scsi driver chipset/buses. */ +static void dma_reset(struct NCR_ESP *esp) +{ + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *)esp->dregs; - dev_set_drvdata(&dev->dev, esp); - - err = scsi_esp_register(esp, &dev->dev); - if (err) - goto fail_free_irq; - - return 0; - -fail_free_irq: - free_irq(host->irq, esp); -fail_unmap_command_block: - dma_free_coherent(esp->dev, 16, - esp->command_block, - esp->command_block_dma); -fail_unmap_regs_dma: - iounmap(esp->dma_regs); -fail_unmap_regs: - iounmap(esp->regs); -fail_unlink: - scsi_host_put(host); -fail: - return err; + /* Punt the DVMA into a known state. */ + dregs->cond_reg |= DMA_RST_SCSI; + dregs->cond_reg &= ~(DMA_RST_SCSI); + DMA_INTSON(dregs); } -static int __devexit esp_sun3x_remove(struct platform_device *dev) +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) { - struct esp *esp = dev_get_drvdata(&dev->dev); - unsigned int irq = esp->host->irq; - u32 val; + struct sparc_dma_registers *dregs = + (struct sparc_dma_registers *) esp->dregs; + unsigned long nreg = dregs->cond_reg; + +// printk("dma_setup %c addr %08x cnt %08x\n", +// write ? 'W' : 'R', addr, count); - scsi_esp_unregister(esp); + dma_do_drain(esp); - /* Disable interrupts. */ - val = dma_read32(DMA_CSR); - dma_write32(val & ~DMA_INT_ENAB, DMA_CSR); + if(write) + nreg |= DMA_ST_WRITE; + else { + nreg &= ~(DMA_ST_WRITE); + } + + nreg |= DMA_ENABLE; + dregs->cond_reg = nreg; + dregs->st_addr = addr; +} - free_irq(irq, esp); - dma_free_coherent(esp->dev, 16, - esp->command_block, - esp->command_block_dma); +static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + sp->SCp.have_data_in = dvma_map((unsigned long)sp->SCp.buffer, + sp->SCp.this_residual); + sp->SCp.ptr = (char *)((unsigned long)sp->SCp.have_data_in); +} - scsi_host_put(esp->host); +static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + int sz = sp->SCp.buffers_residual; + struct scatterlist *sg = sp->SCp.buffer; + + while (sz >= 0) { + sg[sz].dma_address = dvma_map((unsigned long)sg_virt(&sg[sz]), + sg[sz].length); + sz--; + } + sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dma_address); +} - return 0; +static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + dvma_unmap((char *)sp->SCp.have_data_in); } -static struct platform_driver esp_sun3x_driver = { - .probe = esp_sun3x_probe, - .remove = __devexit_p(esp_sun3x_remove), - .driver = { - .name = "sun3x_esp", - }, -}; +static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp) +{ + int sz = sp->use_sg - 1; + struct scatterlist *sg = (struct scatterlist *)sp->request_buffer; + + while(sz >= 0) { + dvma_unmap((char *)sg[sz].dma_address); + sz--; + } +} -static int __init sun3x_esp_init(void) +static void dma_advance_sg (Scsi_Cmnd *sp) { - return platform_driver_register(&esp_sun3x_driver); + sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dma_address); } -static void __exit sun3x_esp_exit(void) +static int sun3x_esp_release(struct Scsi_Host *instance) { - platform_driver_unregister(&esp_sun3x_driver); + /* this code does not support being compiled as a module */ + return 1; + } -MODULE_DESCRIPTION("Sun3x ESP SCSI driver"); -MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); +static struct scsi_host_template driver_template = { + .proc_name = "sun3x_esp", + .proc_info = &esp_proc_info, + .name = "Sun ESP 100/100a/200", + .detect = sun3x_esp_detect, + .release = sun3x_esp_release, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, + .info = esp_info, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING, +}; + -module_init(sun3x_esp_init); -module_exit(sun3x_esp_exit); +#include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/sym53c8xx_2/sym_hipd.c b/trunk/drivers/scsi/sym53c8xx_2/sym_hipd.c index 35142b5341b5..254bdaeb35ff 100644 --- a/trunk/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/trunk/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -3842,7 +3842,7 @@ int sym_compute_residual(struct sym_hcb *np, struct sym_ccb *cp) if (cp->startp == cp->phys.head.lastp || sym_evaluate_dp(np, cp, scr_to_cpu(cp->phys.head.lastp), &dp_ofs) < 0) { - return cp->data_len - cp->odd_byte_adjustment; + return cp->data_len; } /* diff --git a/trunk/drivers/scsi/u14-34f.c b/trunk/drivers/scsi/u14-34f.c index 58d7eee4fe81..662c00451be4 100644 --- a/trunk/drivers/scsi/u14-34f.c +++ b/trunk/drivers/scsi/u14-34f.c @@ -1216,7 +1216,7 @@ static void scsi_to_dev_dir(unsigned int i, unsigned int j) { cpp->xdir = DTD_IN; return; } - else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) { + else if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) { cpp->xdir = DTD_OUT; return; } diff --git a/trunk/fs/Kconfig b/trunk/fs/Kconfig index d7312825592b..3bf6ace1720c 100644 --- a/trunk/fs/Kconfig +++ b/trunk/fs/Kconfig @@ -1778,9 +1778,12 @@ config SUNRPC_GSS tristate config SUNRPC_XPRT_RDMA - tristate + tristate "RDMA transport for sunrpc (EXPERIMENTAL)" depends on SUNRPC && INFINIBAND && EXPERIMENTAL - default SUNRPC && INFINIBAND + default m + help + Adds a client RPC transport for supporting kernel NFS over RDMA + mounts, including Infiniband and iWARP. Experimental. config SUNRPC_BIND34 bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)" diff --git a/trunk/fs/nfs/write.c b/trunk/fs/nfs/write.c index f55c437124a2..b144b1957dd9 100644 --- a/trunk/fs/nfs/write.c +++ b/trunk/fs/nfs/write.c @@ -696,17 +696,6 @@ int nfs_flush_incompatible(struct file *file, struct page *page) return status; } -/* - * If the page cache is marked as unsafe or invalid, then we can't rely on - * the PageUptodate() flag. In this case, we will need to turn off - * write optimisations that depend on the page contents being correct. - */ -static int nfs_write_pageuptodate(struct page *page, struct inode *inode) -{ - return PageUptodate(page) && - !(NFS_I(inode)->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA)); -} - /* * Update and possibly write a cached page of an NFS file. * @@ -728,13 +717,10 @@ int nfs_updatepage(struct file *file, struct page *page, (long long)(page_offset(page) +offset)); /* If we're not using byte range locks, and we know the page - * is up to date, it may be more efficient to extend the write - * to cover the entire page in order to avoid fragmentation - * inefficiencies. + * is entirely in cache, it may be more efficient to avoid + * fragmenting write requests. */ - if (nfs_write_pageuptodate(page, inode) && - inode->i_flock == NULL && - !(file->f_mode & O_SYNC)) { + if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { count = max(count + offset, nfs_page_length(page)); offset = 0; } diff --git a/trunk/fs/xfs/Makefile-linux-2.6 b/trunk/fs/xfs/Makefile-linux-2.6 index 97316451fc6d..d1491aa7a0e2 100644 --- a/trunk/fs/xfs/Makefile-linux-2.6 +++ b/trunk/fs/xfs/Makefile-linux-2.6 @@ -70,6 +70,7 @@ xfs-y += xfs_alloc.o \ xfs_iget.o \ xfs_inode.o \ xfs_inode_item.o \ + xfs_iocore.o \ xfs_iomap.o \ xfs_itable.o \ xfs_dfrag.o \ diff --git a/trunk/fs/xfs/linux-2.6/spin.h b/trunk/fs/xfs/linux-2.6/spin.h new file mode 100644 index 000000000000..50a6191178f4 --- /dev/null +++ b/trunk/fs/xfs/linux-2.6/spin.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would 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 the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __XFS_SUPPORT_SPIN_H__ +#define __XFS_SUPPORT_SPIN_H__ + +#include /* preempt needs this */ +#include + +/* + * Map lock_t from IRIX to Linux spinlocks. + * + * We do not make use of lock_t from interrupt context, so we do not + * have to worry about disabling interrupts at all (unlike IRIX). + */ + +typedef spinlock_t lock_t; + +#define SPLDECL(s) unsigned long s +#ifndef DEFINE_SPINLOCK +#define DEFINE_SPINLOCK(s) spinlock_t s = SPIN_LOCK_UNLOCKED +#endif + +#define spinlock_init(lock, name) spin_lock_init(lock) +#define spinlock_destroy(lock) +#define mutex_spinlock(lock) ({ spin_lock(lock); 0; }) +#define mutex_spinunlock(lock, s) do { spin_unlock(lock); (void)s; } while (0) +#define nested_spinlock(lock) spin_lock(lock) +#define nested_spinunlock(lock) spin_unlock(lock) + +#endif /* __XFS_SUPPORT_SPIN_H__ */ diff --git a/trunk/fs/xfs/linux-2.6/xfs_aops.c b/trunk/fs/xfs/linux-2.6/xfs_aops.c index e0519529c26c..2e34b104107c 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_aops.c +++ b/trunk/fs/xfs/linux-2.6/xfs_aops.c @@ -107,18 +107,6 @@ xfs_page_trace( #define xfs_page_trace(tag, inode, page, pgoff) #endif -STATIC struct block_device * -xfs_find_bdev_for_inode( - struct xfs_inode *ip) -{ - struct xfs_mount *mp = ip->i_mount; - - if (XFS_IS_REALTIME_INODE(ip)) - return mp->m_rtdev_targp->bt_bdev; - else - return mp->m_ddev_targp->bt_bdev; -} - /* * Schedule IO completion handling on a xfsdatad if this was * the final hold on this ioend. If we are asked to wait, @@ -163,7 +151,7 @@ xfs_destroy_ioend( /* * Update on-disk file size now that data has been written to disk. * The current in-memory file size is i_size. If a write is beyond - * eof i_new_size will be the intended file size until i_size is + * eof io_new_size will be the intended file size until i_size is * updated. If this write does not extend all the way to the valid * file size then restrict this update to the end of the write. */ @@ -185,7 +173,7 @@ xfs_setfilesize( xfs_ilock(ip, XFS_ILOCK_EXCL); - isize = MAX(ip->i_size, ip->i_new_size); + isize = MAX(ip->i_size, ip->i_iocore.io_new_size); isize = MIN(isize, bsize); if (ip->i_d.di_size < isize) { @@ -238,13 +226,12 @@ xfs_end_bio_unwritten( { xfs_ioend_t *ioend = container_of(work, xfs_ioend_t, io_work); - struct xfs_inode *ip = XFS_I(ioend->io_inode); xfs_off_t offset = ioend->io_offset; size_t size = ioend->io_size; if (likely(!ioend->io_error)) { - if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) - xfs_iomap_write_unwritten(ip, offset, size); + xfs_bmap(XFS_I(ioend->io_inode), offset, size, + BMAPI_UNWRITTEN, NULL, NULL); xfs_setfilesize(ioend); } xfs_destroy_ioend(ioend); @@ -317,7 +304,7 @@ xfs_map_blocks( xfs_inode_t *ip = XFS_I(inode); int error, nmaps = 1; - error = xfs_iomap(ip, offset, count, + error = xfs_bmap(ip, offset, count, flags, mapp, &nmaps); if (!error && (flags & (BMAPI_WRITE|BMAPI_ALLOCATE))) xfs_iflags_set(ip, XFS_IMODIFIED); @@ -1336,7 +1323,7 @@ __xfs_get_blocks( offset = (xfs_off_t)iblock << inode->i_blkbits; ASSERT(bh_result->b_size >= (1 << inode->i_blkbits)); size = bh_result->b_size; - error = xfs_iomap(XFS_I(inode), offset, size, + error = xfs_bmap(XFS_I(inode), offset, size, create ? flags : BMAPI_READ, &iomap, &niomap); if (error) return -error; @@ -1484,21 +1471,28 @@ xfs_vm_direct_IO( { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - struct block_device *bdev; + xfs_iomap_t iomap; + int maps = 1; + int error; ssize_t ret; - bdev = xfs_find_bdev_for_inode(XFS_I(inode)); + error = xfs_bmap(XFS_I(inode), offset, 0, + BMAPI_DEVICE, &iomap, &maps); + if (error) + return -error; if (rw == WRITE) { iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN); ret = blockdev_direct_IO_own_locking(rw, iocb, inode, - bdev, iov, offset, nr_segs, + iomap.iomap_target->bt_bdev, + iov, offset, nr_segs, xfs_get_blocks_direct, xfs_end_io_direct); } else { iocb->private = xfs_alloc_ioend(inode, IOMAP_READ); ret = blockdev_direct_IO_no_locking(rw, iocb, inode, - bdev, iov, offset, nr_segs, + iomap.iomap_target->bt_bdev, + iov, offset, nr_segs, xfs_get_blocks_direct, xfs_end_io_direct); } @@ -1531,7 +1525,8 @@ xfs_vm_bmap( struct inode *inode = (struct inode *)mapping->host; struct xfs_inode *ip = XFS_I(inode); - xfs_itrace_entry(XFS_I(inode)); + vn_trace_entry(XFS_I(inode), __FUNCTION__, + (inst_t *)__return_address); xfs_rwlock(ip, VRWLOCK_READ); xfs_flush_pages(ip, (xfs_off_t)0, -1, 0, FI_REMAPF); xfs_rwunlock(ip, VRWLOCK_READ); diff --git a/trunk/fs/xfs/linux-2.6/xfs_buf.c b/trunk/fs/xfs/linux-2.6/xfs_buf.c index e347bfd47c91..0382c19d6523 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_buf.c +++ b/trunk/fs/xfs/linux-2.6/xfs_buf.c @@ -387,6 +387,8 @@ _xfs_buf_lookup_pages( if (unlikely(page == NULL)) { if (flags & XBF_READ_AHEAD) { bp->b_page_count = i; + for (i = 0; i < bp->b_page_count; i++) + unlock_page(bp->b_pages[i]); return -ENOMEM; } @@ -416,17 +418,24 @@ _xfs_buf_lookup_pages( ASSERT(!PagePrivate(page)); if (!PageUptodate(page)) { page_count--; - if (blocksize < PAGE_CACHE_SIZE && !PagePrivate(page)) { + if (blocksize >= PAGE_CACHE_SIZE) { + if (flags & XBF_READ) + bp->b_locked = 1; + } else if (!PagePrivate(page)) { if (test_page_region(page, offset, nbytes)) page_count++; } } - unlock_page(page); bp->b_pages[i] = page; offset = 0; } + if (!bp->b_locked) { + for (i = 0; i < bp->b_page_count; i++) + unlock_page(bp->b_pages[i]); + } + if (page_count == bp->b_page_count) bp->b_flags |= XBF_DONE; @@ -742,6 +751,7 @@ xfs_buf_associate_memory( bp->b_pages[i] = mem_to_page((void *)pageaddr); pageaddr += PAGE_CACHE_SIZE; } + bp->b_locked = 0; bp->b_count_desired = len; bp->b_buffer_length = buflen; @@ -1088,13 +1098,25 @@ xfs_buf_iostart( return status; } +STATIC_INLINE int +_xfs_buf_iolocked( + xfs_buf_t *bp) +{ + ASSERT(bp->b_flags & (XBF_READ | XBF_WRITE)); + if (bp->b_flags & XBF_READ) + return bp->b_locked; + return 0; +} + STATIC_INLINE void _xfs_buf_ioend( xfs_buf_t *bp, int schedule) { - if (atomic_dec_and_test(&bp->b_io_remaining) == 1) + if (atomic_dec_and_test(&bp->b_io_remaining) == 1) { + bp->b_locked = 0; xfs_buf_ioend(bp, schedule); + } } STATIC void @@ -1125,6 +1147,10 @@ xfs_buf_bio_end_io( if (--bvec >= bio->bi_io_vec) prefetchw(&bvec->bv_page->flags); + + if (_xfs_buf_iolocked(bp)) { + unlock_page(page); + } } while (bvec >= bio->bi_io_vec); _xfs_buf_ioend(bp, 1); @@ -1135,12 +1161,13 @@ STATIC void _xfs_buf_ioapply( xfs_buf_t *bp) { - int rw, map_i, total_nr_pages, nr_pages; + int i, rw, map_i, total_nr_pages, nr_pages; struct bio *bio; int offset = bp->b_offset; int size = bp->b_count_desired; sector_t sector = bp->b_bn; unsigned int blocksize = bp->b_target->bt_bsize; + int locking = _xfs_buf_iolocked(bp); total_nr_pages = bp->b_page_count; map_i = 0; @@ -1163,7 +1190,7 @@ _xfs_buf_ioapply( * filesystem block size is not smaller than the page size. */ if ((bp->b_buffer_length < PAGE_CACHE_SIZE) && - (bp->b_flags & XBF_READ) && + (bp->b_flags & XBF_READ) && locking && (blocksize >= PAGE_CACHE_SIZE)) { bio = bio_alloc(GFP_NOIO, 1); @@ -1180,6 +1207,24 @@ _xfs_buf_ioapply( goto submit_io; } + /* Lock down the pages which we need to for the request */ + if (locking && (bp->b_flags & XBF_WRITE) && (bp->b_locked == 0)) { + for (i = 0; size; i++) { + int nbytes = PAGE_CACHE_SIZE - offset; + struct page *page = bp->b_pages[i]; + + if (nbytes > size) + nbytes = size; + + lock_page(page); + + size -= nbytes; + offset = 0; + } + offset = bp->b_offset; + size = bp->b_count_desired; + } + next_chunk: atomic_inc(&bp->b_io_remaining); nr_pages = BIO_MAX_SECTORS >> (PAGE_SHIFT - BBSHIFT); @@ -1526,7 +1571,7 @@ xfs_alloc_delwrite_queue( INIT_LIST_HEAD(&btp->bt_list); INIT_LIST_HEAD(&btp->bt_delwrite_queue); - spin_lock_init(&btp->bt_delwrite_lock); + spinlock_init(&btp->bt_delwrite_lock, "delwri_lock"); btp->bt_flags = 0; btp->bt_task = kthread_run(xfsbufd, btp, "xfsbufd"); if (IS_ERR(btp->bt_task)) { diff --git a/trunk/fs/xfs/linux-2.6/xfs_buf.h b/trunk/fs/xfs/linux-2.6/xfs_buf.h index a3d207de48b8..b5908a34b15d 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_buf.h +++ b/trunk/fs/xfs/linux-2.6/xfs_buf.h @@ -143,6 +143,7 @@ typedef struct xfs_buf { void *b_fspriv2; void *b_fspriv3; unsigned short b_error; /* error code on I/O */ + unsigned short b_locked; /* page array is locked */ unsigned int b_page_count; /* size of page array */ unsigned int b_offset; /* page offset in first page */ struct page **b_pages; /* array of page pointers */ diff --git a/trunk/fs/xfs/linux-2.6/xfs_export.c b/trunk/fs/xfs/linux-2.6/xfs_export.c index ca4f66c4de16..15bd4948832c 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_export.c +++ b/trunk/fs/xfs/linux-2.6/xfs_export.c @@ -118,29 +118,20 @@ xfs_nfs_get_inode( u64 ino, u32 generation) { - xfs_mount_t *mp = XFS_M(sb); - xfs_inode_t *ip; + xfs_fid_t xfid; + bhv_vnode_t *vp; int error; - /* - * NFS can sometimes send requests for ino 0. Fail them gracefully. - */ - if (ino == 0) - return ERR_PTR(-ESTALE); + xfid.fid_len = sizeof(xfs_fid_t) - sizeof(xfid.fid_len); + xfid.fid_pad = 0; + xfid.fid_ino = ino; + xfid.fid_gen = generation; - error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0); + error = xfs_vget(XFS_M(sb), &vp, &xfid); if (error) return ERR_PTR(-error); - if (!ip) - return ERR_PTR(-EIO); - - if (!ip->i_d.di_mode || ip->i_d.di_gen != generation) { - xfs_iput_new(ip, XFS_ILOCK_SHARED); - return ERR_PTR(-ENOENT); - } - xfs_iunlock(ip, XFS_ILOCK_SHARED); - return ip->i_vnode; + return vp ? vn_to_inode(vp) : NULL; } STATIC struct dentry * diff --git a/trunk/fs/xfs/linux-2.6/xfs_file.c b/trunk/fs/xfs/linux-2.6/xfs_file.c index edab1ffbb163..21a1c2b1c5fc 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_file.c +++ b/trunk/fs/xfs/linux-2.6/xfs_file.c @@ -350,8 +350,8 @@ xfs_file_readdir( size = buf.used; de = (struct hack_dirent *)buf.dirent; + curr_offset = de->offset /* & 0x7fffffff */; while (size > 0) { - curr_offset = de->offset /* & 0x7fffffff */; if (filldir(dirent, de->name, de->namlen, curr_offset & 0x7fffffff, de->ino, de->d_type)) { @@ -362,6 +362,7 @@ xfs_file_readdir( sizeof(u64)); size -= reclen; de = (struct hack_dirent *)((char *)de + reclen); + curr_offset = de->offset /* & 0x7fffffff */; } } diff --git a/trunk/fs/xfs/linux-2.6/xfs_globals.c b/trunk/fs/xfs/linux-2.6/xfs_globals.c index ef90e64641e6..9febf9dc999d 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_globals.c +++ b/trunk/fs/xfs/linux-2.6/xfs_globals.c @@ -47,6 +47,5 @@ xfs_param_t xfs_params = { /* * Global system credential structure. */ -static cred_t sys_cred_val; -cred_t *sys_cred = &sys_cred_val; +cred_t sys_cred_val, *sys_cred = &sys_cred_val; diff --git a/trunk/fs/xfs/linux-2.6/xfs_ioctl.c b/trunk/fs/xfs/linux-2.6/xfs_ioctl.c index 4c82a050a3a8..98a56568bb24 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/trunk/fs/xfs/linux-2.6/xfs_ioctl.c @@ -75,6 +75,7 @@ xfs_find_handle( xfs_handle_t handle; xfs_fsop_handlereq_t hreq; struct inode *inode; + bhv_vnode_t *vp; if (copy_from_user(&hreq, arg, sizeof(hreq))) return -XFS_ERROR(EFAULT); @@ -133,16 +134,21 @@ xfs_find_handle( return -XFS_ERROR(EBADF); } + /* we need the vnode */ + vp = vn_from_inode(inode); + /* now we can grab the fsid */ memcpy(&handle.ha_fsid, XFS_I(inode)->i_mount->m_fixedfsid, sizeof(xfs_fsid_t)); hsize = sizeof(xfs_fsid_t); if (cmd != XFS_IOC_PATH_TO_FSHANDLE) { - xfs_inode_t *ip = XFS_I(inode); + xfs_inode_t *ip; int lock_mode; /* need to get access to the xfs_inode to read the generation */ + ip = xfs_vtoi(vp); + ASSERT(ip); lock_mode = xfs_ilock_map_shared(ip); /* fill in fid section of handle from inode */ @@ -170,19 +176,21 @@ xfs_find_handle( /* - * Convert userspace handle data into inode. - * - * We use the fact that all the fsop_handlereq ioctl calls have a data - * structure argument whose first component is always a xfs_fsop_handlereq_t, - * so we can pass that sub structure into this handy, shared routine. + * Convert userspace handle data into vnode (and inode). + * We [ab]use the fact that all the fsop_handlereq ioctl calls + * have a data structure argument whose first component is always + * a xfs_fsop_handlereq_t, so we can cast to and from this type. + * This allows us to optimise the copy_from_user calls and gives + * a handy, shared routine. * - * If no error, caller must always iput the returned inode. + * If no error, caller must always VN_RELE the returned vp. */ STATIC int xfs_vget_fsop_handlereq( xfs_mount_t *mp, struct inode *parinode, /* parent inode pointer */ xfs_fsop_handlereq_t *hreq, + bhv_vnode_t **vp, struct inode **inode) { void __user *hanp; @@ -191,6 +199,8 @@ xfs_vget_fsop_handlereq( xfs_handle_t *handlep; xfs_handle_t handle; xfs_inode_t *ip; + struct inode *inodep; + bhv_vnode_t *vpp; xfs_ino_t ino; __u32 igen; int error; @@ -231,7 +241,7 @@ xfs_vget_fsop_handlereq( } /* - * Get the XFS inode, building a Linux inode to go with it. + * Get the XFS inode, building a vnode to go with it. */ error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0); if (error) @@ -243,9 +253,12 @@ xfs_vget_fsop_handlereq( return XFS_ERROR(ENOENT); } + vpp = XFS_ITOV(ip); + inodep = vn_to_inode(vpp); xfs_iunlock(ip, XFS_ILOCK_SHARED); - *inode = XFS_ITOV(ip); + *vp = vpp; + *inode = inodep; return 0; } @@ -262,6 +275,7 @@ xfs_open_by_handle( struct file *filp; struct inode *inode; struct dentry *dentry; + bhv_vnode_t *vp; xfs_fsop_handlereq_t hreq; if (!capable(CAP_SYS_ADMIN)) @@ -269,7 +283,7 @@ xfs_open_by_handle( if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) return -XFS_ERROR(EFAULT); - error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &inode); + error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &vp, &inode); if (error) return -error; @@ -371,6 +385,7 @@ xfs_readlink_by_handle( { struct inode *inode; xfs_fsop_handlereq_t hreq; + bhv_vnode_t *vp; __u32 olen; void *link; int error; @@ -380,7 +395,7 @@ xfs_readlink_by_handle( if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) return -XFS_ERROR(EFAULT); - error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &inode); + error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &vp, &inode); if (error) return -error; @@ -423,32 +438,34 @@ xfs_fssetdm_by_handle( struct fsdmidata fsd; xfs_fsop_setdm_handlereq_t dmhreq; struct inode *inode; + bhv_vnode_t *vp; if (!capable(CAP_MKNOD)) return -XFS_ERROR(EPERM); if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t))) return -XFS_ERROR(EFAULT); - error = xfs_vget_fsop_handlereq(mp, parinode, &dmhreq.hreq, &inode); + error = xfs_vget_fsop_handlereq(mp, parinode, &dmhreq.hreq, &vp, &inode); if (error) return -error; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { - error = -XFS_ERROR(EPERM); - goto out; + VN_RELE(vp); + return -XFS_ERROR(EPERM); } if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) { - error = -XFS_ERROR(EFAULT); - goto out; + VN_RELE(vp); + return -XFS_ERROR(EFAULT); } - error = -xfs_set_dmattrs(XFS_I(inode), fsd.fsd_dmevmask, - fsd.fsd_dmstate); + error = xfs_set_dmattrs(xfs_vtoi(vp), + fsd.fsd_dmevmask, fsd.fsd_dmstate); - out: - iput(inode); - return error; + VN_RELE(vp); + if (error) + return -error; + return 0; } STATIC int @@ -461,6 +478,7 @@ xfs_attrlist_by_handle( attrlist_cursor_kern_t *cursor; xfs_fsop_attrlist_handlereq_t al_hreq; struct inode *inode; + bhv_vnode_t *vp; char *kbuf; if (!capable(CAP_SYS_ADMIN)) @@ -470,7 +488,8 @@ xfs_attrlist_by_handle( if (al_hreq.buflen > XATTR_LIST_MAX) return -XFS_ERROR(EINVAL); - error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq, &inode); + error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq, + &vp, &inode); if (error) goto out; @@ -490,7 +509,7 @@ xfs_attrlist_by_handle( out_kfree: kfree(kbuf); out_vn_rele: - iput(inode); + VN_RELE(vp); out: return -error; } @@ -512,7 +531,7 @@ xfs_attrmulti_attr_get( if (!kbuf) return ENOMEM; - error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags, NULL); + error = xfs_attr_get(XFS_I(inode), name, kbuf, len, flags, NULL); if (error) goto out_kfree; @@ -579,6 +598,7 @@ xfs_attrmulti_by_handle( xfs_attr_multiop_t *ops; xfs_fsop_attrmulti_handlereq_t am_hreq; struct inode *inode; + bhv_vnode_t *vp; unsigned int i, size; char *attr_name; @@ -587,7 +607,7 @@ xfs_attrmulti_by_handle( if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t))) return -XFS_ERROR(EFAULT); - error = xfs_vget_fsop_handlereq(mp, parinode, &am_hreq.hreq, &inode); + error = xfs_vget_fsop_handlereq(mp, parinode, &am_hreq.hreq, &vp, &inode); if (error) goto out; @@ -646,7 +666,7 @@ xfs_attrmulti_by_handle( out_kfree_ops: kfree(ops); out_vn_rele: - iput(inode); + VN_RELE(vp); out: return -error; } @@ -682,6 +702,7 @@ xfs_ioc_fsgeometry( STATIC int xfs_ioc_xattr( + bhv_vnode_t *vp, xfs_inode_t *ip, struct file *filp, unsigned int cmd, @@ -714,10 +735,12 @@ xfs_ioctl( void __user *arg) { struct inode *inode = filp->f_path.dentry->d_inode; + bhv_vnode_t *vp = vn_from_inode(inode); xfs_mount_t *mp = ip->i_mount; int error; - xfs_itrace_entry(XFS_I(inode)); + vn_trace_entry(XFS_I(inode), "xfs_ioctl", (inst_t *)__return_address); + switch (cmd) { case XFS_IOC_ALLOCSP: @@ -741,7 +764,7 @@ xfs_ioctl( case XFS_IOC_DIOINFO: { struct dioattr da; xfs_buftarg_t *target = - XFS_IS_REALTIME_INODE(ip) ? + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? mp->m_rtdev_targp : mp->m_ddev_targp; da.d_mem = da.d_miniosz = 1 << target->bt_sshift; @@ -773,7 +796,7 @@ xfs_ioctl( case XFS_IOC_GETXFLAGS: case XFS_IOC_SETXFLAGS: case XFS_IOC_FSSETXATTR: - return xfs_ioc_xattr(ip, filp, cmd, arg); + return xfs_ioc_xattr(vp, ip, filp, cmd, arg); case XFS_IOC_FSSETDM: { struct fsdmidata dmi; @@ -1180,6 +1203,7 @@ xfs_ioc_fsgetxattr( STATIC int xfs_ioc_xattr( + bhv_vnode_t *vp, xfs_inode_t *ip, struct file *filp, unsigned int cmd, @@ -1213,7 +1237,7 @@ xfs_ioc_xattr( error = xfs_setattr(ip, vattr, attr_flags, NULL); if (likely(!error)) - vn_revalidate(XFS_ITOV(ip)); /* update flags */ + __vn_revalidate(vp, vattr); /* update flags */ error = -error; break; } @@ -1248,7 +1272,7 @@ xfs_ioc_xattr( error = xfs_setattr(ip, vattr, attr_flags, NULL); if (likely(!error)) - vn_revalidate(XFS_ITOV(ip)); /* update flags */ + __vn_revalidate(vp, vattr); /* update flags */ error = -error; break; } diff --git a/trunk/fs/xfs/linux-2.6/xfs_ioctl32.c b/trunk/fs/xfs/linux-2.6/xfs_ioctl32.c index a4b254eb43b2..bf2a956b63c2 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/trunk/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -44,7 +44,6 @@ #include "xfs_error.h" #include "xfs_dfrag.h" #include "xfs_vnodeops.h" -#include "xfs_ioctl32.h" #define _NATIVE_IOC(cmd, type) \ _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type)) @@ -380,6 +379,9 @@ xfs_compat_ioctl( switch (cmd) { case XFS_IOC_DIOINFO: case XFS_IOC_FSGEOMETRY: + case XFS_IOC_GETVERSION: + case XFS_IOC_GETXFLAGS: + case XFS_IOC_SETXFLAGS: case XFS_IOC_FSGETXATTR: case XFS_IOC_FSSETXATTR: case XFS_IOC_FSGETXATTRA: @@ -405,11 +407,6 @@ xfs_compat_ioctl( case XFS_IOC_ERROR_CLEARALL: break; - case XFS_IOC32_GETXFLAGS: - case XFS_IOC32_SETXFLAGS: - case XFS_IOC32_GETVERSION: - cmd = _NATIVE_IOC(cmd, long); - break; #ifdef BROKEN_X86_ALIGNMENT /* xfs_flock_t has wrong u32 vs u64 alignment */ case XFS_IOC_ALLOCSP_32: diff --git a/trunk/fs/xfs/linux-2.6/xfs_iops.c b/trunk/fs/xfs/linux-2.6/xfs_iops.c index cc4abd3daa49..5e8bb7f71b5a 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_iops.c +++ b/trunk/fs/xfs/linux-2.6/xfs_iops.c @@ -52,7 +52,6 @@ #include #include #include -#include /* * Bring the atime in the XFS inode uptodate. @@ -71,22 +70,6 @@ xfs_synchronize_atime( } } -/* - * If the linux inode exists, mark it dirty. - * Used when commiting a dirty inode into a transaction so that - * the inode will get written back by the linux code - */ -void -xfs_mark_inode_dirty_sync( - xfs_inode_t *ip) -{ - bhv_vnode_t *vp; - - vp = XFS_ITOV_NULL(ip); - if (vp) - mark_inode_dirty_sync(vn_to_inode(vp)); -} - /* * Change the requested timestamp in the given inode. * We don't lock across timestamp updates, and we don't log them but @@ -201,6 +184,10 @@ xfs_validate_fields( struct xfs_inode *ip = XFS_I(inode); loff_t size; + inode->i_nlink = ip->i_d.di_nlink; + inode->i_blocks = + XFS_FSB_TO_BB(ip->i_mount, ip->i_d.di_nblocks + + ip->i_delayed_blks); /* we're under i_sem so i_size can't change under us */ size = XFS_ISIZE(ip); if (i_size_read(inode) != size) @@ -554,32 +541,13 @@ xfs_vn_put_link( } #ifdef CONFIG_XFS_POSIX_ACL -STATIC int -xfs_check_acl( - struct inode *inode, - int mask) -{ - struct xfs_inode *ip = XFS_I(inode); - int error; - - xfs_itrace_entry(ip); - - if (XFS_IFORK_Q(ip)) { - error = xfs_acl_iaccess(ip, mask, NULL); - if (error != -1) - return -error; - } - - return -EAGAIN; -} - STATIC int xfs_vn_permission( - struct inode *inode, - int mask, - struct nameidata *nd) + struct inode *inode, + int mode, + struct nameidata *nd) { - return generic_permission(inode, mask, xfs_check_acl); + return -xfs_access(XFS_I(inode), mode << 6, NULL); } #else #define xfs_vn_permission NULL @@ -587,61 +555,33 @@ xfs_vn_permission( STATIC int xfs_vn_getattr( - struct vfsmount *mnt, - struct dentry *dentry, - struct kstat *stat) + struct vfsmount *mnt, + struct dentry *dentry, + struct kstat *stat) { - struct inode *inode = dentry->d_inode; - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - - xfs_itrace_entry(ip); - - if (XFS_FORCED_SHUTDOWN(mp)) - return XFS_ERROR(EIO); - - stat->size = XFS_ISIZE(ip); - stat->dev = inode->i_sb->s_dev; - stat->mode = ip->i_d.di_mode; - stat->nlink = ip->i_d.di_nlink; - stat->uid = ip->i_d.di_uid; - stat->gid = ip->i_d.di_gid; - stat->ino = ip->i_ino; -#if XFS_BIG_INUMS - stat->ino += mp->m_inoadd; -#endif - stat->atime = inode->i_atime; - stat->mtime.tv_sec = ip->i_d.di_mtime.t_sec; - stat->mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; - stat->ctime.tv_sec = ip->i_d.di_ctime.t_sec; - stat->ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; - stat->blocks = - XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); - - - switch (inode->i_mode & S_IFMT) { - case S_IFBLK: - case S_IFCHR: - stat->blksize = BLKDEV_IOSIZE; - stat->rdev = MKDEV(sysv_major(ip->i_df.if_u2.if_rdev) & 0x1ff, - sysv_minor(ip->i_df.if_u2.if_rdev)); - break; - default: - if (XFS_IS_REALTIME_INODE(ip)) { - /* - * If the file blocks are being allocated from a - * realtime volume, then return the inode's realtime - * extent size or the realtime volume's extent size. - */ - stat->blksize = - xfs_get_extsz_hint(ip) << mp->m_sb.sb_blocklog; - } else - stat->blksize = xfs_preferred_iosize(mp); - stat->rdev = 0; - break; - } + struct inode *inode = dentry->d_inode; + bhv_vattr_t vattr = { .va_mask = XFS_AT_STAT }; + int error; - return 0; + error = xfs_getattr(XFS_I(inode), &vattr, ATTR_LAZY); + if (likely(!error)) { + stat->size = i_size_read(inode); + stat->dev = inode->i_sb->s_dev; + stat->rdev = (vattr.va_rdev == 0) ? 0 : + MKDEV(sysv_major(vattr.va_rdev) & 0x1ff, + sysv_minor(vattr.va_rdev)); + stat->mode = vattr.va_mode; + stat->nlink = vattr.va_nlink; + stat->uid = vattr.va_uid; + stat->gid = vattr.va_gid; + stat->ino = vattr.va_nodeid; + stat->atime = vattr.va_atime; + stat->mtime = vattr.va_mtime; + stat->ctime = vattr.va_ctime; + stat->blocks = vattr.va_nblocks; + stat->blksize = vattr.va_blocksize; + } + return -error; } STATIC int @@ -696,7 +636,7 @@ xfs_vn_setattr( error = xfs_setattr(XFS_I(inode), &vattr, flags, NULL); if (likely(!error)) - vn_revalidate(vn_from_inode(inode)); + __vn_revalidate(vn_from_inode(inode), &vattr); return -error; } @@ -810,47 +750,6 @@ xfs_vn_removexattr( return namesp->attr_remove(vp, attr, xflags); } -STATIC long -xfs_vn_fallocate( - struct inode *inode, - int mode, - loff_t offset, - loff_t len) -{ - long error; - loff_t new_size = 0; - xfs_flock64_t bf; - xfs_inode_t *ip = XFS_I(inode); - - /* preallocation on directories not yet supported */ - error = -ENODEV; - if (S_ISDIR(inode->i_mode)) - goto out_error; - - bf.l_whence = 0; - bf.l_start = offset; - bf.l_len = len; - - xfs_ilock(ip, XFS_IOLOCK_EXCL); - error = xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf, - 0, NULL, ATTR_NOLOCK); - if (!error && !(mode & FALLOC_FL_KEEP_SIZE) && - offset + len > i_size_read(inode)) - new_size = offset + len; - - /* Change file size if needed */ - if (new_size) { - bhv_vattr_t va; - - va.va_mask = XFS_AT_SIZE; - va.va_size = new_size; - error = xfs_setattr(ip, &va, ATTR_NOLOCK, NULL); - } - - xfs_iunlock(ip, XFS_IOLOCK_EXCL); -out_error: - return error; -} const struct inode_operations xfs_inode_operations = { .permission = xfs_vn_permission, @@ -861,7 +760,6 @@ const struct inode_operations xfs_inode_operations = { .getxattr = xfs_vn_getxattr, .listxattr = xfs_vn_listxattr, .removexattr = xfs_vn_removexattr, - .fallocate = xfs_vn_fallocate, }; const struct inode_operations xfs_dir_inode_operations = { diff --git a/trunk/fs/xfs/linux-2.6/xfs_linux.h b/trunk/fs/xfs/linux-2.6/xfs_linux.h index 3ca39c4e5d2a..dc3752de22da 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_linux.h +++ b/trunk/fs/xfs/linux-2.6/xfs_linux.h @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -74,7 +75,6 @@ #include #include #include -#include #include #include @@ -136,19 +136,43 @@ #define current_restore_flags_nested(sp, f) \ (current->flags = ((current->flags & ~(f)) | (*(sp) & (f)))) -#define spinlock_destroy(lock) +#define NBPP PAGE_SIZE +#define NDPP (1 << (PAGE_SHIFT - 9)) #define NBBY 8 /* number of bits per byte */ +#define NBPC PAGE_SIZE /* Number of bytes per click */ +#define BPCSHIFT PAGE_SHIFT /* LOG2(NBPC) if exact */ /* * Size of block device i/o is parameterized here. * Currently the system supports page-sized i/o. */ -#define BLKDEV_IOSHIFT PAGE_CACHE_SHIFT +#define BLKDEV_IOSHIFT BPCSHIFT #define BLKDEV_IOSIZE (1<>BPCSHIFT) +#define btoct(x) ((__psunsigned_t)(x)>>BPCSHIFT) +#define btoc64(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT) +#define btoct64(x) ((__uint64_t)(x)>>BPCSHIFT) + +/* off_t bytes to clicks */ +#define offtoc(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT) +#define offtoct(x) ((xfs_off_t)(x)>>BPCSHIFT) + +/* clicks to off_t bytes */ +#define ctooff(x) ((xfs_off_t)(x)<>BPCSHIFT) +#define ctob64(x) ((__uint64_t)(x)<>BPCSHIFT) + #define ENOATTR ENODATA /* Attribute not found */ #define EWRONGFS EINVAL /* Mount with wrong filesystem type */ #define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ @@ -181,6 +205,10 @@ #define xfs_stack_trace() dump_stack() #define xfs_itruncate_data(ip, off) \ (-vmtruncate(vn_to_inode(XFS_ITOV(ip)), (off))) +#define xfs_statvfs_fsid(statp, mp) \ + ({ u64 id = huge_encode_dev((mp)->m_ddev_targp->bt_dev); \ + __kernel_fsid_t *fsid = &(statp)->f_fsid; \ + (fsid->val[0] = (u32)id, fsid->val[1] = (u32)(id >> 32)); }) /* Move the kernel do_div definition off to one side */ diff --git a/trunk/fs/xfs/linux-2.6/xfs_lrw.c b/trunk/fs/xfs/linux-2.6/xfs_lrw.c index 166353388490..6f614f35f650 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_lrw.c +++ b/trunk/fs/xfs/linux-2.6/xfs_lrw.c @@ -58,12 +58,14 @@ void xfs_rw_enter_trace( int tag, - xfs_inode_t *ip, + xfs_iocore_t *io, void *data, size_t segs, loff_t offset, int ioflags) { + xfs_inode_t *ip = XFS_IO_INODE(io); + if (ip->i_rwtrace == NULL) return; ktrace_enter(ip->i_rwtrace, @@ -76,8 +78,8 @@ xfs_rw_enter_trace( (void *)((unsigned long)((offset >> 32) & 0xffffffff)), (void *)((unsigned long)(offset & 0xffffffff)), (void *)((unsigned long)ioflags), - (void *)((unsigned long)((ip->i_new_size >> 32) & 0xffffffff)), - (void *)((unsigned long)(ip->i_new_size & 0xffffffff)), + (void *)((unsigned long)((io->io_new_size >> 32) & 0xffffffff)), + (void *)((unsigned long)(io->io_new_size & 0xffffffff)), (void *)((unsigned long)current_pid()), (void *)NULL, (void *)NULL, @@ -87,12 +89,13 @@ xfs_rw_enter_trace( void xfs_inval_cached_trace( - xfs_inode_t *ip, + xfs_iocore_t *io, xfs_off_t offset, xfs_off_t len, xfs_off_t first, xfs_off_t last) { + xfs_inode_t *ip = XFS_IO_INODE(io); if (ip->i_rwtrace == NULL) return; @@ -128,7 +131,7 @@ xfs_inval_cached_trace( */ STATIC int xfs_iozero( - struct xfs_inode *ip, /* inode */ + struct inode *ip, /* inode */ loff_t pos, /* offset in file */ size_t count) /* size of data to zero */ { @@ -136,7 +139,7 @@ xfs_iozero( struct address_space *mapping; int status; - mapping = ip->i_vnode->i_mapping; + mapping = ip->i_mapping; do { unsigned offset, bytes; void *fsdata; @@ -202,7 +205,7 @@ xfs_read( if (unlikely(ioflags & IO_ISDIRECT)) { xfs_buftarg_t *target = - XFS_IS_REALTIME_INODE(ip) ? + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? mp->m_rtdev_targp : mp->m_ddev_targp; if ((*offset & target->bt_smask) || (size & target->bt_smask)) { @@ -243,8 +246,9 @@ xfs_read( if (unlikely(ioflags & IO_ISDIRECT)) { if (VN_CACHED(vp)) - ret = xfs_flushinval_pages(ip, (*offset & PAGE_CACHE_MASK), - -1, FI_REMAPF_LOCKED); + ret = xfs_flushinval_pages(ip, + ctooff(offtoct(*offset)), + -1, FI_REMAPF_LOCKED); mutex_unlock(&inode->i_mutex); if (ret) { xfs_iunlock(ip, XFS_IOLOCK_SHARED); @@ -252,7 +256,7 @@ xfs_read( } } - xfs_rw_enter_trace(XFS_READ_ENTER, ip, + xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore, (void *)iovp, segs, *offset, ioflags); iocb->ki_pos = *offset; @@ -297,7 +301,7 @@ xfs_splice_read( return -error; } } - xfs_rw_enter_trace(XFS_SPLICE_READ_ENTER, ip, + xfs_rw_enter_trace(XFS_SPLICE_READ_ENTER, &ip->i_iocore, pipe, count, *ppos, ioflags); ret = generic_file_splice_read(infilp, ppos, pipe, count, flags); if (ret > 0) @@ -319,6 +323,7 @@ xfs_splice_write( { bhv_vnode_t *vp = XFS_ITOV(ip); xfs_mount_t *mp = ip->i_mount; + xfs_iocore_t *io = &ip->i_iocore; ssize_t ret; struct inode *inode = outfilp->f_mapping->host; xfs_fsize_t isize, new_size; @@ -345,10 +350,10 @@ xfs_splice_write( xfs_ilock(ip, XFS_ILOCK_EXCL); if (new_size > ip->i_size) - ip->i_new_size = new_size; + io->io_new_size = new_size; xfs_iunlock(ip, XFS_ILOCK_EXCL); - xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, ip, + xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore, pipe, count, *ppos, ioflags); ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags); if (ret > 0) @@ -365,9 +370,9 @@ xfs_splice_write( xfs_iunlock(ip, XFS_ILOCK_EXCL); } - if (ip->i_new_size) { + if (io->io_new_size) { xfs_ilock(ip, XFS_ILOCK_EXCL); - ip->i_new_size = 0; + io->io_new_size = 0; if (ip->i_d.di_size > ip->i_size) ip->i_d.di_size = ip->i_size; xfs_iunlock(ip, XFS_ILOCK_EXCL); @@ -384,19 +389,20 @@ xfs_splice_write( */ STATIC int /* error (positive) */ xfs_zero_last_block( - xfs_inode_t *ip, + struct inode *ip, + xfs_iocore_t *io, xfs_fsize_t offset, xfs_fsize_t isize) { xfs_fileoff_t last_fsb; - xfs_mount_t *mp = ip->i_mount; + xfs_mount_t *mp = io->io_mount; int nimaps; int zero_offset; int zero_len; int error = 0; xfs_bmbt_irec_t imap; - ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0); + ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0); zero_offset = XFS_B_FSB_OFFSET(mp, isize); if (zero_offset == 0) { @@ -409,7 +415,7 @@ xfs_zero_last_block( last_fsb = XFS_B_TO_FSBT(mp, isize); nimaps = 1; - error = xfs_bmapi(NULL, ip, last_fsb, 1, 0, NULL, 0, &imap, + error = XFS_BMAPI(mp, NULL, io, last_fsb, 1, 0, NULL, 0, &imap, &nimaps, NULL, NULL); if (error) { return error; @@ -427,14 +433,14 @@ xfs_zero_last_block( * out sync. We need to drop the ilock while we do this so we * don't deadlock when the buffer cache calls back to us. */ - xfs_iunlock(ip, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD); + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD); zero_len = mp->m_sb.sb_blocksize - zero_offset; if (isize + zero_len > offset) zero_len = offset - isize; error = xfs_iozero(ip, isize, zero_len); - xfs_ilock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); ASSERT(error >= 0); return error; } @@ -452,33 +458,35 @@ xfs_zero_last_block( int /* error (positive) */ xfs_zero_eof( - xfs_inode_t *ip, + bhv_vnode_t *vp, + xfs_iocore_t *io, xfs_off_t offset, /* starting I/O offset */ xfs_fsize_t isize) /* current inode size */ { - xfs_mount_t *mp = ip->i_mount; + struct inode *ip = vn_to_inode(vp); xfs_fileoff_t start_zero_fsb; xfs_fileoff_t end_zero_fsb; xfs_fileoff_t zero_count_fsb; xfs_fileoff_t last_fsb; xfs_fileoff_t zero_off; xfs_fsize_t zero_len; + xfs_mount_t *mp = io->io_mount; int nimaps; int error = 0; xfs_bmbt_irec_t imap; - ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); - ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); + ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); + ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); ASSERT(offset > isize); /* * First handle zeroing the block on which isize resides. * We only zero a part of that block so it is handled specially. */ - error = xfs_zero_last_block(ip, offset, isize); + error = xfs_zero_last_block(ip, io, offset, isize); if (error) { - ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); - ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); + ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); + ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); return error; } @@ -506,11 +514,11 @@ xfs_zero_eof( while (start_zero_fsb <= end_zero_fsb) { nimaps = 1; zero_count_fsb = end_zero_fsb - start_zero_fsb + 1; - error = xfs_bmapi(NULL, ip, start_zero_fsb, zero_count_fsb, + error = XFS_BMAPI(mp, NULL, io, start_zero_fsb, zero_count_fsb, 0, NULL, 0, &imap, &nimaps, NULL, NULL); if (error) { - ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); - ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); + ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); + ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); return error; } ASSERT(nimaps > 0); @@ -534,7 +542,7 @@ xfs_zero_eof( * Drop the inode lock while we're doing the I/O. * We'll still have the iolock to protect us. */ - xfs_iunlock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); zero_off = XFS_FSB_TO_B(mp, start_zero_fsb); zero_len = XFS_FSB_TO_B(mp, imap.br_blockcount); @@ -550,13 +558,14 @@ xfs_zero_eof( start_zero_fsb = imap.br_startoff + imap.br_blockcount; ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); - xfs_ilock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); } return 0; out_lock: - xfs_ilock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); ASSERT(error >= 0); return error; } @@ -578,6 +587,7 @@ xfs_write( xfs_mount_t *mp; ssize_t ret = 0, error = 0; xfs_fsize_t isize, new_size; + xfs_iocore_t *io; int iolock; int eventsent = 0; bhv_vrwlock_t locktype; @@ -597,7 +607,8 @@ xfs_write( if (count == 0) return 0; - mp = xip->i_mount; + io = &xip->i_iocore; + mp = io->io_mount; xfs_wait_for_freeze(mp, SB_FREEZE_WRITE); @@ -656,7 +667,7 @@ xfs_write( if (ioflags & IO_ISDIRECT) { xfs_buftarg_t *target = - XFS_IS_REALTIME_INODE(xip) ? + (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? mp->m_rtdev_targp : mp->m_ddev_targp; if ((pos & target->bt_smask) || (count & target->bt_smask)) { @@ -677,7 +688,7 @@ xfs_write( new_size = pos + count; if (new_size > xip->i_size) - xip->i_new_size = new_size; + io->io_new_size = new_size; if (likely(!(ioflags & IO_INVIS))) { file_update_time(file); @@ -695,7 +706,7 @@ xfs_write( */ if (pos > xip->i_size) { - error = xfs_zero_eof(xip, pos, xip->i_size); + error = xfs_zero_eof(vp, io, pos, xip->i_size); if (error) { xfs_iunlock(xip, XFS_ILOCK_EXCL); goto out_unlock_internal; @@ -729,10 +740,10 @@ xfs_write( if ((ioflags & IO_ISDIRECT)) { if (VN_CACHED(vp)) { WARN_ON(need_i_mutex == 0); - xfs_inval_cached_trace(xip, pos, -1, - (pos & PAGE_CACHE_MASK), -1); + xfs_inval_cached_trace(io, pos, -1, + ctooff(offtoct(pos)), -1); error = xfs_flushinval_pages(xip, - (pos & PAGE_CACHE_MASK), + ctooff(offtoct(pos)), -1, FI_REMAPF_LOCKED); if (error) goto out_unlock_internal; @@ -740,7 +751,7 @@ xfs_write( if (need_i_mutex) { /* demote the lock now the cached pages are gone */ - xfs_ilock_demote(xip, XFS_IOLOCK_EXCL); + XFS_ILOCK_DEMOTE(mp, io, XFS_IOLOCK_EXCL); mutex_unlock(&inode->i_mutex); iolock = XFS_IOLOCK_SHARED; @@ -748,7 +759,7 @@ xfs_write( need_i_mutex = 0; } - xfs_rw_enter_trace(XFS_DIOWR_ENTER, xip, (void *)iovp, segs, + xfs_rw_enter_trace(XFS_DIOWR_ENTER, io, (void *)iovp, segs, *offset, ioflags); ret = generic_file_direct_write(iocb, iovp, &segs, pos, offset, count, ocount); @@ -768,7 +779,7 @@ xfs_write( goto relock; } } else { - xfs_rw_enter_trace(XFS_WRITE_ENTER, xip, (void *)iovp, segs, + xfs_rw_enter_trace(XFS_WRITE_ENTER, io, (void *)iovp, segs, *offset, ioflags); ret = generic_file_buffered_write(iocb, iovp, segs, pos, offset, count, ret); @@ -832,9 +843,9 @@ xfs_write( } out_unlock_internal: - if (xip->i_new_size) { + if (io->io_new_size) { xfs_ilock(xip, XFS_ILOCK_EXCL); - xip->i_new_size = 0; + io->io_new_size = 0; /* * If this was a direct or synchronous I/O that failed (such * as ENOSPC) then part of the I/O may have been written to @@ -883,6 +894,25 @@ xfs_bdstrat_cb(struct xfs_buf *bp) } } + +int +xfs_bmap( + xfs_inode_t *ip, + xfs_off_t offset, + ssize_t count, + int flags, + xfs_iomap_t *iomapp, + int *niomaps) +{ + xfs_iocore_t *io = &ip->i_iocore; + + ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG); + ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) == + ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0)); + + return xfs_iomap(io, offset, count, flags, iomapp, niomaps); +} + /* * Wrapper around bdstrat so that we can stop data * from going to disk in case we are shutting down the filesystem. diff --git a/trunk/fs/xfs/linux-2.6/xfs_lrw.h b/trunk/fs/xfs/linux-2.6/xfs_lrw.h index e200253139cf..4b7747a828d9 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_lrw.h +++ b/trunk/fs/xfs/linux-2.6/xfs_lrw.h @@ -19,6 +19,7 @@ #define __XFS_LRW_H__ struct xfs_mount; +struct xfs_iocore; struct xfs_inode; struct xfs_bmbt_irec; struct xfs_buf; @@ -59,19 +60,20 @@ struct xfs_iomap; #define XFS_IOMAP_UNWRITTEN 27 #define XFS_SPLICE_READ_ENTER 28 #define XFS_SPLICE_WRITE_ENTER 29 -extern void xfs_rw_enter_trace(int, struct xfs_inode *, - void *, size_t, loff_t, int); -extern void xfs_inval_cached_trace(struct xfs_inode *, - xfs_off_t, xfs_off_t, xfs_off_t, xfs_off_t); +extern void xfs_rw_enter_trace(int, struct xfs_iocore *, + void *, size_t, loff_t, int); +extern void xfs_inval_cached_trace(struct xfs_iocore *, + xfs_off_t, xfs_off_t, xfs_off_t, xfs_off_t); #else -#define xfs_rw_enter_trace(tag, ip, data, size, offset, ioflags) -#define xfs_inval_cached_trace(ip, offset, len, first, last) +#define xfs_rw_enter_trace(tag, io, data, size, offset, ioflags) +#define xfs_inval_cached_trace(io, offset, len, first, last) #endif extern int xfsbdstrat(struct xfs_mount *, struct xfs_buf *); extern int xfs_bdstrat_cb(struct xfs_buf *); extern int xfs_dev_is_read_only(struct xfs_mount *, char *); -extern int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t); +extern int xfs_zero_eof(struct inode *, struct xfs_iocore *, xfs_off_t, + xfs_fsize_t); #endif /* __XFS_LRW_H__ */ diff --git a/trunk/fs/xfs/linux-2.6/xfs_super.c b/trunk/fs/xfs/linux-2.6/xfs_super.c index 21dfc9da235e..8cb63c60c048 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_super.c +++ b/trunk/fs/xfs/linux-2.6/xfs_super.c @@ -41,7 +41,6 @@ #include "xfs_rtalloc.h" #include "xfs_error.h" #include "xfs_itable.h" -#include "xfs_fsops.h" #include "xfs_rw.h" #include "xfs_acl.h" #include "xfs_attr.h" @@ -50,8 +49,6 @@ #include "xfs_vnodeops.h" #include "xfs_vfsops.h" #include "xfs_version.h" -#include "xfs_log_priv.h" -#include "xfs_trans_priv.h" #include #include @@ -90,435 +87,6 @@ xfs_args_allocate( return args; } -#define MNTOPT_LOGBUFS "logbufs" /* number of XFS log buffers */ -#define MNTOPT_LOGBSIZE "logbsize" /* size of XFS log buffers */ -#define MNTOPT_LOGDEV "logdev" /* log device */ -#define MNTOPT_RTDEV "rtdev" /* realtime I/O device */ -#define MNTOPT_BIOSIZE "biosize" /* log2 of preferred buffered io size */ -#define MNTOPT_WSYNC "wsync" /* safe-mode nfs compatible mount */ -#define MNTOPT_INO64 "ino64" /* force inodes into 64-bit range */ -#define MNTOPT_NOALIGN "noalign" /* turn off stripe alignment */ -#define MNTOPT_SWALLOC "swalloc" /* turn on stripe width allocation */ -#define MNTOPT_SUNIT "sunit" /* data volume stripe unit */ -#define MNTOPT_SWIDTH "swidth" /* data volume stripe width */ -#define MNTOPT_NOUUID "nouuid" /* ignore filesystem UUID */ -#define MNTOPT_MTPT "mtpt" /* filesystem mount point */ -#define MNTOPT_GRPID "grpid" /* group-ID from parent directory */ -#define MNTOPT_NOGRPID "nogrpid" /* group-ID from current process */ -#define MNTOPT_BSDGROUPS "bsdgroups" /* group-ID from parent directory */ -#define MNTOPT_SYSVGROUPS "sysvgroups" /* group-ID from current process */ -#define MNTOPT_ALLOCSIZE "allocsize" /* preferred allocation size */ -#define MNTOPT_NORECOVERY "norecovery" /* don't run XFS recovery */ -#define MNTOPT_BARRIER "barrier" /* use writer barriers for log write and - * unwritten extent conversion */ -#define MNTOPT_NOBARRIER "nobarrier" /* .. disable */ -#define MNTOPT_OSYNCISOSYNC "osyncisosync" /* o_sync is REALLY o_sync */ -#define MNTOPT_64BITINODE "inode64" /* inodes can be allocated anywhere */ -#define MNTOPT_IKEEP "ikeep" /* do not free empty inode clusters */ -#define MNTOPT_NOIKEEP "noikeep" /* free empty inode clusters */ -#define MNTOPT_LARGEIO "largeio" /* report large I/O sizes in stat() */ -#define MNTOPT_NOLARGEIO "nolargeio" /* do not report large I/O sizes - * in stat(). */ -#define MNTOPT_ATTR2 "attr2" /* do use attr2 attribute format */ -#define MNTOPT_NOATTR2 "noattr2" /* do not use attr2 attribute format */ -#define MNTOPT_FILESTREAM "filestreams" /* use filestreams allocator */ -#define MNTOPT_QUOTA "quota" /* disk quotas (user) */ -#define MNTOPT_NOQUOTA "noquota" /* no quotas */ -#define MNTOPT_USRQUOTA "usrquota" /* user quota enabled */ -#define MNTOPT_GRPQUOTA "grpquota" /* group quota enabled */ -#define MNTOPT_PRJQUOTA "prjquota" /* project quota enabled */ -#define MNTOPT_UQUOTA "uquota" /* user quota (IRIX variant) */ -#define MNTOPT_GQUOTA "gquota" /* group quota (IRIX variant) */ -#define MNTOPT_PQUOTA "pquota" /* project quota (IRIX variant) */ -#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */ -#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */ -#define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */ -#define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */ -#define MNTOPT_DMAPI "dmapi" /* DMI enabled (DMAPI / XDSM) */ -#define MNTOPT_XDSM "xdsm" /* DMI enabled (DMAPI / XDSM) */ -#define MNTOPT_DMI "dmi" /* DMI enabled (DMAPI / XDSM) */ - -STATIC unsigned long -suffix_strtoul(char *s, char **endp, unsigned int base) -{ - int last, shift_left_factor = 0; - char *value = s; - - last = strlen(value) - 1; - if (value[last] == 'K' || value[last] == 'k') { - shift_left_factor = 10; - value[last] = '\0'; - } - if (value[last] == 'M' || value[last] == 'm') { - shift_left_factor = 20; - value[last] = '\0'; - } - if (value[last] == 'G' || value[last] == 'g') { - shift_left_factor = 30; - value[last] = '\0'; - } - - return simple_strtoul((const char *)s, endp, base) << shift_left_factor; -} - -STATIC int -xfs_parseargs( - struct xfs_mount *mp, - char *options, - struct xfs_mount_args *args, - int update) -{ - char *this_char, *value, *eov; - int dsunit, dswidth, vol_dsunit, vol_dswidth; - int iosize; - int ikeep = 0; - - args->flags |= XFSMNT_BARRIER; - args->flags2 |= XFSMNT2_COMPAT_IOSIZE; - - if (!options) - goto done; - - iosize = dsunit = dswidth = vol_dsunit = vol_dswidth = 0; - - while ((this_char = strsep(&options, ",")) != NULL) { - if (!*this_char) - continue; - if ((value = strchr(this_char, '=')) != NULL) - *value++ = 0; - - if (!strcmp(this_char, MNTOPT_LOGBUFS)) { - if (!value || !*value) { - cmn_err(CE_WARN, - "XFS: %s option requires an argument", - this_char); - return EINVAL; - } - args->logbufs = simple_strtoul(value, &eov, 10); - } else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) { - if (!value || !*value) { - cmn_err(CE_WARN, - "XFS: %s option requires an argument", - this_char); - return EINVAL; - } - args->logbufsize = suffix_strtoul(value, &eov, 10); - } else if (!strcmp(this_char, MNTOPT_LOGDEV)) { - if (!value || !*value) { - cmn_err(CE_WARN, - "XFS: %s option requires an argument", - this_char); - return EINVAL; - } - strncpy(args->logname, value, MAXNAMELEN); - } else if (!strcmp(this_char, MNTOPT_MTPT)) { - if (!value || !*value) { - cmn_err(CE_WARN, - "XFS: %s option requires an argument", - this_char); - return EINVAL; - } - strncpy(args->mtpt, value, MAXNAMELEN); - } else if (!strcmp(this_char, MNTOPT_RTDEV)) { - if (!value || !*value) { - cmn_err(CE_WARN, - "XFS: %s option requires an argument", - this_char); - return EINVAL; - } - strncpy(args->rtname, value, MAXNAMELEN); - } else if (!strcmp(this_char, MNTOPT_BIOSIZE)) { - if (!value || !*value) { - cmn_err(CE_WARN, - "XFS: %s option requires an argument", - this_char); - return EINVAL; - } - iosize = simple_strtoul(value, &eov, 10); - args->flags |= XFSMNT_IOSIZE; - args->iosizelog = (uint8_t) iosize; - } else if (!strcmp(this_char, MNTOPT_ALLOCSIZE)) { - if (!value || !*value) { - cmn_err(CE_WARN, - "XFS: %s option requires an argument", - this_char); - return EINVAL; - } - iosize = suffix_strtoul(value, &eov, 10); - args->flags |= XFSMNT_IOSIZE; - args->iosizelog = ffs(iosize) - 1; - } else if (!strcmp(this_char, MNTOPT_GRPID) || - !strcmp(this_char, MNTOPT_BSDGROUPS)) { - mp->m_flags |= XFS_MOUNT_GRPID; - } else if (!strcmp(this_char, MNTOPT_NOGRPID) || - !strcmp(this_char, MNTOPT_SYSVGROUPS)) { - mp->m_flags &= ~XFS_MOUNT_GRPID; - } else if (!strcmp(this_char, MNTOPT_WSYNC)) { - args->flags |= XFSMNT_WSYNC; - } else if (!strcmp(this_char, MNTOPT_OSYNCISOSYNC)) { - args->flags |= XFSMNT_OSYNCISOSYNC; - } else if (!strcmp(this_char, MNTOPT_NORECOVERY)) { - args->flags |= XFSMNT_NORECOVERY; - } else if (!strcmp(this_char, MNTOPT_INO64)) { - args->flags |= XFSMNT_INO64; -#if !XFS_BIG_INUMS - cmn_err(CE_WARN, - "XFS: %s option not allowed on this system", - this_char); - return EINVAL; -#endif - } else if (!strcmp(this_char, MNTOPT_NOALIGN)) { - args->flags |= XFSMNT_NOALIGN; - } else if (!strcmp(this_char, MNTOPT_SWALLOC)) { - args->flags |= XFSMNT_SWALLOC; - } else if (!strcmp(this_char, MNTOPT_SUNIT)) { - if (!value || !*value) { - cmn_err(CE_WARN, - "XFS: %s option requires an argument", - this_char); - return EINVAL; - } - dsunit = simple_strtoul(value, &eov, 10); - } else if (!strcmp(this_char, MNTOPT_SWIDTH)) { - if (!value || !*value) { - cmn_err(CE_WARN, - "XFS: %s option requires an argument", - this_char); - return EINVAL; - } - dswidth = simple_strtoul(value, &eov, 10); - } else if (!strcmp(this_char, MNTOPT_64BITINODE)) { - args->flags &= ~XFSMNT_32BITINODES; -#if !XFS_BIG_INUMS - cmn_err(CE_WARN, - "XFS: %s option not allowed on this system", - this_char); - return EINVAL; -#endif - } else if (!strcmp(this_char, MNTOPT_NOUUID)) { - args->flags |= XFSMNT_NOUUID; - } else if (!strcmp(this_char, MNTOPT_BARRIER)) { - args->flags |= XFSMNT_BARRIER; - } else if (!strcmp(this_char, MNTOPT_NOBARRIER)) { - args->flags &= ~XFSMNT_BARRIER; - } else if (!strcmp(this_char, MNTOPT_IKEEP)) { - ikeep = 1; - args->flags &= ~XFSMNT_IDELETE; - } else if (!strcmp(this_char, MNTOPT_NOIKEEP)) { - args->flags |= XFSMNT_IDELETE; - } else if (!strcmp(this_char, MNTOPT_LARGEIO)) { - args->flags2 &= ~XFSMNT2_COMPAT_IOSIZE; - } else if (!strcmp(this_char, MNTOPT_NOLARGEIO)) { - args->flags2 |= XFSMNT2_COMPAT_IOSIZE; - } else if (!strcmp(this_char, MNTOPT_ATTR2)) { - args->flags |= XFSMNT_ATTR2; - } else if (!strcmp(this_char, MNTOPT_NOATTR2)) { - args->flags &= ~XFSMNT_ATTR2; - } else if (!strcmp(this_char, MNTOPT_FILESTREAM)) { - args->flags2 |= XFSMNT2_FILESTREAMS; - } else if (!strcmp(this_char, MNTOPT_NOQUOTA)) { - args->flags &= ~(XFSMNT_UQUOTAENF|XFSMNT_UQUOTA); - args->flags &= ~(XFSMNT_GQUOTAENF|XFSMNT_GQUOTA); - } else if (!strcmp(this_char, MNTOPT_QUOTA) || - !strcmp(this_char, MNTOPT_UQUOTA) || - !strcmp(this_char, MNTOPT_USRQUOTA)) { - args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF; - } else if (!strcmp(this_char, MNTOPT_QUOTANOENF) || - !strcmp(this_char, MNTOPT_UQUOTANOENF)) { - args->flags |= XFSMNT_UQUOTA; - args->flags &= ~XFSMNT_UQUOTAENF; - } else if (!strcmp(this_char, MNTOPT_PQUOTA) || - !strcmp(this_char, MNTOPT_PRJQUOTA)) { - args->flags |= XFSMNT_PQUOTA | XFSMNT_PQUOTAENF; - } else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) { - args->flags |= XFSMNT_PQUOTA; - args->flags &= ~XFSMNT_PQUOTAENF; - } else if (!strcmp(this_char, MNTOPT_GQUOTA) || - !strcmp(this_char, MNTOPT_GRPQUOTA)) { - args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF; - } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) { - args->flags |= XFSMNT_GQUOTA; - args->flags &= ~XFSMNT_GQUOTAENF; - } else if (!strcmp(this_char, MNTOPT_DMAPI)) { - args->flags |= XFSMNT_DMAPI; - } else if (!strcmp(this_char, MNTOPT_XDSM)) { - args->flags |= XFSMNT_DMAPI; - } else if (!strcmp(this_char, MNTOPT_DMI)) { - args->flags |= XFSMNT_DMAPI; - } else if (!strcmp(this_char, "ihashsize")) { - cmn_err(CE_WARN, - "XFS: ihashsize no longer used, option is deprecated."); - } else if (!strcmp(this_char, "osyncisdsync")) { - /* no-op, this is now the default */ - cmn_err(CE_WARN, - "XFS: osyncisdsync is now the default, option is deprecated."); - } else if (!strcmp(this_char, "irixsgid")) { - cmn_err(CE_WARN, - "XFS: irixsgid is now a sysctl(2) variable, option is deprecated."); - } else { - cmn_err(CE_WARN, - "XFS: unknown mount option [%s].", this_char); - return EINVAL; - } - } - - if (args->flags & XFSMNT_NORECOVERY) { - if ((mp->m_flags & XFS_MOUNT_RDONLY) == 0) { - cmn_err(CE_WARN, - "XFS: no-recovery mounts must be read-only."); - return EINVAL; - } - } - - if ((args->flags & XFSMNT_NOALIGN) && (dsunit || dswidth)) { - cmn_err(CE_WARN, - "XFS: sunit and swidth options incompatible with the noalign option"); - return EINVAL; - } - - if ((args->flags & XFSMNT_GQUOTA) && (args->flags & XFSMNT_PQUOTA)) { - cmn_err(CE_WARN, - "XFS: cannot mount with both project and group quota"); - return EINVAL; - } - - if ((args->flags & XFSMNT_DMAPI) && *args->mtpt == '\0') { - printk("XFS: %s option needs the mount point option as well\n", - MNTOPT_DMAPI); - return EINVAL; - } - - if ((dsunit && !dswidth) || (!dsunit && dswidth)) { - cmn_err(CE_WARN, - "XFS: sunit and swidth must be specified together"); - return EINVAL; - } - - if (dsunit && (dswidth % dsunit != 0)) { - cmn_err(CE_WARN, - "XFS: stripe width (%d) must be a multiple of the stripe unit (%d)", - dswidth, dsunit); - return EINVAL; - } - - /* - * Applications using DMI filesystems often expect the - * inode generation number to be monotonically increasing. - * If we delete inode chunks we break this assumption, so - * keep unused inode chunks on disk for DMI filesystems - * until we come up with a better solution. - * Note that if "ikeep" or "noikeep" mount options are - * supplied, then they are honored. - */ - if (!(args->flags & XFSMNT_DMAPI) && !ikeep) - args->flags |= XFSMNT_IDELETE; - - if ((args->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) { - if (dsunit) { - args->sunit = dsunit; - args->flags |= XFSMNT_RETERR; - } else { - args->sunit = vol_dsunit; - } - dswidth ? (args->swidth = dswidth) : - (args->swidth = vol_dswidth); - } else { - args->sunit = args->swidth = 0; - } - -done: - if (args->flags & XFSMNT_32BITINODES) - mp->m_flags |= XFS_MOUNT_SMALL_INUMS; - if (args->flags2) - args->flags |= XFSMNT_FLAGS2; - return 0; -} - -struct proc_xfs_info { - int flag; - char *str; -}; - -STATIC int -xfs_showargs( - struct xfs_mount *mp, - struct seq_file *m) -{ - static struct proc_xfs_info xfs_info_set[] = { - /* the few simple ones we can get from the mount struct */ - { XFS_MOUNT_WSYNC, "," MNTOPT_WSYNC }, - { XFS_MOUNT_INO64, "," MNTOPT_INO64 }, - { XFS_MOUNT_NOALIGN, "," MNTOPT_NOALIGN }, - { XFS_MOUNT_SWALLOC, "," MNTOPT_SWALLOC }, - { XFS_MOUNT_NOUUID, "," MNTOPT_NOUUID }, - { XFS_MOUNT_NORECOVERY, "," MNTOPT_NORECOVERY }, - { XFS_MOUNT_OSYNCISOSYNC, "," MNTOPT_OSYNCISOSYNC }, - { XFS_MOUNT_ATTR2, "," MNTOPT_ATTR2 }, - { XFS_MOUNT_FILESTREAMS, "," MNTOPT_FILESTREAM }, - { XFS_MOUNT_DMAPI, "," MNTOPT_DMAPI }, - { XFS_MOUNT_GRPID, "," MNTOPT_GRPID }, - { 0, NULL } - }; - static struct proc_xfs_info xfs_info_unset[] = { - /* the few simple ones we can get from the mount struct */ - { XFS_MOUNT_IDELETE, "," MNTOPT_IKEEP }, - { XFS_MOUNT_COMPAT_IOSIZE, "," MNTOPT_LARGEIO }, - { XFS_MOUNT_BARRIER, "," MNTOPT_NOBARRIER }, - { XFS_MOUNT_SMALL_INUMS, "," MNTOPT_64BITINODE }, - { 0, NULL } - }; - struct proc_xfs_info *xfs_infop; - - for (xfs_infop = xfs_info_set; xfs_infop->flag; xfs_infop++) { - if (mp->m_flags & xfs_infop->flag) - seq_puts(m, xfs_infop->str); - } - for (xfs_infop = xfs_info_unset; xfs_infop->flag; xfs_infop++) { - if (!(mp->m_flags & xfs_infop->flag)) - seq_puts(m, xfs_infop->str); - } - - if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) - seq_printf(m, "," MNTOPT_ALLOCSIZE "=%dk", - (int)(1 << mp->m_writeio_log) >> 10); - - if (mp->m_logbufs > 0) - seq_printf(m, "," MNTOPT_LOGBUFS "=%d", mp->m_logbufs); - if (mp->m_logbsize > 0) - seq_printf(m, "," MNTOPT_LOGBSIZE "=%dk", mp->m_logbsize >> 10); - - if (mp->m_logname) - seq_printf(m, "," MNTOPT_LOGDEV "=%s", mp->m_logname); - if (mp->m_rtname) - seq_printf(m, "," MNTOPT_RTDEV "=%s", mp->m_rtname); - - if (mp->m_dalign > 0) - seq_printf(m, "," MNTOPT_SUNIT "=%d", - (int)XFS_FSB_TO_BB(mp, mp->m_dalign)); - if (mp->m_swidth > 0) - seq_printf(m, "," MNTOPT_SWIDTH "=%d", - (int)XFS_FSB_TO_BB(mp, mp->m_swidth)); - - if (mp->m_qflags & (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD)) - seq_puts(m, "," MNTOPT_USRQUOTA); - else if (mp->m_qflags & XFS_UQUOTA_ACCT) - seq_puts(m, "," MNTOPT_UQUOTANOENF); - - if (mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD)) - seq_puts(m, "," MNTOPT_PRJQUOTA); - else if (mp->m_qflags & XFS_PQUOTA_ACCT) - seq_puts(m, "," MNTOPT_PQUOTANOENF); - - if (mp->m_qflags & (XFS_GQUOTA_ACCT|XFS_OQUOTA_ENFD)) - seq_puts(m, "," MNTOPT_GRPQUOTA); - else if (mp->m_qflags & XFS_GQUOTA_ACCT) - seq_puts(m, "," MNTOPT_GQUOTANOENF); - - if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) - seq_puts(m, "," MNTOPT_NOQUOTA); - - return 0; -} __uint64_t xfs_max_file_offset( unsigned int blockshift) @@ -569,7 +137,7 @@ xfs_set_inodeops( break; case S_IFLNK: inode->i_op = &xfs_symlink_inode_operations; - if (!(XFS_I(inode)->i_df.if_flags & XFS_IFINLINE)) + if (inode->i_blocks) inode->i_mapping->a_ops = &xfs_address_space_operations; break; default: @@ -606,6 +174,8 @@ xfs_revalidate_inode( inode->i_generation = ip->i_d.di_gen; i_size_write(inode, ip->i_d.di_size); + inode->i_blocks = + XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); inode->i_atime.tv_sec = ip->i_d.di_atime.t_sec; inode->i_atime.tv_nsec = ip->i_d.di_atime.t_nsec; inode->i_mtime.tv_sec = ip->i_d.di_mtime.t_sec; @@ -764,64 +334,6 @@ xfs_blkdev_issue_flush( blkdev_issue_flush(buftarg->bt_bdev, NULL); } -/* - * XFS AIL push thread support - */ -void -xfsaild_wakeup( - xfs_mount_t *mp, - xfs_lsn_t threshold_lsn) -{ - mp->m_ail.xa_target = threshold_lsn; - wake_up_process(mp->m_ail.xa_task); -} - -int -xfsaild( - void *data) -{ - xfs_mount_t *mp = (xfs_mount_t *)data; - xfs_lsn_t last_pushed_lsn = 0; - long tout = 0; - - while (!kthread_should_stop()) { - if (tout) - schedule_timeout_interruptible(msecs_to_jiffies(tout)); - tout = 1000; - - /* swsusp */ - try_to_freeze(); - - ASSERT(mp->m_log); - if (XFS_FORCED_SHUTDOWN(mp)) - continue; - - tout = xfsaild_push(mp, &last_pushed_lsn); - } - - return 0; -} /* xfsaild */ - -int -xfsaild_start( - xfs_mount_t *mp) -{ - mp->m_ail.xa_target = 0; - mp->m_ail.xa_task = kthread_run(xfsaild, mp, "xfsaild"); - if (IS_ERR(mp->m_ail.xa_task)) - return -PTR_ERR(mp->m_ail.xa_task); - return 0; -} - -void -xfsaild_stop( - xfs_mount_t *mp) -{ - kthread_stop(mp->m_ail.xa_task); -} - - - STATIC struct inode * xfs_fs_alloc_inode( struct super_block *sb) @@ -849,7 +361,7 @@ xfs_fs_inode_init_once( inode_init_once(vn_to_inode((bhv_vnode_t *)vnode)); } -STATIC int __init +STATIC int xfs_init_zones(void) { xfs_vnode_zone = kmem_zone_init_flags(sizeof(bhv_vnode_t), "xfs_vnode", @@ -898,7 +410,8 @@ xfs_fs_write_inode( { int error = 0, flags = FLUSH_INODE; - xfs_itrace_entry(XFS_I(inode)); + vn_trace_entry(XFS_I(inode), __FUNCTION__, + (inst_t *)__return_address); if (sync) { filemap_fdatawait(inode->i_mapping); flags |= FLUSH_SYNC; @@ -925,7 +438,8 @@ xfs_fs_clear_inode( * find an inode with di_mode == 0 but without IGET_CREATE set. */ if (ip) { - xfs_itrace_entry(ip); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + XFS_STATS_INC(vn_rele); XFS_STATS_INC(vn_remove); XFS_STATS_INC(vn_reclaim); @@ -1169,44 +683,8 @@ xfs_fs_statfs( struct dentry *dentry, struct kstatfs *statp) { - struct xfs_mount *mp = XFS_M(dentry->d_sb); - xfs_sb_t *sbp = &mp->m_sb; - __uint64_t fakeinos, id; - xfs_extlen_t lsize; - - statp->f_type = XFS_SB_MAGIC; - statp->f_namelen = MAXNAMELEN - 1; - - id = huge_encode_dev(mp->m_ddev_targp->bt_dev); - statp->f_fsid.val[0] = (u32)id; - statp->f_fsid.val[1] = (u32)(id >> 32); - - xfs_icsb_sync_counters_flags(mp, XFS_ICSB_LAZY_COUNT); - - spin_lock(&mp->m_sb_lock); - statp->f_bsize = sbp->sb_blocksize; - lsize = sbp->sb_logstart ? sbp->sb_logblocks : 0; - statp->f_blocks = sbp->sb_dblocks - lsize; - statp->f_bfree = statp->f_bavail = - sbp->sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); - fakeinos = statp->f_bfree << sbp->sb_inopblog; -#if XFS_BIG_INUMS - fakeinos += mp->m_inoadd; -#endif - statp->f_files = - MIN(sbp->sb_icount + fakeinos, (__uint64_t)XFS_MAXINUMBER); - if (mp->m_maxicount) -#if XFS_BIG_INUMS - if (!mp->m_inoadd) -#endif - statp->f_files = min_t(typeof(statp->f_files), - statp->f_files, - mp->m_maxicount); - statp->f_ffree = statp->f_files - (sbp->sb_icount - sbp->sb_ifree); - spin_unlock(&mp->m_sb_lock); - - XFS_QM_DQSTATVFS(XFS_I(dentry->d_inode), statp); - return 0; + return -xfs_statvfs(XFS_M(dentry->d_sb), statp, + vn_from_inode(dentry->d_inode)); } STATIC int @@ -1226,19 +704,11 @@ xfs_fs_remount( return -error; } -/* - * Second stage of a freeze. The data is already frozen so we only - * need to take care of themetadata. Once that's done write a dummy - * record to dirty the log in case of a crash while frozen. - */ STATIC void xfs_fs_lockfs( struct super_block *sb) { - struct xfs_mount *mp = XFS_M(sb); - - xfs_attr_quiesce(mp); - xfs_fs_log_dummy(mp); + xfs_freeze(XFS_M(sb)); } STATIC int @@ -1309,6 +779,7 @@ xfs_fs_fill_super( struct inode *rootvp; struct xfs_mount *mp = NULL; struct xfs_mount_args *args = xfs_args_allocate(sb, silent); + struct kstatfs statvfs; int error; mp = xfs_mount_init(); @@ -1336,19 +807,21 @@ xfs_fs_fill_super( if (error) goto fail_vfsop; + error = xfs_statvfs(mp, &statvfs, NULL); + if (error) + goto fail_unmount; + sb->s_dirt = 1; - sb->s_magic = XFS_SB_MAGIC; - sb->s_blocksize = mp->m_sb.sb_blocksize; - sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1; + sb->s_magic = statvfs.f_type; + sb->s_blocksize = statvfs.f_bsize; + sb->s_blocksize_bits = ffs(statvfs.f_bsize) - 1; sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits); sb->s_time_gran = 1; set_posix_acl_flag(sb); - rootvp = igrab(mp->m_rootip->i_vnode); - if (!rootvp) { - error = ENOENT; + error = xfs_root(mp, &rootvp); + if (error) goto fail_unmount; - } sb->s_root = d_alloc_root(vn_to_inode(rootvp)); if (!sb->s_root) { @@ -1368,7 +841,8 @@ xfs_fs_fill_super( goto fail_vnrele; } - xfs_itrace_exit(XFS_I(sb->s_root->d_inode)); + vn_trace_exit(XFS_I(sb->s_root->d_inode), __FUNCTION__, + (inst_t *)__return_address); kmem_free(args, sizeof(*args)); return 0; diff --git a/trunk/fs/xfs/linux-2.6/xfs_vnode.c b/trunk/fs/xfs/linux-2.6/xfs_vnode.c index bc7afe007338..814169fd7e1e 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_vnode.c +++ b/trunk/fs/xfs/linux-2.6/xfs_vnode.c @@ -40,7 +40,7 @@ #define vptosync(v) (&vsync[((unsigned long)v) % NVSYNC]) static wait_queue_head_t vsync[NVSYNC]; -void __init +void vn_init(void) { int i; @@ -82,55 +82,84 @@ vn_ioerror( xfs_do_force_shutdown(ip->i_mount, SHUTDOWN_DEVICE_REQ, f, l); } +bhv_vnode_t * +vn_initialize( + struct inode *inode) +{ + bhv_vnode_t *vp = vn_from_inode(inode); + + XFS_STATS_INC(vn_active); + XFS_STATS_INC(vn_alloc); + + ASSERT(VN_CACHED(vp) == 0); + + return vp; +} + /* - * Revalidate the Linux inode from the XFS inode. + * Revalidate the Linux inode from the vattr. * Note: i_size _not_ updated; we must hold the inode * semaphore when doing that - callers responsibility. */ -int -vn_revalidate( - bhv_vnode_t *vp) +void +vn_revalidate_core( + bhv_vnode_t *vp, + bhv_vattr_t *vap) { - struct inode *inode = vn_to_inode(vp); - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - unsigned long xflags; - - xfs_itrace_entry(ip); - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - xfs_ilock(ip, XFS_ILOCK_SHARED); - inode->i_mode = ip->i_d.di_mode; - inode->i_uid = ip->i_d.di_uid; - inode->i_gid = ip->i_d.di_gid; - inode->i_mtime.tv_sec = ip->i_d.di_mtime.t_sec; - inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; - inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec; - inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; - - xflags = xfs_ip2xflags(ip); - if (xflags & XFS_XFLAG_IMMUTABLE) + struct inode *inode = vn_to_inode(vp); + + inode->i_mode = vap->va_mode; + inode->i_nlink = vap->va_nlink; + inode->i_uid = vap->va_uid; + inode->i_gid = vap->va_gid; + inode->i_blocks = vap->va_nblocks; + inode->i_mtime = vap->va_mtime; + inode->i_ctime = vap->va_ctime; + if (vap->va_xflags & XFS_XFLAG_IMMUTABLE) inode->i_flags |= S_IMMUTABLE; else inode->i_flags &= ~S_IMMUTABLE; - if (xflags & XFS_XFLAG_APPEND) + if (vap->va_xflags & XFS_XFLAG_APPEND) inode->i_flags |= S_APPEND; else inode->i_flags &= ~S_APPEND; - if (xflags & XFS_XFLAG_SYNC) + if (vap->va_xflags & XFS_XFLAG_SYNC) inode->i_flags |= S_SYNC; else inode->i_flags &= ~S_SYNC; - if (xflags & XFS_XFLAG_NOATIME) + if (vap->va_xflags & XFS_XFLAG_NOATIME) inode->i_flags |= S_NOATIME; else inode->i_flags &= ~S_NOATIME; - xfs_iunlock(ip, XFS_ILOCK_SHARED); +} + +/* + * Revalidate the Linux inode from the vnode. + */ +int +__vn_revalidate( + bhv_vnode_t *vp, + bhv_vattr_t *vattr) +{ + int error; + + vn_trace_entry(xfs_vtoi(vp), __FUNCTION__, (inst_t *)__return_address); + vattr->va_mask = XFS_AT_STAT | XFS_AT_XFLAGS; + error = xfs_getattr(xfs_vtoi(vp), vattr, 0); + if (likely(!error)) { + vn_revalidate_core(vp, vattr); + xfs_iflags_clear(xfs_vtoi(vp), XFS_IMODIFIED); + } + return -error; +} + +int +vn_revalidate( + bhv_vnode_t *vp) +{ + bhv_vattr_t vattr; - xfs_iflags_clear(ip, XFS_IMODIFIED); - return 0; + return __vn_revalidate(vp, &vattr); } /* @@ -150,7 +179,7 @@ vn_hold( return vp; } -#ifdef XFS_INODE_TRACE +#ifdef XFS_VNODE_TRACE /* * Reference count of Linux inode if present, -1 if the xfs_inode @@ -182,32 +211,32 @@ static inline int xfs_icount(struct xfs_inode *ip) * Vnode tracing code. */ void -_xfs_itrace_entry(xfs_inode_t *ip, const char *func, inst_t *ra) +vn_trace_entry(xfs_inode_t *ip, const char *func, inst_t *ra) { - KTRACE_ENTER(ip, INODE_KTRACE_ENTRY, func, 0, ra); + KTRACE_ENTER(ip, VNODE_KTRACE_ENTRY, func, 0, ra); } void -_xfs_itrace_exit(xfs_inode_t *ip, const char *func, inst_t *ra) +vn_trace_exit(xfs_inode_t *ip, const char *func, inst_t *ra) { - KTRACE_ENTER(ip, INODE_KTRACE_EXIT, func, 0, ra); + KTRACE_ENTER(ip, VNODE_KTRACE_EXIT, func, 0, ra); } void -xfs_itrace_hold(xfs_inode_t *ip, char *file, int line, inst_t *ra) +vn_trace_hold(xfs_inode_t *ip, char *file, int line, inst_t *ra) { - KTRACE_ENTER(ip, INODE_KTRACE_HOLD, file, line, ra); + KTRACE_ENTER(ip, VNODE_KTRACE_HOLD, file, line, ra); } void -_xfs_itrace_ref(xfs_inode_t *ip, char *file, int line, inst_t *ra) +vn_trace_ref(xfs_inode_t *ip, char *file, int line, inst_t *ra) { - KTRACE_ENTER(ip, INODE_KTRACE_REF, file, line, ra); + KTRACE_ENTER(ip, VNODE_KTRACE_REF, file, line, ra); } void -xfs_itrace_rele(xfs_inode_t *ip, char *file, int line, inst_t *ra) +vn_trace_rele(xfs_inode_t *ip, char *file, int line, inst_t *ra) { - KTRACE_ENTER(ip, INODE_KTRACE_RELE, file, line, ra); + KTRACE_ENTER(ip, VNODE_KTRACE_RELE, file, line, ra); } -#endif /* XFS_INODE_TRACE */ +#endif /* XFS_VNODE_TRACE */ diff --git a/trunk/fs/xfs/linux-2.6/xfs_vnode.h b/trunk/fs/xfs/linux-2.6/xfs_vnode.h index b5ea418693b1..55fb46948589 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_vnode.h +++ b/trunk/fs/xfs/linux-2.6/xfs_vnode.h @@ -187,7 +187,10 @@ typedef struct bhv_vattr { (VN_ISREG(vp) && ((mode) & (VSGID|(VEXEC>>3))) == VSGID) extern void vn_init(void); +extern bhv_vnode_t *vn_initialize(struct inode *); extern int vn_revalidate(bhv_vnode_t *); +extern int __vn_revalidate(bhv_vnode_t *, bhv_vattr_t *); +extern void vn_revalidate_core(bhv_vnode_t *, bhv_vattr_t *); /* * Yeah, these don't take vnode anymore at all, all this should be @@ -207,12 +210,12 @@ static inline int vn_count(bhv_vnode_t *vp) */ extern bhv_vnode_t *vn_hold(bhv_vnode_t *); -#if defined(XFS_INODE_TRACE) +#if defined(XFS_VNODE_TRACE) #define VN_HOLD(vp) \ ((void)vn_hold(vp), \ - xfs_itrace_hold(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address)) + vn_trace_hold(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address)) #define VN_RELE(vp) \ - (xfs_itrace_rele(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address), \ + (vn_trace_rele(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address), \ iput(vn_to_inode(vp))) #else #define VN_HOLD(vp) ((void)vn_hold(vp)) @@ -235,6 +238,11 @@ static inline bhv_vnode_t *vn_grab(bhv_vnode_t *vp) /* * Dealing with bad inodes */ +static inline void vn_mark_bad(bhv_vnode_t *vp) +{ + make_bad_inode(vn_to_inode(vp)); +} + static inline int VN_BAD(bhv_vnode_t *vp) { return is_bad_inode(vn_to_inode(vp)); @@ -288,36 +296,26 @@ static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt) /* * Tracking vnode activity. */ -#if defined(XFS_INODE_TRACE) - -#define INODE_TRACE_SIZE 16 /* number of trace entries */ -#define INODE_KTRACE_ENTRY 1 -#define INODE_KTRACE_EXIT 2 -#define INODE_KTRACE_HOLD 3 -#define INODE_KTRACE_REF 4 -#define INODE_KTRACE_RELE 5 - -extern void _xfs_itrace_entry(struct xfs_inode *, const char *, inst_t *); -extern void _xfs_itrace_exit(struct xfs_inode *, const char *, inst_t *); -extern void xfs_itrace_hold(struct xfs_inode *, char *, int, inst_t *); -extern void _xfs_itrace_ref(struct xfs_inode *, char *, int, inst_t *); -extern void xfs_itrace_rele(struct xfs_inode *, char *, int, inst_t *); -#define xfs_itrace_entry(ip) \ - _xfs_itrace_entry(ip, __FUNCTION__, (inst_t *)__return_address) -#define xfs_itrace_exit(ip) \ - _xfs_itrace_exit(ip, __FUNCTION__, (inst_t *)__return_address) -#define xfs_itrace_exit_tag(ip, tag) \ - _xfs_itrace_exit(ip, tag, (inst_t *)__return_address) -#define xfs_itrace_ref(ip) \ - _xfs_itrace_ref(ip, __FILE__, __LINE__, (inst_t *)__return_address) - +#if defined(XFS_VNODE_TRACE) + +#define VNODE_TRACE_SIZE 16 /* number of trace entries */ +#define VNODE_KTRACE_ENTRY 1 +#define VNODE_KTRACE_EXIT 2 +#define VNODE_KTRACE_HOLD 3 +#define VNODE_KTRACE_REF 4 +#define VNODE_KTRACE_RELE 5 + +extern void vn_trace_entry(struct xfs_inode *, const char *, inst_t *); +extern void vn_trace_exit(struct xfs_inode *, const char *, inst_t *); +extern void vn_trace_hold(struct xfs_inode *, char *, int, inst_t *); +extern void vn_trace_ref(struct xfs_inode *, char *, int, inst_t *); +extern void vn_trace_rele(struct xfs_inode *, char *, int, inst_t *); #else -#define xfs_itrace_entry(a) -#define xfs_itrace_exit(a) -#define xfs_itrace_exit_tag(a, b) -#define xfs_itrace_hold(a, b, c, d) -#define xfs_itrace_ref(a) -#define xfs_itrace_rele(a, b, c, d) +#define vn_trace_entry(a,b,c) +#define vn_trace_exit(a,b,c) +#define vn_trace_hold(a,b,c,d) +#define vn_trace_ref(a,b,c,d) +#define vn_trace_rele(a,b,c,d) #endif #endif /* __XFS_VNODE_H__ */ diff --git a/trunk/fs/xfs/quota/xfs_dquot.c b/trunk/fs/xfs/quota/xfs_dquot.c index 665babcca6a6..cfdd35ee9f7a 100644 --- a/trunk/fs/xfs/quota/xfs_dquot.c +++ b/trunk/fs/xfs/quota/xfs_dquot.c @@ -1209,6 +1209,7 @@ xfs_qm_dqflush( xfs_buf_t *bp; xfs_disk_dquot_t *ddqp; int error; + SPLDECL(s); ASSERT(XFS_DQ_IS_LOCKED(dqp)); ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp)); @@ -1269,9 +1270,9 @@ xfs_qm_dqflush( mp = dqp->q_mount; /* lsn is 64 bits */ - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp, s); dqp->q_logitem.qli_flush_lsn = dqp->q_logitem.qli_item.li_lsn; - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); /* * Attach an iodone routine so that we can remove this dquot from the @@ -1317,6 +1318,7 @@ xfs_qm_dqflush_done( xfs_dq_logitem_t *qip) { xfs_dquot_t *dqp; + SPLDECL(s); dqp = qip->qli_dquot; @@ -1331,15 +1333,15 @@ xfs_qm_dqflush_done( if ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && qip->qli_item.li_lsn == qip->qli_flush_lsn) { - spin_lock(&dqp->q_mount->m_ail_lock); + AIL_LOCK(dqp->q_mount, s); /* * xfs_trans_delete_ail() drops the AIL lock. */ if (qip->qli_item.li_lsn == qip->qli_flush_lsn) xfs_trans_delete_ail(dqp->q_mount, - (xfs_log_item_t*)qip); + (xfs_log_item_t*)qip, s); else - spin_unlock(&dqp->q_mount->m_ail_lock); + AIL_UNLOCK(dqp->q_mount, s); } /* diff --git a/trunk/fs/xfs/quota/xfs_dquot.h b/trunk/fs/xfs/quota/xfs_dquot.h index 5c371a92e3e2..78d3ab95c5fd 100644 --- a/trunk/fs/xfs/quota/xfs_dquot.h +++ b/trunk/fs/xfs/quota/xfs_dquot.h @@ -123,6 +123,11 @@ XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp) vsema(&((dqp)->q_flock)); \ (dqp)->dq_flags &= ~(XFS_DQ_FLOCKED); } +#define XFS_DQ_PINLOCK(dqp) mutex_spinlock( \ + &(XFS_DQ_TO_QINF(dqp)->qi_pinlock)) +#define XFS_DQ_PINUNLOCK(dqp, s) mutex_spinunlock( \ + &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s) + #define XFS_DQ_IS_FLUSH_LOCKED(dqp) (issemalocked(&((dqp)->q_flock))) #define XFS_DQ_IS_ON_FREELIST(dqp) ((dqp)->dq_flnext != (dqp)) #define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY) diff --git a/trunk/fs/xfs/quota/xfs_dquot_item.c b/trunk/fs/xfs/quota/xfs_dquot_item.c index 1800e8d1f646..ddb61fe22a5c 100644 --- a/trunk/fs/xfs/quota/xfs_dquot_item.c +++ b/trunk/fs/xfs/quota/xfs_dquot_item.c @@ -94,13 +94,14 @@ STATIC void xfs_qm_dquot_logitem_pin( xfs_dq_logitem_t *logitem) { + unsigned long s; xfs_dquot_t *dqp; dqp = logitem->qli_dquot; ASSERT(XFS_DQ_IS_LOCKED(dqp)); - spin_lock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); + s = XFS_DQ_PINLOCK(dqp); dqp->q_pincount++; - spin_unlock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); + XFS_DQ_PINUNLOCK(dqp, s); } /* @@ -114,16 +115,17 @@ xfs_qm_dquot_logitem_unpin( xfs_dq_logitem_t *logitem, int stale) { + unsigned long s; xfs_dquot_t *dqp; dqp = logitem->qli_dquot; ASSERT(dqp->q_pincount > 0); - spin_lock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); + s = XFS_DQ_PINLOCK(dqp); dqp->q_pincount--; if (dqp->q_pincount == 0) { sv_broadcast(&dqp->q_pinwait); } - spin_unlock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); + XFS_DQ_PINUNLOCK(dqp, s); } /* ARGSUSED */ @@ -187,6 +189,8 @@ void xfs_qm_dqunpin_wait( xfs_dquot_t *dqp) { + SPLDECL(s); + ASSERT(XFS_DQ_IS_LOCKED(dqp)); if (dqp->q_pincount == 0) { return; @@ -196,9 +200,9 @@ xfs_qm_dqunpin_wait( * Give the log a push so we don't wait here too long. */ xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, XFS_LOG_FORCE); - spin_lock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); + s = XFS_DQ_PINLOCK(dqp); if (dqp->q_pincount == 0) { - spin_unlock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); + XFS_DQ_PINUNLOCK(dqp, s); return; } sv_wait(&(dqp->q_pinwait), PINOD, @@ -212,8 +216,8 @@ xfs_qm_dqunpin_wait( * If so, we want to push it out to help us take this item off the AIL as soon * as possible. * - * We must not be holding the AIL lock at this point. Calling incore() to - * search the buffer cache can be a time consuming thing, and AIL lock is a + * We must not be holding the AIL_LOCK at this point. Calling incore() to + * search the buffer cache can be a time consuming thing, and AIL_LOCK is a * spinlock. */ STATIC void @@ -318,7 +322,7 @@ xfs_qm_dquot_logitem_trylock( * want to do that now since we might sleep in the device * strategy routine. We also don't want to grab the buffer lock * here because we'd like not to call into the buffer cache - * while holding the AIL lock. + * while holding the AIL_LOCK. * Make sure to only return PUSHBUF if we set pushbuf_flag * ourselves. If someone else is doing it then we don't * want to go to the push routine and duplicate their efforts. @@ -558,14 +562,15 @@ xfs_qm_qoffend_logitem_committed( xfs_lsn_t lsn) { xfs_qoff_logitem_t *qfs; + SPLDECL(s); qfs = qfe->qql_start_lip; - spin_lock(&qfs->qql_item.li_mountp->m_ail_lock); + AIL_LOCK(qfs->qql_item.li_mountp,s); /* * Delete the qoff-start logitem from the AIL. * xfs_trans_delete_ail() drops the AIL lock. */ - xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs); + xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs, s); kmem_free(qfs, sizeof(xfs_qoff_logitem_t)); kmem_free(qfe, sizeof(xfs_qoff_logitem_t)); return (xfs_lsn_t)-1; diff --git a/trunk/fs/xfs/quota/xfs_qm.c b/trunk/fs/xfs/quota/xfs_qm.c index 35582fe9d648..d488645f833d 100644 --- a/trunk/fs/xfs/quota/xfs_qm.c +++ b/trunk/fs/xfs/quota/xfs_qm.c @@ -310,6 +310,7 @@ xfs_qm_mount_quotas( xfs_mount_t *mp, int mfsi_flags) { + unsigned long s; int error = 0; uint sbf; @@ -366,13 +367,13 @@ xfs_qm_mount_quotas( write_changes: /* - * We actually don't have to acquire the m_sb_lock at all. + * We actually don't have to acquire the SB_LOCK at all. * This can only be called from mount, and that's single threaded. XXX */ - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); sbf = mp->m_sb.sb_qflags; mp->m_sb.sb_qflags = mp->m_qflags & XFS_MOUNT_QUOTA_ALL; - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); if (sbf != (mp->m_qflags & XFS_MOUNT_QUOTA_ALL)) { if (xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS)) { @@ -1138,7 +1139,7 @@ xfs_qm_init_quotainfo( return error; } - spin_lock_init(&qinf->qi_pinlock); + spinlock_init(&qinf->qi_pinlock, "xfs_qinf_pin"); xfs_qm_list_init(&qinf->qi_dqlist, "mpdqlist", 0); qinf->qi_dqreclaims = 0; @@ -1369,6 +1370,7 @@ xfs_qm_qino_alloc( { xfs_trans_t *tp; int error; + unsigned long s; int committed; tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QINOCREATE); @@ -1400,7 +1402,7 @@ xfs_qm_qino_alloc( * sbfields arg may contain fields other than *QUOTINO; * VERSIONNUM for example. */ - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); if (flags & XFS_QMOPT_SBVERSION) { #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) unsigned oldv = mp->m_sb.sb_versionnum; @@ -1427,7 +1429,7 @@ xfs_qm_qino_alloc( mp->m_sb.sb_uquotino = (*ip)->i_ino; else mp->m_sb.sb_gquotino = (*ip)->i_ino; - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); xfs_mod_sb(tp, sbfields); if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES))) { diff --git a/trunk/fs/xfs/quota/xfs_qm.h b/trunk/fs/xfs/quota/xfs_qm.h index baf537c1c177..23ccaa5fceaf 100644 --- a/trunk/fs/xfs/quota/xfs_qm.h +++ b/trunk/fs/xfs/quota/xfs_qm.h @@ -52,8 +52,8 @@ extern kmem_zone_t *qm_dqtrxzone; /* * Dquot hashtable constants/threshold values. */ -#define XFS_QM_HASHSIZE_LOW (PAGE_SIZE / sizeof(xfs_dqhash_t)) -#define XFS_QM_HASHSIZE_HIGH ((PAGE_SIZE * 4) / sizeof(xfs_dqhash_t)) +#define XFS_QM_HASHSIZE_LOW (NBPP / sizeof(xfs_dqhash_t)) +#define XFS_QM_HASHSIZE_HIGH ((NBPP * 4) / sizeof(xfs_dqhash_t)) /* * This defines the unit of allocation of dquots. @@ -106,7 +106,7 @@ typedef struct xfs_qm { typedef struct xfs_quotainfo { xfs_inode_t *qi_uquotaip; /* user quota inode */ xfs_inode_t *qi_gquotaip; /* group quota inode */ - spinlock_t qi_pinlock; /* dquot pinning lock */ + lock_t qi_pinlock; /* dquot pinning mutex */ xfs_dqlist_t qi_dqlist; /* all dquots in filesys */ int qi_dqreclaims; /* a change here indicates a removal in the dqlist */ diff --git a/trunk/fs/xfs/quota/xfs_qm_syscalls.c b/trunk/fs/xfs/quota/xfs_qm_syscalls.c index 2cc5886cfe85..ad5579d4eac4 100644 --- a/trunk/fs/xfs/quota/xfs_qm_syscalls.c +++ b/trunk/fs/xfs/quota/xfs_qm_syscalls.c @@ -200,6 +200,7 @@ xfs_qm_scall_quotaoff( boolean_t force) { uint dqtype; + unsigned long s; int error; uint inactivate_flags; xfs_qoff_logitem_t *qoffstart; @@ -236,9 +237,9 @@ xfs_qm_scall_quotaoff( if ((flags & XFS_ALL_QUOTA_ACCT) == 0) { mp->m_qflags &= ~(flags); - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); mp->m_sb.sb_qflags = mp->m_qflags; - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); /* XXX what to do if error ? Revert back to old vals incore ? */ @@ -414,6 +415,7 @@ xfs_qm_scall_quotaon( uint flags) { int error; + unsigned long s; uint qf; uint accflags; __int64_t sbflags; @@ -466,10 +468,10 @@ xfs_qm_scall_quotaon( * Change sb_qflags on disk but not incore mp->qflags * if this is the root filesystem. */ - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); qf = mp->m_sb.sb_qflags; mp->m_sb.sb_qflags = qf | flags; - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); /* * There's nothing to change if it's the same. @@ -813,6 +815,7 @@ xfs_qm_log_quotaoff( { xfs_trans_t *tp; int error; + unsigned long s; xfs_qoff_logitem_t *qoffi=NULL; uint oldsbqflag=0; @@ -829,10 +832,10 @@ xfs_qm_log_quotaoff( qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT); xfs_trans_log_quotaoff_item(tp, qoffi); - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); oldsbqflag = mp->m_sb.sb_qflags; mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL; - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); xfs_mod_sb(tp, XFS_SB_QFLAGS); @@ -851,9 +854,9 @@ xfs_qm_log_quotaoff( * No one else is modifying sb_qflags, so this is OK. * We still hold the quotaofflock. */ - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); mp->m_sb.sb_qflags = oldsbqflag; - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); } *qoffstartp = qoffi; return (error); diff --git a/trunk/fs/xfs/support/debug.c b/trunk/fs/xfs/support/debug.c index c27abef7b84f..f45a49ffd3a3 100644 --- a/trunk/fs/xfs/support/debug.c +++ b/trunk/fs/xfs/support/debug.c @@ -17,6 +17,7 @@ */ #include #include "debug.h" +#include "spin.h" static char message[1024]; /* keep it off the stack */ static DEFINE_SPINLOCK(xfs_err_lock); @@ -80,9 +81,3 @@ assfail(char *expr, char *file, int line) printk("Assertion failed: %s, file: %s, line: %d\n", expr, file, line); BUG(); } - -void -xfs_hex_dump(void *p, int length) -{ - print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_OFFSET, 16, 1, p, length, 1); -} diff --git a/trunk/fs/xfs/support/ktrace.c b/trunk/fs/xfs/support/ktrace.c index 129067cfcb86..5cf2e86caa71 100644 --- a/trunk/fs/xfs/support/ktrace.c +++ b/trunk/fs/xfs/support/ktrace.c @@ -21,7 +21,7 @@ static kmem_zone_t *ktrace_hdr_zone; static kmem_zone_t *ktrace_ent_zone; static int ktrace_zentries; -void __init +void ktrace_init(int zentries) { ktrace_zentries = zentries; @@ -36,7 +36,7 @@ ktrace_init(int zentries) ASSERT(ktrace_ent_zone); } -void __exit +void ktrace_uninit(void) { kmem_zone_destroy(ktrace_hdr_zone); @@ -90,6 +90,8 @@ ktrace_alloc(int nentries, unsigned int __nocast sleep) return NULL; } + spinlock_init(&(ktp->kt_lock), "kt_lock"); + ktp->kt_entries = ktep; ktp->kt_nentries = nentries; ktp->kt_index = 0; @@ -112,6 +114,8 @@ ktrace_free(ktrace_t *ktp) if (ktp == (ktrace_t *)NULL) return; + spinlock_destroy(&ktp->kt_lock); + /* * Special treatment for the Vnode trace buffer. */ diff --git a/trunk/fs/xfs/support/ktrace.h b/trunk/fs/xfs/support/ktrace.h index 56e72b40a859..0d73216287c0 100644 --- a/trunk/fs/xfs/support/ktrace.h +++ b/trunk/fs/xfs/support/ktrace.h @@ -18,6 +18,8 @@ #ifndef __XFS_SUPPORT_KTRACE_H__ #define __XFS_SUPPORT_KTRACE_H__ +#include + /* * Trace buffer entry structure. */ @@ -29,6 +31,7 @@ typedef struct ktrace_entry { * Trace buffer header structure. */ typedef struct ktrace { + lock_t kt_lock; /* mutex to guard counters */ int kt_nentries; /* number of entries in trace buf */ int kt_index; /* current index in entries */ int kt_rollover; diff --git a/trunk/fs/xfs/support/uuid.c b/trunk/fs/xfs/support/uuid.c index 493a6ecf8590..e157015c70ff 100644 --- a/trunk/fs/xfs/support/uuid.c +++ b/trunk/fs/xfs/support/uuid.c @@ -133,7 +133,7 @@ uuid_table_remove(uuid_t *uuid) mutex_unlock(&uuid_monitor); } -void __init +void uuid_init(void) { mutex_init(&uuid_monitor); diff --git a/trunk/fs/xfs/xfs.h b/trunk/fs/xfs/xfs.h index 540e4c989825..b5a7d92c6843 100644 --- a/trunk/fs/xfs/xfs.h +++ b/trunk/fs/xfs/xfs.h @@ -37,7 +37,7 @@ #define XFS_LOG_TRACE 1 #define XFS_RW_TRACE 1 #define XFS_BUF_TRACE 1 -#define XFS_INODE_TRACE 1 +#define XFS_VNODE_TRACE 1 #define XFS_FILESTREAMS_TRACE 1 #endif diff --git a/trunk/fs/xfs/xfs_acl.c b/trunk/fs/xfs/xfs_acl.c index 7272fe39a92d..5bfb66f33caf 100644 --- a/trunk/fs/xfs/xfs_acl.c +++ b/trunk/fs/xfs/xfs_acl.c @@ -391,6 +391,32 @@ xfs_acl_allow_set( return error; } +/* + * The access control process to determine the access permission: + * if uid == file owner id, use the file owner bits. + * if gid == file owner group id, use the file group bits. + * scan ACL for a matching user or group, and use matched entry + * permission. Use total permissions of all matching group entries, + * until all acl entries are exhausted. The final permission produced + * by matching acl entry or entries needs to be & with group permission. + * if not owner, owning group, or matching entry in ACL, use file + * other bits. + */ +STATIC int +xfs_acl_capability_check( + mode_t mode, + cred_t *cr) +{ + if ((mode & ACL_READ) && !capable_cred(cr, CAP_DAC_READ_SEARCH)) + return EACCES; + if ((mode & ACL_WRITE) && !capable_cred(cr, CAP_DAC_OVERRIDE)) + return EACCES; + if ((mode & ACL_EXECUTE) && !capable_cred(cr, CAP_DAC_OVERRIDE)) + return EACCES; + + return 0; +} + /* * Note: cr is only used here for the capability check if the ACL test fails. * It is not used to find out the credentials uid or groups etc, as was @@ -412,6 +438,7 @@ xfs_acl_access( matched.ae_tag = 0; /* Invalid type */ matched.ae_perm = 0; + md >>= 6; /* Normalize the bits for comparison */ for (i = 0; i < fap->acl_cnt; i++) { /* @@ -493,8 +520,7 @@ xfs_acl_access( break; } - /* EACCES tells generic_permission to check for capability overrides */ - return EACCES; + return xfs_acl_capability_check(md, cr); } /* diff --git a/trunk/fs/xfs/xfs_acl.h b/trunk/fs/xfs/xfs_acl.h index 332a772461c4..34b7d3391299 100644 --- a/trunk/fs/xfs/xfs_acl.h +++ b/trunk/fs/xfs/xfs_acl.h @@ -75,6 +75,7 @@ extern int xfs_acl_vremove(bhv_vnode_t *, int); #define _ACL_GET_DEFAULT(pv,pd) (xfs_acl_vtoacl(pv,NULL,pd) == 0) #define _ACL_ACCESS_EXISTS xfs_acl_vhasacl_access #define _ACL_DEFAULT_EXISTS xfs_acl_vhasacl_default +#define _ACL_XFS_IACCESS(i,m,c) (XFS_IFORK_Q(i) ? xfs_acl_iaccess(i,m,c) : -1) #define _ACL_ALLOC(a) ((a) = kmem_zone_alloc(xfs_acl_zone, KM_SLEEP)) #define _ACL_FREE(a) ((a)? kmem_zone_free(xfs_acl_zone, (a)):(void)0) @@ -94,6 +95,7 @@ extern int xfs_acl_vremove(bhv_vnode_t *, int); #define _ACL_GET_DEFAULT(pv,pd) (0) #define _ACL_ACCESS_EXISTS (NULL) #define _ACL_DEFAULT_EXISTS (NULL) +#define _ACL_XFS_IACCESS(i,m,c) (-1) #endif #endif /* __XFS_ACL_H__ */ diff --git a/trunk/fs/xfs/xfs_ag.h b/trunk/fs/xfs/xfs_ag.h index 61b292a9fb41..9381b0360c4b 100644 --- a/trunk/fs/xfs/xfs_ag.h +++ b/trunk/fs/xfs/xfs_ag.h @@ -193,7 +193,7 @@ typedef struct xfs_perag xfs_agino_t pagi_count; /* number of allocated inodes */ int pagb_count; /* pagb slots in use */ #ifdef __KERNEL__ - spinlock_t pagb_lock; /* lock for pagb_list */ + lock_t pagb_lock; /* lock for pagb_list */ #endif xfs_perag_busy_t *pagb_list; /* unstable blocks */ atomic_t pagf_fstrms; /* # of filestreams active in this AG */ diff --git a/trunk/fs/xfs/xfs_alloc.c b/trunk/fs/xfs/xfs_alloc.c index ea6aa60ace06..012a649a19c3 100644 --- a/trunk/fs/xfs/xfs_alloc.c +++ b/trunk/fs/xfs/xfs_alloc.c @@ -2206,7 +2206,7 @@ xfs_alloc_read_agf( be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi]); pag->pagf_levels[XFS_BTNUM_CNTi] = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]); - spin_lock_init(&pag->pagb_lock); + spinlock_init(&pag->pagb_lock, "xfspagb"); pag->pagb_list = kmem_zalloc(XFS_PAGB_NUM_SLOTS * sizeof(xfs_perag_busy_t), KM_SLEEP); pag->pagf_init = 1; @@ -2500,9 +2500,10 @@ xfs_alloc_mark_busy(xfs_trans_t *tp, xfs_mount_t *mp; xfs_perag_busy_t *bsy; int n; + SPLDECL(s); mp = tp->t_mountp; - spin_lock(&mp->m_perag[agno].pagb_lock); + s = mutex_spinlock(&mp->m_perag[agno].pagb_lock); /* search pagb_list for an open slot */ for (bsy = mp->m_perag[agno].pagb_list, n = 0; @@ -2532,7 +2533,7 @@ xfs_alloc_mark_busy(xfs_trans_t *tp, xfs_trans_set_sync(tp); } - spin_unlock(&mp->m_perag[agno].pagb_lock); + mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s); } void @@ -2542,10 +2543,11 @@ xfs_alloc_clear_busy(xfs_trans_t *tp, { xfs_mount_t *mp; xfs_perag_busy_t *list; + SPLDECL(s); mp = tp->t_mountp; - spin_lock(&mp->m_perag[agno].pagb_lock); + s = mutex_spinlock(&mp->m_perag[agno].pagb_lock); list = mp->m_perag[agno].pagb_list; ASSERT(idx < XFS_PAGB_NUM_SLOTS); @@ -2557,7 +2559,7 @@ xfs_alloc_clear_busy(xfs_trans_t *tp, TRACE_UNBUSY("xfs_alloc_clear_busy", "missing", agno, idx, tp); } - spin_unlock(&mp->m_perag[agno].pagb_lock); + mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s); } @@ -2576,10 +2578,11 @@ xfs_alloc_search_busy(xfs_trans_t *tp, xfs_agblock_t uend, bend; xfs_lsn_t lsn; int cnt; + SPLDECL(s); mp = tp->t_mountp; - spin_lock(&mp->m_perag[agno].pagb_lock); + s = mutex_spinlock(&mp->m_perag[agno].pagb_lock); cnt = mp->m_perag[agno].pagb_count; uend = bno + len - 1; @@ -2612,12 +2615,12 @@ xfs_alloc_search_busy(xfs_trans_t *tp, if (cnt) { TRACE_BUSYSEARCH("xfs_alloc_search_busy", "found", agno, bno, len, n, tp); lsn = bsy->busy_tp->t_commit_lsn; - spin_unlock(&mp->m_perag[agno].pagb_lock); + mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s); xfs_log_force(mp, lsn, XFS_LOG_FORCE|XFS_LOG_SYNC); } else { TRACE_BUSYSEARCH("xfs_alloc_search_busy", "not-found", agno, bno, len, n, tp); n = -1; - spin_unlock(&mp->m_perag[agno].pagb_lock); + mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s); } return n; diff --git a/trunk/fs/xfs/xfs_attr.c b/trunk/fs/xfs/xfs_attr.c index e58f321fdae9..93fa64dd1be6 100644 --- a/trunk/fs/xfs/xfs_attr.c +++ b/trunk/fs/xfs/xfs_attr.c @@ -929,7 +929,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args) * This leaf block cannot have a "remote" value, we only call this routine * if bmap_one_block() says there is only one block (ie: no remote blks). */ -STATIC int +int xfs_attr_leaf_addname(xfs_da_args_t *args) { xfs_inode_t *dp; diff --git a/trunk/fs/xfs/xfs_attr_leaf.c b/trunk/fs/xfs/xfs_attr_leaf.c index eb3815ebb7aa..81f45dae1c57 100644 --- a/trunk/fs/xfs/xfs_attr_leaf.c +++ b/trunk/fs/xfs/xfs_attr_leaf.c @@ -226,15 +226,17 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes) STATIC void xfs_sbversion_add_attr2(xfs_mount_t *mp, xfs_trans_t *tp) { + unsigned long s; + if ((mp->m_flags & XFS_MOUNT_ATTR2) && !(XFS_SB_VERSION_HASATTR2(&mp->m_sb))) { - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); if (!XFS_SB_VERSION_HASATTR2(&mp->m_sb)) { XFS_SB_VERSION_ADDATTR2(&mp->m_sb); - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); xfs_mod_sb(tp, XFS_SB_VERSIONNUM | XFS_SB_FEATURES2); } else - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); } } diff --git a/trunk/fs/xfs/xfs_bit.c b/trunk/fs/xfs/xfs_bit.c index 48228848f5ae..fab0b6d5a41b 100644 --- a/trunk/fs/xfs/xfs_bit.c +++ b/trunk/fs/xfs/xfs_bit.c @@ -25,6 +25,109 @@ * XFS bit manipulation routines, used in non-realtime code. */ +#ifndef HAVE_ARCH_HIGHBIT +/* + * Index of high bit number in byte, -1 for none set, 0..7 otherwise. + */ +static const char xfs_highbit[256] = { + -1, 0, 1, 1, 2, 2, 2, 2, /* 00 .. 07 */ + 3, 3, 3, 3, 3, 3, 3, 3, /* 08 .. 0f */ + 4, 4, 4, 4, 4, 4, 4, 4, /* 10 .. 17 */ + 4, 4, 4, 4, 4, 4, 4, 4, /* 18 .. 1f */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 20 .. 27 */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 28 .. 2f */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 30 .. 37 */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 38 .. 3f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 40 .. 47 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 48 .. 4f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 50 .. 57 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 58 .. 5f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 60 .. 67 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 68 .. 6f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 70 .. 77 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 78 .. 7f */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 80 .. 87 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 88 .. 8f */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 90 .. 97 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 98 .. 9f */ + 7, 7, 7, 7, 7, 7, 7, 7, /* a0 .. a7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* a8 .. af */ + 7, 7, 7, 7, 7, 7, 7, 7, /* b0 .. b7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* b8 .. bf */ + 7, 7, 7, 7, 7, 7, 7, 7, /* c0 .. c7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* c8 .. cf */ + 7, 7, 7, 7, 7, 7, 7, 7, /* d0 .. d7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* d8 .. df */ + 7, 7, 7, 7, 7, 7, 7, 7, /* e0 .. e7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* e8 .. ef */ + 7, 7, 7, 7, 7, 7, 7, 7, /* f0 .. f7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* f8 .. ff */ +}; +#endif + +/* + * xfs_highbit32: get high bit set out of 32-bit argument, -1 if none set. + */ +inline int +xfs_highbit32( + __uint32_t v) +{ +#ifdef HAVE_ARCH_HIGHBIT + return highbit32(v); +#else + int i; + + if (v & 0xffff0000) + if (v & 0xff000000) + i = 24; + else + i = 16; + else if (v & 0x0000ffff) + if (v & 0x0000ff00) + i = 8; + else + i = 0; + else + return -1; + return i + xfs_highbit[(v >> i) & 0xff]; +#endif +} + +/* + * xfs_lowbit64: get low bit set out of 64-bit argument, -1 if none set. + */ +int +xfs_lowbit64( + __uint64_t v) +{ + __uint32_t w = (__uint32_t)v; + int n = 0; + + if (w) { /* lower bits */ + n = ffs(w); + } else { /* upper bits */ + w = (__uint32_t)(v >> 32); + if (w && (n = ffs(w))) + n += 32; + } + return n - 1; +} + +/* + * xfs_highbit64: get high bit set out of 64-bit argument, -1 if none set. + */ +int +xfs_highbit64( + __uint64_t v) +{ + __uint32_t h = (__uint32_t)(v >> 32); + + if (h) + return xfs_highbit32(h) + 32; + return xfs_highbit32((__uint32_t)v); +} + + /* * Return whether bitmap is empty. * Size is number of words in the bitmap, which is padded to word boundary diff --git a/trunk/fs/xfs/xfs_bit.h b/trunk/fs/xfs/xfs_bit.h index 325a007dec91..082641a9782c 100644 --- a/trunk/fs/xfs/xfs_bit.h +++ b/trunk/fs/xfs/xfs_bit.h @@ -47,30 +47,13 @@ static inline __uint64_t xfs_mask64lo(int n) } /* Get high bit set out of 32-bit argument, -1 if none set */ -static inline int xfs_highbit32(__uint32_t v) -{ - return fls(v) - 1; -} - -/* Get high bit set out of 64-bit argument, -1 if none set */ -static inline int xfs_highbit64(__uint64_t v) -{ - return fls64(v) - 1; -} - -/* Get low bit set out of 32-bit argument, -1 if none set */ -static inline int xfs_lowbit32(__uint32_t v) -{ - __uint32_t t = v; - return (t) ? find_first_bit((unsigned long *)&t, 32) : -1; -} +extern int xfs_highbit32(__uint32_t v); /* Get low bit set out of 64-bit argument, -1 if none set */ -static inline int xfs_lowbit64(__uint64_t v) -{ - __uint64_t t = v; - return (t) ? find_first_bit((unsigned long *)&t, 64) : -1; -} +extern int xfs_lowbit64(__uint64_t v); + +/* Get high bit set out of 64-bit argument, -1 if none set */ +extern int xfs_highbit64(__uint64_t); /* Return whether bitmap is empty (1 == empty) */ extern int xfs_bitmap_empty(uint *map, uint size); diff --git a/trunk/fs/xfs/xfs_bmap.c b/trunk/fs/xfs/xfs_bmap.c index 1c0a5a585a82..2e9b34b7344b 100644 --- a/trunk/fs/xfs/xfs_bmap.c +++ b/trunk/fs/xfs/xfs_bmap.c @@ -2830,11 +2830,11 @@ xfs_bmap_btalloc( args.prod = align; if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod))) args.mod = (xfs_extlen_t)(args.prod - args.mod); - } else if (mp->m_sb.sb_blocksize >= PAGE_CACHE_SIZE) { + } else if (mp->m_sb.sb_blocksize >= NBPP) { args.prod = 1; args.mod = 0; } else { - args.prod = PAGE_CACHE_SIZE >> mp->m_sb.sb_blocklog; + args.prod = NBPP >> mp->m_sb.sb_blocklog; if ((args.mod = (xfs_extlen_t)(do_mod(ap->off, args.prod)))) args.mod = (xfs_extlen_t)(args.prod - args.mod); } @@ -2969,7 +2969,7 @@ STATIC int xfs_bmap_alloc( xfs_bmalloca_t *ap) /* bmap alloc argument struct */ { - if (XFS_IS_REALTIME_INODE(ap->ip) && ap->userdata) + if ((ap->ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && ap->userdata) return xfs_bmap_rtalloc(ap); return xfs_bmap_btalloc(ap); } @@ -3096,7 +3096,8 @@ xfs_bmap_del_extent( /* * Realtime allocation. Free it and record di_nblocks update. */ - if (whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip)) { + if (whichfork == XFS_DATA_FORK && + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { xfs_fsblock_t bno; xfs_filblks_t len; @@ -3955,6 +3956,7 @@ xfs_bmap_add_attrfork( xfs_bmap_free_t flist; /* freed extent records */ xfs_mount_t *mp; /* mount structure */ xfs_trans_t *tp; /* transaction pointer */ + unsigned long s; /* spinlock spl value */ int blks; /* space reservation */ int version = 1; /* superblock attr version */ int committed; /* xaction was committed */ @@ -4051,7 +4053,7 @@ xfs_bmap_add_attrfork( (!XFS_SB_VERSION_HASATTR2(&mp->m_sb) && version == 2)) { __int64_t sbfields = 0; - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); if (!XFS_SB_VERSION_HASATTR(&mp->m_sb)) { XFS_SB_VERSION_ADDATTR(&mp->m_sb); sbfields |= XFS_SB_VERSIONNUM; @@ -4061,10 +4063,10 @@ xfs_bmap_add_attrfork( sbfields |= (XFS_SB_VERSIONNUM | XFS_SB_FEATURES2); } if (sbfields) { - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); xfs_mod_sb(tp, sbfields); } else - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); } if ((error = xfs_bmap_finish(&tp, &flist, &committed))) goto error2; @@ -6392,7 +6394,7 @@ xfs_bmap_count_blocks( * Recursively walks each level of a btree * to count total fsblocks is use. */ -STATIC int /* error */ +int /* error */ xfs_bmap_count_tree( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ @@ -6468,7 +6470,7 @@ xfs_bmap_count_tree( /* * Count leaf blocks given a range of extent records. */ -STATIC int +int xfs_bmap_count_leaves( xfs_ifork_t *ifp, xfs_extnum_t idx, @@ -6488,7 +6490,7 @@ xfs_bmap_count_leaves( * Count leaf blocks given a range of extent records originally * in btree format. */ -STATIC int +int xfs_bmap_disk_count_leaves( xfs_extnum_t idx, xfs_bmbt_block_t *block, diff --git a/trunk/fs/xfs/xfs_bmap.h b/trunk/fs/xfs/xfs_bmap.h index 87224b7d7984..68267d75ff19 100644 --- a/trunk/fs/xfs/xfs_bmap.h +++ b/trunk/fs/xfs/xfs_bmap.h @@ -25,8 +25,6 @@ struct xfs_inode; struct xfs_mount; struct xfs_trans; -extern kmem_zone_t *xfs_bmap_free_item_zone; - /* * DELTA: describe a change to the in-core extent list. * diff --git a/trunk/fs/xfs/xfs_bmap_btree.c b/trunk/fs/xfs/xfs_bmap_btree.c index c4181d85605c..32b49ec00fb5 100644 --- a/trunk/fs/xfs/xfs_bmap_btree.c +++ b/trunk/fs/xfs/xfs_bmap_btree.c @@ -2062,7 +2062,8 @@ xfs_bmbt_insert( pcur->bc_private.b.allocated; pcur->bc_private.b.allocated = 0; ASSERT((cur->bc_private.b.firstblock != NULLFSBLOCK) || - XFS_IS_REALTIME_INODE(cur->bc_private.b.ip)); + (cur->bc_private.b.ip->i_d.di_flags & + XFS_DIFLAG_REALTIME)); cur->bc_private.b.firstblock = pcur->bc_private.b.firstblock; ASSERT(cur->bc_private.b.flist == diff --git a/trunk/fs/xfs/xfs_btree.h b/trunk/fs/xfs/xfs_btree.h index 7440b78f9cec..6e40a0a198ff 100644 --- a/trunk/fs/xfs/xfs_btree.h +++ b/trunk/fs/xfs/xfs_btree.h @@ -24,8 +24,6 @@ struct xfs_inode; struct xfs_mount; struct xfs_trans; -extern kmem_zone_t *xfs_btree_cur_zone; - /* * This nonsense is to make -wlint happy. */ diff --git a/trunk/fs/xfs/xfs_buf_item.c b/trunk/fs/xfs/xfs_buf_item.c index 63debd147eb5..c8f2c2886fe4 100644 --- a/trunk/fs/xfs/xfs_buf_item.c +++ b/trunk/fs/xfs/xfs_buf_item.c @@ -378,6 +378,7 @@ xfs_buf_item_unpin( xfs_mount_t *mp; xfs_buf_t *bp; int freed; + SPLDECL(s); bp = bip->bli_buf; ASSERT(bp != NULL); @@ -408,8 +409,8 @@ xfs_buf_item_unpin( XFS_BUF_SET_FSPRIVATE(bp, NULL); XFS_BUF_CLR_IODONE_FUNC(bp); } else { - spin_lock(&mp->m_ail_lock); - xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip); + AIL_LOCK(mp,s); + xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip, s); xfs_buf_item_relse(bp); ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL); } @@ -1112,6 +1113,7 @@ xfs_buf_iodone( xfs_buf_log_item_t *bip) { struct xfs_mount *mp; + SPLDECL(s); ASSERT(bip->bli_buf == bp); @@ -1126,11 +1128,11 @@ xfs_buf_iodone( * * Either way, AIL is useless if we're forcing a shutdown. */ - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp,s); /* * xfs_trans_delete_ail() drops the AIL lock. */ - xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip); + xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip, s); #ifdef XFS_TRANS_DEBUG kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp)); diff --git a/trunk/fs/xfs/xfs_buf_item.h b/trunk/fs/xfs/xfs_buf_item.h index 5a41c348bb1c..d7e136143066 100644 --- a/trunk/fs/xfs/xfs_buf_item.h +++ b/trunk/fs/xfs/xfs_buf_item.h @@ -18,8 +18,6 @@ #ifndef __XFS_BUF_ITEM_H__ #define __XFS_BUF_ITEM_H__ -extern kmem_zone_t *xfs_buf_item_zone; - /* * This is the structure used to lay out a buf log item in the * log. The data map describes which 128 byte chunks of the buffer diff --git a/trunk/fs/xfs/xfs_da_btree.c b/trunk/fs/xfs/xfs_da_btree.c index 1b446849fb3d..26d09e2e1a7f 100644 --- a/trunk/fs/xfs/xfs_da_btree.c +++ b/trunk/fs/xfs/xfs_da_btree.c @@ -2218,7 +2218,7 @@ xfs_da_state_free(xfs_da_state_t *state) #ifdef XFS_DABUF_DEBUG xfs_dabuf_t *xfs_dabuf_global_list; -spinlock_t xfs_dabuf_global_lock; +lock_t xfs_dabuf_global_lock; #endif /* @@ -2264,9 +2264,10 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra) } #ifdef XFS_DABUF_DEBUG { + SPLDECL(s); xfs_dabuf_t *p; - spin_lock(&xfs_dabuf_global_lock); + s = mutex_spinlock(&xfs_dabuf_global_lock); for (p = xfs_dabuf_global_list; p; p = p->next) { ASSERT(p->blkno != dabuf->blkno || p->target != dabuf->target); @@ -2276,7 +2277,7 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra) xfs_dabuf_global_list->prev = dabuf; dabuf->next = xfs_dabuf_global_list; xfs_dabuf_global_list = dabuf; - spin_unlock(&xfs_dabuf_global_lock); + mutex_spinunlock(&xfs_dabuf_global_lock, s); } #endif return dabuf; @@ -2318,14 +2319,16 @@ xfs_da_buf_done(xfs_dabuf_t *dabuf) kmem_free(dabuf->data, BBTOB(dabuf->bbcount)); #ifdef XFS_DABUF_DEBUG { - spin_lock(&xfs_dabuf_global_lock); + SPLDECL(s); + + s = mutex_spinlock(&xfs_dabuf_global_lock); if (dabuf->prev) dabuf->prev->next = dabuf->next; else xfs_dabuf_global_list = dabuf->next; if (dabuf->next) dabuf->next->prev = dabuf->prev; - spin_unlock(&xfs_dabuf_global_lock); + mutex_spinunlock(&xfs_dabuf_global_lock, s); } memset(dabuf, 0, XFS_DA_BUF_SIZE(dabuf->nbuf)); #endif diff --git a/trunk/fs/xfs/xfs_da_btree.h b/trunk/fs/xfs/xfs_da_btree.h index 7facf86f74f9..44dabf02f2a3 100644 --- a/trunk/fs/xfs/xfs_da_btree.h +++ b/trunk/fs/xfs/xfs_da_btree.h @@ -260,7 +260,6 @@ void xfs_da_binval(struct xfs_trans *tp, xfs_dabuf_t *dabuf); xfs_daddr_t xfs_da_blkno(xfs_dabuf_t *dabuf); extern struct kmem_zone *xfs_da_state_zone; -extern struct kmem_zone *xfs_dabuf_zone; #endif /* __KERNEL__ */ #endif /* __XFS_DA_BTREE_H__ */ diff --git a/trunk/fs/xfs/xfs_dfrag.c b/trunk/fs/xfs/xfs_dfrag.c index 3f53fad356a3..584f1ae85cd9 100644 --- a/trunk/fs/xfs/xfs_dfrag.c +++ b/trunk/fs/xfs/xfs_dfrag.c @@ -52,72 +52,76 @@ xfs_swapext( xfs_swapext_t __user *sxu) { xfs_swapext_t *sxp; - xfs_inode_t *ip, *tip; - struct file *file, *target_file; + xfs_inode_t *ip=NULL, *tip=NULL; + xfs_mount_t *mp; + struct file *fp = NULL, *tfp = NULL; + bhv_vnode_t *vp, *tvp; int error = 0; sxp = kmem_alloc(sizeof(xfs_swapext_t), KM_MAYFAIL); if (!sxp) { error = XFS_ERROR(ENOMEM); - goto out; + goto error0; } if (copy_from_user(sxp, sxu, sizeof(xfs_swapext_t))) { error = XFS_ERROR(EFAULT); - goto out_free_sxp; + goto error0; } /* Pull information for the target fd */ - file = fget((int)sxp->sx_fdtarget); - if (!file) { + if (((fp = fget((int)sxp->sx_fdtarget)) == NULL) || + ((vp = vn_from_inode(fp->f_path.dentry->d_inode)) == NULL)) { error = XFS_ERROR(EINVAL); - goto out_free_sxp; + goto error0; } - if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) { + ip = xfs_vtoi(vp); + if (ip == NULL) { error = XFS_ERROR(EBADF); - goto out_put_file; + goto error0; } - target_file = fget((int)sxp->sx_fdtmp); - if (!target_file) { + if (((tfp = fget((int)sxp->sx_fdtmp)) == NULL) || + ((tvp = vn_from_inode(tfp->f_path.dentry->d_inode)) == NULL)) { error = XFS_ERROR(EINVAL); - goto out_put_file; + goto error0; } - if (!(target_file->f_mode & FMODE_WRITE) || - (target_file->f_flags & O_APPEND)) { + tip = xfs_vtoi(tvp); + if (tip == NULL) { error = XFS_ERROR(EBADF); - goto out_put_target_file; + goto error0; } - ip = XFS_I(file->f_path.dentry->d_inode); - tip = XFS_I(target_file->f_path.dentry->d_inode); - if (ip->i_mount != tip->i_mount) { - error = XFS_ERROR(EINVAL); - goto out_put_target_file; + error = XFS_ERROR(EINVAL); + goto error0; } if (ip->i_ino == tip->i_ino) { - error = XFS_ERROR(EINVAL); - goto out_put_target_file; + error = XFS_ERROR(EINVAL); + goto error0; } - if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { - error = XFS_ERROR(EIO); - goto out_put_target_file; + mp = ip->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) { + error = XFS_ERROR(EIO); + goto error0; } - error = xfs_swap_extents(ip, tip, sxp); + error = XFS_SWAP_EXTENTS(mp, &ip->i_iocore, &tip->i_iocore, sxp); + + error0: + if (fp != NULL) + fput(fp); + if (tfp != NULL) + fput(tfp); + + if (sxp != NULL) + kmem_free(sxp, sizeof(xfs_swapext_t)); - out_put_target_file: - fput(target_file); - out_put_file: - fput(file); - out_free_sxp: - kmem_free(sxp, sizeof(xfs_swapext_t)); - out: return error; } @@ -165,6 +169,15 @@ xfs_swap_extents( xfs_lock_inodes(ips, 2, 0, lock_flags); locked = 1; + /* Check permissions */ + error = xfs_iaccess(ip, S_IWUSR, NULL); + if (error) + goto error0; + + error = xfs_iaccess(tip, S_IWUSR, NULL); + if (error) + goto error0; + /* Verify that both files have the same format */ if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) { error = XFS_ERROR(EINVAL); @@ -172,7 +185,8 @@ xfs_swap_extents( } /* Verify both files are either real-time or non-realtime */ - if (XFS_IS_REALTIME_INODE(ip) != XFS_IS_REALTIME_INODE(tip)) { + if ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != + (tip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { error = XFS_ERROR(EINVAL); goto error0; } @@ -185,7 +199,7 @@ xfs_swap_extents( } if (VN_CACHED(tvp) != 0) { - xfs_inval_cached_trace(tip, 0, -1, 0, -1); + xfs_inval_cached_trace(&tip->i_iocore, 0, -1, 0, -1); error = xfs_flushinval_pages(tip, 0, -1, FI_REMAPF_LOCKED); if (error) diff --git a/trunk/fs/xfs/xfs_dinode.h b/trunk/fs/xfs/xfs_dinode.h index c9065eaf2a4d..dedd713574e1 100644 --- a/trunk/fs/xfs/xfs_dinode.h +++ b/trunk/fs/xfs/xfs_dinode.h @@ -171,35 +171,69 @@ typedef enum xfs_dinode_fmt /* * Inode data & attribute fork sizes, per inode. */ -#define XFS_DFORK_Q(dip) ((dip)->di_core.di_forkoff != 0) -#define XFS_DFORK_BOFF(dip) ((int)((dip)->di_core.di_forkoff << 3)) +#define XFS_CFORK_Q(dcp) ((dcp)->di_forkoff != 0) +#define XFS_CFORK_Q_DISK(dcp) ((dcp)->di_forkoff != 0) + +#define XFS_CFORK_BOFF(dcp) ((int)((dcp)->di_forkoff << 3)) +#define XFS_CFORK_BOFF_DISK(dcp) ((int)((dcp)->di_forkoff << 3)) + +#define XFS_CFORK_DSIZE_DISK(dcp,mp) \ + (XFS_CFORK_Q_DISK(dcp) ? XFS_CFORK_BOFF_DISK(dcp) : XFS_LITINO(mp)) +#define XFS_CFORK_DSIZE(dcp,mp) \ + (XFS_CFORK_Q(dcp) ? XFS_CFORK_BOFF(dcp) : XFS_LITINO(mp)) + +#define XFS_CFORK_ASIZE_DISK(dcp,mp) \ + (XFS_CFORK_Q_DISK(dcp) ? XFS_LITINO(mp) - XFS_CFORK_BOFF_DISK(dcp) : 0) +#define XFS_CFORK_ASIZE(dcp,mp) \ + (XFS_CFORK_Q(dcp) ? XFS_LITINO(mp) - XFS_CFORK_BOFF(dcp) : 0) + +#define XFS_CFORK_SIZE_DISK(dcp,mp,w) \ + ((w) == XFS_DATA_FORK ? \ + XFS_CFORK_DSIZE_DISK(dcp, mp) : \ + XFS_CFORK_ASIZE_DISK(dcp, mp)) +#define XFS_CFORK_SIZE(dcp,mp,w) \ + ((w) == XFS_DATA_FORK ? \ + XFS_CFORK_DSIZE(dcp, mp) : XFS_CFORK_ASIZE(dcp, mp)) #define XFS_DFORK_DSIZE(dip,mp) \ - (XFS_DFORK_Q(dip) ? \ - XFS_DFORK_BOFF(dip) : \ - XFS_LITINO(mp)) + XFS_CFORK_DSIZE_DISK(&(dip)->di_core, mp) +#define XFS_DFORK_DSIZE_HOST(dip,mp) \ + XFS_CFORK_DSIZE(&(dip)->di_core, mp) #define XFS_DFORK_ASIZE(dip,mp) \ - (XFS_DFORK_Q(dip) ? \ - XFS_LITINO(mp) - XFS_DFORK_BOFF(dip) : \ - 0) -#define XFS_DFORK_SIZE(dip,mp,w) \ - ((w) == XFS_DATA_FORK ? \ - XFS_DFORK_DSIZE(dip, mp) : \ - XFS_DFORK_ASIZE(dip, mp)) + XFS_CFORK_ASIZE_DISK(&(dip)->di_core, mp) +#define XFS_DFORK_ASIZE_HOST(dip,mp) \ + XFS_CFORK_ASIZE(&(dip)->di_core, mp) +#define XFS_DFORK_SIZE(dip,mp,w) \ + XFS_CFORK_SIZE_DISK(&(dip)->di_core, mp, w) +#define XFS_DFORK_SIZE_HOST(dip,mp,w) \ + XFS_CFORK_SIZE(&(dip)->di_core, mp, w) -#define XFS_DFORK_DPTR(dip) ((dip)->di_u.di_c) -#define XFS_DFORK_APTR(dip) \ +#define XFS_DFORK_Q(dip) XFS_CFORK_Q_DISK(&(dip)->di_core) +#define XFS_DFORK_BOFF(dip) XFS_CFORK_BOFF_DISK(&(dip)->di_core) +#define XFS_DFORK_DPTR(dip) ((dip)->di_u.di_c) +#define XFS_DFORK_APTR(dip) \ ((dip)->di_u.di_c + XFS_DFORK_BOFF(dip)) -#define XFS_DFORK_PTR(dip,w) \ +#define XFS_DFORK_PTR(dip,w) \ ((w) == XFS_DATA_FORK ? XFS_DFORK_DPTR(dip) : XFS_DFORK_APTR(dip)) -#define XFS_DFORK_FORMAT(dip,w) \ +#define XFS_CFORK_FORMAT(dcp,w) \ + ((w) == XFS_DATA_FORK ? (dcp)->di_format : (dcp)->di_aformat) +#define XFS_CFORK_FMT_SET(dcp,w,n) \ ((w) == XFS_DATA_FORK ? \ - (dip)->di_core.di_format : \ - (dip)->di_core.di_aformat) -#define XFS_DFORK_NEXTENTS(dip,w) \ + ((dcp)->di_format = (n)) : ((dcp)->di_aformat = (n))) +#define XFS_DFORK_FORMAT(dip,w) XFS_CFORK_FORMAT(&(dip)->di_core, w) + +#define XFS_CFORK_NEXTENTS_DISK(dcp,w) \ ((w) == XFS_DATA_FORK ? \ - be32_to_cpu((dip)->di_core.di_nextents) : \ - be16_to_cpu((dip)->di_core.di_anextents)) + be32_to_cpu((dcp)->di_nextents) : \ + be16_to_cpu((dcp)->di_anextents)) +#define XFS_CFORK_NEXTENTS(dcp,w) \ + ((w) == XFS_DATA_FORK ? (dcp)->di_nextents : (dcp)->di_anextents) +#define XFS_DFORK_NEXTENTS(dip,w) XFS_CFORK_NEXTENTS_DISK(&(dip)->di_core, w) +#define XFS_DFORK_NEXTENTS_HOST(dip,w) XFS_CFORK_NEXTENTS(&(dip)->di_core, w) + +#define XFS_CFORK_NEXT_SET(dcp,w,n) \ + ((w) == XFS_DATA_FORK ? \ + ((dcp)->di_nextents = (n)) : ((dcp)->di_anextents = (n))) #define XFS_BUF_TO_DINODE(bp) ((xfs_dinode_t *)XFS_BUF_PTR(bp)) @@ -239,12 +273,6 @@ typedef enum xfs_dinode_fmt #define XFS_DIFLAG_NODEFRAG (1 << XFS_DIFLAG_NODEFRAG_BIT) #define XFS_DIFLAG_FILESTREAM (1 << XFS_DIFLAG_FILESTREAM_BIT) -#ifdef CONFIG_XFS_RT -#define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) -#else -#define XFS_IS_REALTIME_INODE(ip) (0) -#endif - #define XFS_DIFLAG_ANY \ (XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \ XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \ diff --git a/trunk/fs/xfs/xfs_dir2.c b/trunk/fs/xfs/xfs_dir2.c index be7c4251fa61..b0f1ee8fcb90 100644 --- a/trunk/fs/xfs/xfs_dir2.c +++ b/trunk/fs/xfs/xfs_dir2.c @@ -42,7 +42,6 @@ #include "xfs_dir2_node.h" #include "xfs_dir2_trace.h" #include "xfs_error.h" -#include "xfs_vnodeops.h" void @@ -302,7 +301,7 @@ xfs_readdir( int rval; /* return value */ int v; /* type-checking value */ - xfs_itrace_entry(dp); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return XFS_ERROR(EIO); diff --git a/trunk/fs/xfs/xfs_error.c b/trunk/fs/xfs/xfs_error.c index 05e5365d3c31..a4634d94e561 100644 --- a/trunk/fs/xfs/xfs_error.c +++ b/trunk/fs/xfs/xfs_error.c @@ -230,6 +230,37 @@ xfs_error_report( } } +STATIC void +xfs_hex_dump(void *p, int length) +{ + __uint8_t *uip = (__uint8_t*)p; + int i; + char sbuf[128], *s; + + s = sbuf; + *s = '\0'; + for (i=0; iefi_item.li_mountp; - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp, s); if (efip->efi_flags & XFS_EFI_CANCELED) { /* * xfs_trans_delete_ail() drops the AIL lock. */ - xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip); + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); xfs_efi_item_free(efip); } else { efip->efi_flags |= XFS_EFI_COMMITTED; - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); } } @@ -137,9 +138,10 @@ xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp) { xfs_mount_t *mp; xfs_log_item_desc_t *lidp; + SPLDECL(s); mp = efip->efi_item.li_mountp; - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp, s); if (efip->efi_flags & XFS_EFI_CANCELED) { /* * free the xaction descriptor pointing to this item @@ -150,11 +152,11 @@ xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp) * pull the item off the AIL. * xfs_trans_delete_ail() drops the AIL lock. */ - xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip); + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); xfs_efi_item_free(efip); } else { efip->efi_flags |= XFS_EFI_COMMITTED; - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); } } @@ -348,12 +350,13 @@ xfs_efi_release(xfs_efi_log_item_t *efip, { xfs_mount_t *mp; int extents_left; + SPLDECL(s); mp = efip->efi_item.li_mountp; ASSERT(efip->efi_next_extent > 0); ASSERT(efip->efi_flags & XFS_EFI_COMMITTED); - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp, s); ASSERT(efip->efi_next_extent >= nextents); efip->efi_next_extent -= nextents; extents_left = efip->efi_next_extent; @@ -361,10 +364,10 @@ xfs_efi_release(xfs_efi_log_item_t *efip, /* * xfs_trans_delete_ail() drops the AIL lock. */ - xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip); + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); xfs_efi_item_free(efip); } else { - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); } } diff --git a/trunk/fs/xfs/xfs_filestream.c b/trunk/fs/xfs/xfs_filestream.c index eb03eab5ca52..36d8f6aa11af 100644 --- a/trunk/fs/xfs/xfs_filestream.c +++ b/trunk/fs/xfs/xfs_filestream.c @@ -348,7 +348,7 @@ _xfs_filestream_update_ag( } /* xfs_fstrm_free_func(): callback for freeing cached stream items. */ -STATIC void +void xfs_fstrm_free_func( unsigned long ino, void *data) diff --git a/trunk/fs/xfs/xfs_fs.h b/trunk/fs/xfs/xfs_fs.h index 3bed6433d050..aab966276517 100644 --- a/trunk/fs/xfs/xfs_fs.h +++ b/trunk/fs/xfs/xfs_fs.h @@ -419,13 +419,9 @@ typedef struct xfs_handle { /* * ioctl commands that are used by Linux filesystems */ -#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS -#define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS -#define XFS_IOC_GETVERSION FS_IOC_GETVERSION -/* 32-bit compat counterparts */ -#define XFS_IOC32_GETXFLAGS FS_IOC32_GETFLAGS -#define XFS_IOC32_SETXFLAGS FS_IOC32_SETFLAGS -#define XFS_IOC32_GETVERSION FS_IOC32_GETVERSION +#define XFS_IOC_GETXFLAGS _IOR('f', 1, long) +#define XFS_IOC_SETXFLAGS _IOW('f', 2, long) +#define XFS_IOC_GETVERSION _IOR('v', 1, long) /* * ioctl commands that replace IRIX fcntl()'s diff --git a/trunk/fs/xfs/xfs_fsops.c b/trunk/fs/xfs/xfs_fsops.c index b8de7f3cc17e..c92d5b821029 100644 --- a/trunk/fs/xfs/xfs_fsops.c +++ b/trunk/fs/xfs/xfs_fsops.c @@ -462,13 +462,15 @@ xfs_fs_counts( xfs_mount_t *mp, xfs_fsop_counts_t *cnt) { + unsigned long s; + xfs_icsb_sync_counters_flags(mp, XFS_ICSB_LAZY_COUNT); - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); cnt->freedata = mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); cnt->freertx = mp->m_sb.sb_frextents; cnt->freeino = mp->m_sb.sb_ifree; cnt->allocino = mp->m_sb.sb_icount; - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); return 0; } @@ -495,6 +497,7 @@ xfs_reserve_blocks( { __int64_t lcounter, delta, fdblks_delta; __uint64_t request; + unsigned long s; /* If inval is null, report current values and return */ if (inval == (__uint64_t *)NULL) { @@ -512,7 +515,7 @@ xfs_reserve_blocks( * problem. we needto work out if we are freeing or allocation * blocks first, then we can do the modification as necessary. * - * We do this under the m_sb_lock so that if we are near + * We do this under the XFS_SB_LOCK so that if we are near * ENOSPC, we will hold out any changes while we work out * what to do. This means that the amount of free space can * change while we do this, so we need to retry if we end up @@ -523,7 +526,7 @@ xfs_reserve_blocks( * enabled, disabled or even compiled in.... */ retry: - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); xfs_icsb_sync_counters_flags(mp, XFS_ICSB_SB_LOCKED); /* @@ -566,7 +569,7 @@ xfs_reserve_blocks( outval->resblks = mp->m_resblks; outval->resblks_avail = mp->m_resblks_avail; } - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); if (fdblks_delta) { /* diff --git a/trunk/fs/xfs/xfs_ialloc_btree.h b/trunk/fs/xfs/xfs_ialloc_btree.h index 8efc4a5b8b92..bf8e9aff272e 100644 --- a/trunk/fs/xfs/xfs_ialloc_btree.h +++ b/trunk/fs/xfs/xfs_ialloc_btree.h @@ -81,6 +81,8 @@ typedef struct xfs_btree_sblock xfs_inobt_block_t; #define XFS_INOBT_MASK(i) ((xfs_inofree_t)1 << (i)) #define XFS_INOBT_IS_FREE(rp,i) \ (((rp)->ir_free & XFS_INOBT_MASK(i)) != 0) +#define XFS_INOBT_IS_FREE_DISK(rp,i) \ + ((be64_to_cpu((rp)->ir_free) & XFS_INOBT_MASK(i)) != 0) #define XFS_INOBT_SET_FREE(rp,i) ((rp)->ir_free |= XFS_INOBT_MASK(i)) #define XFS_INOBT_CLR_FREE(rp,i) ((rp)->ir_free &= ~XFS_INOBT_MASK(i)) diff --git a/trunk/fs/xfs/xfs_iget.c b/trunk/fs/xfs/xfs_iget.c index f01b07687faf..fb69ef180b27 100644 --- a/trunk/fs/xfs/xfs_iget.c +++ b/trunk/fs/xfs/xfs_iget.c @@ -65,7 +65,7 @@ */ STATIC int xfs_iget_core( - struct inode *inode, + bhv_vnode_t *vp, xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, @@ -74,9 +74,9 @@ xfs_iget_core( xfs_inode_t **ipp, xfs_daddr_t bno) { - struct inode *old_inode; xfs_inode_t *ip; xfs_inode_t *iq; + bhv_vnode_t *inode_vp; int error; xfs_icluster_t *icl, *new_icl = NULL; unsigned long first_index, mask; @@ -111,8 +111,8 @@ xfs_iget_core( goto again; } - old_inode = ip->i_vnode; - if (old_inode == NULL) { + inode_vp = XFS_ITOV_NULL(ip); + if (inode_vp == NULL) { /* * If IRECLAIM is set this inode is * on its way out of the system, @@ -140,9 +140,28 @@ xfs_iget_core( return ENOENT; } - xfs_itrace_exit_tag(ip, "xfs_iget.alloc"); + /* + * There may be transactions sitting in the + * incore log buffers or being flushed to disk + * at this time. We can't clear the + * XFS_IRECLAIMABLE flag until these + * transactions have hit the disk, otherwise we + * will void the guarantee the flag provides + * xfs_iunpin() + */ + if (xfs_ipincount(ip)) { + read_unlock(&pag->pag_ici_lock); + xfs_log_force(mp, 0, + XFS_LOG_FORCE|XFS_LOG_SYNC); + XFS_STATS_INC(xs_ig_frecycle); + goto again; + } + + vn_trace_exit(ip, "xfs_iget.alloc", + (inst_t *)__return_address); XFS_STATS_INC(xs_ig_found); + xfs_iflags_clear(ip, XFS_IRECLAIMABLE); read_unlock(&pag->pag_ici_lock); @@ -152,11 +171,13 @@ xfs_iget_core( goto finish_inode; - } else if (inode != old_inode) { + } else if (vp != inode_vp) { + struct inode *inode = vn_to_inode(inode_vp); + /* The inode is being torn down, pause and * try again. */ - if (old_inode->i_state & (I_FREEING | I_CLEAR)) { + if (inode->i_state & (I_FREEING | I_CLEAR)) { read_unlock(&pag->pag_ici_lock); delay(1); XFS_STATS_INC(xs_ig_frecycle); @@ -169,7 +190,7 @@ xfs_iget_core( */ cmn_err(CE_PANIC, "xfs_iget_core: ambiguous vns: vp/0x%p, invp/0x%p", - old_inode, inode); + inode_vp, vp); } /* @@ -179,16 +200,20 @@ xfs_iget_core( XFS_STATS_INC(xs_ig_found); finish_inode: - if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) { - xfs_put_perag(mp, pag); - return ENOENT; + if (ip->i_d.di_mode == 0) { + if (!(flags & XFS_IGET_CREATE)) { + xfs_put_perag(mp, pag); + return ENOENT; + } + xfs_iocore_inode_reinit(ip); } if (lock_flags != 0) xfs_ilock(ip, lock_flags); xfs_iflags_clear(ip, XFS_ISTALE); - xfs_itrace_exit_tag(ip, "xfs_iget.found"); + vn_trace_exit(ip, "xfs_iget.found", + (inst_t *)__return_address); goto return_ip; } @@ -209,16 +234,10 @@ xfs_iget_core( return error; } - xfs_itrace_exit_tag(ip, "xfs_iget.alloc"); - - - mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER, - "xfsino", ip->i_ino); - mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino); - init_waitqueue_head(&ip->i_ipin_wait); - atomic_set(&ip->i_pincount, 0); - initnsema(&ip->i_flock, 1, "xfsfino"); + vn_trace_exit(ip, "xfs_iget.alloc", (inst_t *)__return_address); + xfs_inode_lock_init(ip, vp); + xfs_iocore_inode_init(ip); if (lock_flags) xfs_ilock(ip, lock_flags); @@ -314,6 +333,9 @@ xfs_iget_core( ASSERT(ip->i_df.if_ext_max == XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t)); + ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) == + ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0)); + xfs_iflags_set(ip, XFS_IMODIFIED); *ipp = ip; @@ -321,7 +343,7 @@ xfs_iget_core( * If we have a real type for an on-disk inode, we can set ops(&unlock) * now. If it's a new inode being created, xfs_ialloc will handle it. */ - xfs_initialize_vnode(mp, inode, ip); + xfs_initialize_vnode(mp, vp, ip); return 0; } @@ -341,58 +363,69 @@ xfs_iget( xfs_daddr_t bno) { struct inode *inode; - xfs_inode_t *ip; + bhv_vnode_t *vp = NULL; int error; XFS_STATS_INC(xs_ig_attempts); retry: inode = iget_locked(mp->m_super, ino); - if (!inode) - /* If we got no inode we are out of memory */ - return ENOMEM; - - if (inode->i_state & I_NEW) { - XFS_STATS_INC(vn_active); - XFS_STATS_INC(vn_alloc); - - error = xfs_iget_core(inode, mp, tp, ino, flags, - lock_flags, ipp, bno); - if (error) { - make_bad_inode(inode); - if (inode->i_state & I_NEW) - unlock_new_inode(inode); - iput(inode); - } - return error; - } + if (inode) { + xfs_inode_t *ip; + + vp = vn_from_inode(inode); + if (inode->i_state & I_NEW) { + vn_initialize(inode); + error = xfs_iget_core(vp, mp, tp, ino, flags, + lock_flags, ipp, bno); + if (error) { + vn_mark_bad(vp); + if (inode->i_state & I_NEW) + unlock_new_inode(inode); + iput(inode); + } + } else { + /* + * If the inode is not fully constructed due to + * filehandle mismatches wait for the inode to go + * away and try again. + * + * iget_locked will call __wait_on_freeing_inode + * to wait for the inode to go away. + */ + if (is_bad_inode(inode) || + ((ip = xfs_vtoi(vp)) == NULL)) { + iput(inode); + delay(1); + goto retry; + } - /* - * If the inode is not fully constructed due to - * filehandle mismatches wait for the inode to go - * away and try again. - * - * iget_locked will call __wait_on_freeing_inode - * to wait for the inode to go away. - */ - if (is_bad_inode(inode)) { - iput(inode); - delay(1); - goto retry; - } + if (lock_flags != 0) + xfs_ilock(ip, lock_flags); + XFS_STATS_INC(xs_ig_found); + *ipp = ip; + error = 0; + } + } else + error = ENOMEM; /* If we got no inode we are out of memory */ - ip = XFS_I(inode); - if (!ip) { - iput(inode); - delay(1); - goto retry; - } + return error; +} - if (lock_flags != 0) - xfs_ilock(ip, lock_flags); - XFS_STATS_INC(xs_ig_found); - *ipp = ip; - return 0; +/* + * Do the setup for the various locks within the incore inode. + */ +void +xfs_inode_lock_init( + xfs_inode_t *ip, + bhv_vnode_t *vp) +{ + mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER, + "xfsino", ip->i_ino); + mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino); + init_waitqueue_head(&ip->i_ipin_wait); + atomic_set(&ip->i_pincount, 0); + initnsema(&ip->i_flock, 1, "xfsfino"); } /* @@ -432,9 +465,11 @@ void xfs_iput(xfs_inode_t *ip, uint lock_flags) { - xfs_itrace_entry(ip); + bhv_vnode_t *vp = XFS_ITOV(ip); + + vn_trace_entry(ip, "xfs_iput", (inst_t *)__return_address); xfs_iunlock(ip, lock_flags); - IRELE(ip); + VN_RELE(vp); } /* @@ -444,19 +479,20 @@ void xfs_iput_new(xfs_inode_t *ip, uint lock_flags) { - struct inode *inode = ip->i_vnode; + bhv_vnode_t *vp = XFS_ITOV(ip); + struct inode *inode = vn_to_inode(vp); - xfs_itrace_entry(ip); + vn_trace_entry(ip, "xfs_iput_new", (inst_t *)__return_address); if ((ip->i_d.di_mode == 0)) { ASSERT(!xfs_iflags_test(ip, XFS_IRECLAIMABLE)); - make_bad_inode(inode); + vn_mark_bad(vp); } if (inode->i_state & I_NEW) unlock_new_inode(inode); if (lock_flags) xfs_iunlock(ip, lock_flags); - IRELE(ip); + VN_RELE(vp); } @@ -469,6 +505,8 @@ xfs_iput_new(xfs_inode_t *ip, void xfs_ireclaim(xfs_inode_t *ip) { + bhv_vnode_t *vp; + /* * Remove from old hash list and mount list. */ @@ -497,8 +535,9 @@ xfs_ireclaim(xfs_inode_t *ip) /* * Pull our behavior descriptor from the vnode chain. */ - if (ip->i_vnode) { - ip->i_vnode->i_private = NULL; + vp = XFS_ITOV_NULL(ip); + if (vp) { + vn_to_inode(vp)->i_private = NULL; ip->i_vnode = NULL; } diff --git a/trunk/fs/xfs/xfs_inode.c b/trunk/fs/xfs/xfs_inode.c index a550546a7083..344948082819 100644 --- a/trunk/fs/xfs/xfs_inode.c +++ b/trunk/fs/xfs/xfs_inode.c @@ -15,8 +15,6 @@ * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include - #include "xfs.h" #include "xfs_fs.h" #include "xfs_types.h" @@ -828,17 +826,15 @@ xfs_ip2xflags( xfs_icdinode_t *dic = &ip->i_d; return _xfs_dic2xflags(dic->di_flags) | - (XFS_IFORK_Q(ip) ? XFS_XFLAG_HASATTR : 0); + (XFS_CFORK_Q(dic) ? XFS_XFLAG_HASATTR : 0); } uint xfs_dic2xflags( - xfs_dinode_t *dip) + xfs_dinode_core_t *dic) { - xfs_dinode_core_t *dic = &dip->di_core; - return _xfs_dic2xflags(be16_to_cpu(dic->di_flags)) | - (XFS_DFORK_Q(dip) ? XFS_XFLAG_HASATTR : 0); + (XFS_CFORK_Q_DISK(dic) ? XFS_XFLAG_HASATTR : 0); } /* @@ -888,8 +884,8 @@ xfs_iread( * Initialize inode's trace buffers. * Do this before xfs_iformat in case it adds entries. */ -#ifdef XFS_INODE_TRACE - ip->i_trace = ktrace_alloc(INODE_TRACE_SIZE, KM_SLEEP); +#ifdef XFS_VNODE_TRACE + ip->i_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP); #endif #ifdef XFS_BMAP_TRACE ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, KM_SLEEP); @@ -1224,8 +1220,10 @@ xfs_ialloc( ip->i_d.di_extsize = pip->i_d.di_extsize; } } else if ((mode & S_IFMT) == S_IFREG) { - if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) + if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) { di_flags |= XFS_DIFLAG_REALTIME; + ip->i_iocore.io_flags |= XFS_IOCORE_RT; + } if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { di_flags |= XFS_DIFLAG_EXTSIZE; ip->i_d.di_extsize = pip->i_d.di_extsize; @@ -1300,10 +1298,7 @@ xfs_isize_check( if ((ip->i_d.di_mode & S_IFMT) != S_IFREG) return; - if (XFS_IS_REALTIME_INODE(ip)) - return; - - if (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) + if (ip->i_d.di_flags & (XFS_DIFLAG_REALTIME | XFS_DIFLAG_EXTSIZE)) return; nimaps = 2; @@ -1716,7 +1711,7 @@ xfs_itruncate_finish( * runs. */ XFS_BMAP_INIT(&free_list, &first_block); - error = xfs_bunmapi(ntp, ip, + error = XFS_BUNMAPI(mp, ntp, &ip->i_iocore, first_unmap_block, unmap_len, XFS_BMAPI_AFLAG(fork) | (sync ? 0 : XFS_BMAPI_ASYNC), @@ -1849,6 +1844,8 @@ xfs_igrow_start( xfs_fsize_t new_size, cred_t *credp) { + int error; + ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0); ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0); ASSERT(new_size > ip->i_size); @@ -1858,7 +1855,9 @@ xfs_igrow_start( * xfs_write_file() beyond the end of the file * and any blocks between the old and new file sizes. */ - return xfs_zero_eof(ip, new_size, ip->i_size); + error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size, + ip->i_size); + return error; } /* @@ -1960,6 +1959,24 @@ xfs_iunlink( ASSERT(agi->agi_unlinked[bucket_index]); ASSERT(be32_to_cpu(agi->agi_unlinked[bucket_index]) != agino); + error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0); + if (error) + return error; + + /* + * Clear the on-disk di_nlink. This is to prevent xfs_bulkstat + * from picking up this inode when it is reclaimed (its incore state + * initialzed but not flushed to disk yet). The in-core di_nlink is + * already cleared in xfs_droplink() and a corresponding transaction + * logged. The hack here just synchronizes the in-core to on-disk + * di_nlink value in advance before the actual inode sync to disk. + * This is OK because the inode is already unlinked and would never + * change its di_nlink again for this inode generation. + * This is a temporary hack that would require a proper fix + * in the future. + */ + dip->di_core.di_nlink = 0; + if (be32_to_cpu(agi->agi_unlinked[bucket_index]) != NULLAGINO) { /* * There is already another inode in the bucket we need @@ -1967,10 +1984,6 @@ xfs_iunlink( * Here we put the head pointer into our next pointer, * and then we fall through to point the head at us. */ - error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0); - if (error) - return error; - ASSERT(be32_to_cpu(dip->di_next_unlinked) == NULLAGINO); /* both on-disk, don't endian flip twice */ dip->di_next_unlinked = agi->agi_unlinked[bucket_index]; @@ -2196,6 +2209,7 @@ xfs_ifree_cluster( xfs_inode_log_item_t *iip; xfs_log_item_t *lip; xfs_perag_t *pag = xfs_get_perag(mp, inum); + SPLDECL(s); if (mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) { blks_per_cluster = 1; @@ -2297,9 +2311,9 @@ xfs_ifree_cluster( iip = (xfs_inode_log_item_t *)lip; ASSERT(iip->ili_logged == 1); lip->li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*)) xfs_istale_done; - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp,s); iip->ili_flush_lsn = iip->ili_item.li_lsn; - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); xfs_iflags_set(iip->ili_inode, XFS_ISTALE); pre_flushed++; } @@ -2320,9 +2334,9 @@ xfs_ifree_cluster( iip->ili_last_fields = iip->ili_format.ilf_fields; iip->ili_format.ilf_fields = 0; iip->ili_logged = 1; - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp,s); iip->ili_flush_lsn = iip->ili_item.li_lsn; - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t*,xfs_log_item_t*)) @@ -2360,8 +2374,6 @@ xfs_ifree( int error; int delete; xfs_ino_t first_ino; - xfs_dinode_t *dip; - xfs_buf_t *ibp; ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); ASSERT(ip->i_transp == tp); @@ -2397,27 +2409,8 @@ xfs_ifree( * by reincarnations of this inode. */ ip->i_d.di_gen++; - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - error = xfs_itobp(ip->i_mount, tp, ip, &dip, &ibp, 0, 0); - if (error) - return error; - - /* - * Clear the on-disk di_mode. This is to prevent xfs_bulkstat - * from picking up this inode when it is reclaimed (its incore state - * initialzed but not flushed to disk yet). The in-core di_mode is - * already cleared and a corresponding transaction logged. - * The hack here just synchronizes the in-core to on-disk - * di_mode value in advance before the actual inode sync to disk. - * This is OK because the inode is already unlinked and would never - * change its di_mode again for this inode generation. - * This is a temporary hack that would require a proper fix - * in the future. - */ - dip->di_core.di_mode = 0; - if (delete) { xfs_ifree_cluster(ip, tp, first_ino); } @@ -2742,6 +2735,7 @@ void xfs_idestroy( xfs_inode_t *ip) { + switch (ip->i_d.di_mode & S_IFMT) { case S_IFREG: case S_IFDIR: @@ -2755,7 +2749,7 @@ xfs_idestroy( mrfree(&ip->i_iolock); freesema(&ip->i_flock); -#ifdef XFS_INODE_TRACE +#ifdef XFS_VNODE_TRACE ktrace_free(ip->i_trace); #endif #ifdef XFS_BMAP_TRACE @@ -2781,15 +2775,16 @@ xfs_idestroy( */ xfs_mount_t *mp = ip->i_mount; xfs_log_item_t *lip = &ip->i_itemp->ili_item; + int s; ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) || XFS_FORCED_SHUTDOWN(ip->i_mount)); if (lip->li_flags & XFS_LI_IN_AIL) { - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp, s); if (lip->li_flags & XFS_LI_IN_AIL) - xfs_trans_delete_ail(mp, lip); + xfs_trans_delete_ail(mp, lip, s); else - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); } xfs_inode_item_destroy(ip); } @@ -2821,8 +2816,40 @@ xfs_iunpin( { ASSERT(atomic_read(&ip->i_pincount) > 0); - if (atomic_dec_and_test(&ip->i_pincount)) + if (atomic_dec_and_lock(&ip->i_pincount, &ip->i_flags_lock)) { + + /* + * If the inode is currently being reclaimed, the link between + * the bhv_vnode and the xfs_inode will be broken after the + * XFS_IRECLAIM* flag is set. Hence, if these flags are not + * set, then we can move forward and mark the linux inode dirty + * knowing that it is still valid as it won't freed until after + * the bhv_vnode<->xfs_inode link is broken in xfs_reclaim. The + * i_flags_lock is used to synchronise the setting of the + * XFS_IRECLAIM* flags and the breaking of the link, and so we + * can execute atomically w.r.t to reclaim by holding this lock + * here. + * + * However, we still need to issue the unpin wakeup call as the + * inode reclaim may be blocked waiting for the inode to become + * unpinned. + */ + + if (!__xfs_iflags_test(ip, XFS_IRECLAIM|XFS_IRECLAIMABLE)) { + bhv_vnode_t *vp = XFS_ITOV_NULL(ip); + struct inode *inode = NULL; + + BUG_ON(vp == NULL); + inode = vn_to_inode(vp); + BUG_ON(inode->i_state & I_CLEAR); + + /* make sync come back and flush this inode */ + if (!(inode->i_state & (I_NEW|I_FREEING))) + mark_inode_dirty_sync(inode); + } + spin_unlock(&ip->i_flags_lock); wake_up(&ip->i_ipin_wait); + } } /* @@ -3311,6 +3338,7 @@ xfs_iflush_int( #ifdef XFS_TRANS_DEBUG int first; #endif + SPLDECL(s); ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); ASSERT(issemalocked(&(ip->i_flock))); @@ -3505,9 +3533,9 @@ xfs_iflush_int( iip->ili_logged = 1; ASSERT(sizeof(xfs_lsn_t) == 8); /* don't lock if it shrinks */ - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp,s); iip->ili_flush_lsn = iip->ili_item.li_lsn; - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); /* * Attach the function xfs_iflush_done to the inode's @@ -3583,6 +3611,95 @@ xfs_iflush_all( XFS_MOUNT_IUNLOCK(mp); } +/* + * xfs_iaccess: check accessibility of inode for mode. + */ +int +xfs_iaccess( + xfs_inode_t *ip, + mode_t mode, + cred_t *cr) +{ + int error; + mode_t orgmode = mode; + struct inode *inode = vn_to_inode(XFS_ITOV(ip)); + + if (mode & S_IWUSR) { + umode_t imode = inode->i_mode; + + if (IS_RDONLY(inode) && + (S_ISREG(imode) || S_ISDIR(imode) || S_ISLNK(imode))) + return XFS_ERROR(EROFS); + + if (IS_IMMUTABLE(inode)) + return XFS_ERROR(EACCES); + } + + /* + * If there's an Access Control List it's used instead of + * the mode bits. + */ + if ((error = _ACL_XFS_IACCESS(ip, mode, cr)) != -1) + return error ? XFS_ERROR(error) : 0; + + if (current_fsuid(cr) != ip->i_d.di_uid) { + mode >>= 3; + if (!in_group_p((gid_t)ip->i_d.di_gid)) + mode >>= 3; + } + + /* + * If the DACs are ok we don't need any capability check. + */ + if ((ip->i_d.di_mode & mode) == mode) + return 0; + /* + * Read/write DACs are always overridable. + * Executable DACs are overridable if at least one exec bit is set. + */ + if (!(orgmode & S_IXUSR) || + (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode)) + if (capable_cred(cr, CAP_DAC_OVERRIDE)) + return 0; + + if ((orgmode == S_IRUSR) || + (S_ISDIR(inode->i_mode) && (!(orgmode & S_IWUSR)))) { + if (capable_cred(cr, CAP_DAC_READ_SEARCH)) + return 0; +#ifdef NOISE + cmn_err(CE_NOTE, "Ick: mode=%o, orgmode=%o", mode, orgmode); +#endif /* NOISE */ + return XFS_ERROR(EACCES); + } + return XFS_ERROR(EACCES); +} + +/* + * xfs_iroundup: round up argument to next power of two + */ +uint +xfs_iroundup( + uint v) +{ + int i; + uint m; + + if ((v & (v - 1)) == 0) + return v; + ASSERT((v & 0x80000000) == 0); + if ((v & (v + 1)) == 0) + return v + 1; + for (i = 0, m = 1; i < 31; i++, m <<= 1) { + if (v & m) + continue; + v |= m; + if ((v & (v + 1)) == 0) + return v + 1; + } + ASSERT(0); + return( 0 ); +} + #ifdef XFS_ILOCK_TRACE ktrace_t *xfs_ilock_trace_buf; @@ -4089,7 +4206,7 @@ xfs_iext_realloc_direct( return; } if (!is_power_of_2(new_size)){ - rnew_size = roundup_pow_of_two(new_size); + rnew_size = xfs_iroundup(new_size); } if (rnew_size != ifp->if_real_bytes) { ifp->if_u1.if_extents = @@ -4112,7 +4229,7 @@ xfs_iext_realloc_direct( else { new_size += ifp->if_bytes; if (!is_power_of_2(new_size)) { - rnew_size = roundup_pow_of_two(new_size); + rnew_size = xfs_iroundup(new_size); } xfs_iext_inline_to_direct(ifp, rnew_size); } diff --git a/trunk/fs/xfs/xfs_inode.h b/trunk/fs/xfs/xfs_inode.h index bfcd72cbaeea..e5aff929cc65 100644 --- a/trunk/fs/xfs/xfs_inode.h +++ b/trunk/fs/xfs/xfs_inode.h @@ -132,6 +132,45 @@ typedef struct dm_attrs_s { __uint16_t da_pad; /* DMIG extra padding */ } dm_attrs_t; +typedef struct xfs_iocore { + void *io_obj; /* pointer to container + * inode or dcxvn structure */ + struct xfs_mount *io_mount; /* fs mount struct ptr */ +#ifdef DEBUG + mrlock_t *io_lock; /* inode IO lock */ + mrlock_t *io_iolock; /* inode IO lock */ +#endif + + /* I/O state */ + xfs_fsize_t io_new_size; /* sz when write completes */ + + /* Miscellaneous state. */ + unsigned int io_flags; /* IO related flags */ + + /* DMAPI state */ + dm_attrs_t io_dmattrs; + +} xfs_iocore_t; + +#define io_dmevmask io_dmattrs.da_dmevmask +#define io_dmstate io_dmattrs.da_dmstate + +#define XFS_IO_INODE(io) ((xfs_inode_t *) ((io)->io_obj)) +#define XFS_IO_DCXVN(io) ((dcxvn_t *) ((io)->io_obj)) + +/* + * Flags in the flags field + */ + +#define XFS_IOCORE_RT 0x1 + +/* + * xfs_iocore prototypes + */ + +extern void xfs_iocore_inode_init(struct xfs_inode *); +extern void xfs_iocore_inode_reinit(struct xfs_inode *); + /* * This is the xfs inode cluster structure. This structure is used by * xfs_iflush to find inodes that share a cluster and can be flushed to disk at @@ -142,7 +181,7 @@ typedef struct xfs_icluster { xfs_daddr_t icl_blkno; /* starting block number of * the cluster */ struct xfs_buf *icl_buf; /* the inode buffer */ - spinlock_t icl_lock; /* inode list lock */ + lock_t icl_lock; /* inode list lock */ } xfs_icluster_t; /* @@ -244,6 +283,9 @@ typedef struct xfs_inode { struct xfs_inode **i_refcache; /* ptr to entry in ref cache */ struct xfs_inode *i_release; /* inode to unref */ #endif + /* I/O state */ + xfs_iocore_t i_iocore; /* I/O core */ + /* Miscellaneous state. */ unsigned short i_flags; /* see defined flags below */ unsigned char i_update_core; /* timestamps/size is dirty */ @@ -256,10 +298,9 @@ typedef struct xfs_inode { struct hlist_node i_cnode; /* cluster link node */ xfs_fsize_t i_size; /* in-memory size */ - xfs_fsize_t i_new_size; /* size when write completes */ atomic_t i_iocount; /* outstanding I/O count */ /* Trace buffers per inode. */ -#ifdef XFS_INODE_TRACE +#ifdef XFS_VNODE_TRACE struct ktrace *i_trace; /* general inode trace */ #endif #ifdef XFS_BMAP_TRACE @@ -341,42 +382,17 @@ xfs_iflags_test_and_clear(xfs_inode_t *ip, unsigned short flags) /* * Fork handling. */ +#define XFS_IFORK_PTR(ip,w) \ + ((w) == XFS_DATA_FORK ? &(ip)->i_df : (ip)->i_afp) +#define XFS_IFORK_Q(ip) XFS_CFORK_Q(&(ip)->i_d) +#define XFS_IFORK_DSIZE(ip) XFS_CFORK_DSIZE(&ip->i_d, ip->i_mount) +#define XFS_IFORK_ASIZE(ip) XFS_CFORK_ASIZE(&ip->i_d, ip->i_mount) +#define XFS_IFORK_SIZE(ip,w) XFS_CFORK_SIZE(&ip->i_d, ip->i_mount, w) +#define XFS_IFORK_FORMAT(ip,w) XFS_CFORK_FORMAT(&ip->i_d, w) +#define XFS_IFORK_FMT_SET(ip,w,n) XFS_CFORK_FMT_SET(&ip->i_d, w, n) +#define XFS_IFORK_NEXTENTS(ip,w) XFS_CFORK_NEXTENTS(&ip->i_d, w) +#define XFS_IFORK_NEXT_SET(ip,w,n) XFS_CFORK_NEXT_SET(&ip->i_d, w, n) -#define XFS_IFORK_Q(ip) ((ip)->i_d.di_forkoff != 0) -#define XFS_IFORK_BOFF(ip) ((int)((ip)->i_d.di_forkoff << 3)) - -#define XFS_IFORK_PTR(ip,w) \ - ((w) == XFS_DATA_FORK ? \ - &(ip)->i_df : \ - (ip)->i_afp) -#define XFS_IFORK_DSIZE(ip) \ - (XFS_IFORK_Q(ip) ? \ - XFS_IFORK_BOFF(ip) : \ - XFS_LITINO((ip)->i_mount)) -#define XFS_IFORK_ASIZE(ip) \ - (XFS_IFORK_Q(ip) ? \ - XFS_LITINO((ip)->i_mount) - XFS_IFORK_BOFF(ip) : \ - 0) -#define XFS_IFORK_SIZE(ip,w) \ - ((w) == XFS_DATA_FORK ? \ - XFS_IFORK_DSIZE(ip) : \ - XFS_IFORK_ASIZE(ip)) -#define XFS_IFORK_FORMAT(ip,w) \ - ((w) == XFS_DATA_FORK ? \ - (ip)->i_d.di_format : \ - (ip)->i_d.di_aformat) -#define XFS_IFORK_FMT_SET(ip,w,n) \ - ((w) == XFS_DATA_FORK ? \ - ((ip)->i_d.di_format = (n)) : \ - ((ip)->i_d.di_aformat = (n))) -#define XFS_IFORK_NEXTENTS(ip,w) \ - ((w) == XFS_DATA_FORK ? \ - (ip)->i_d.di_nextents : \ - (ip)->i_d.di_anextents) -#define XFS_IFORK_NEXT_SET(ip,w,n) \ - ((w) == XFS_DATA_FORK ? \ - ((ip)->i_d.di_nextents = (n)) : \ - ((ip)->i_d.di_anextents = (n))) #ifdef __KERNEL__ @@ -493,6 +509,7 @@ void xfs_ihash_init(struct xfs_mount *); void xfs_ihash_free(struct xfs_mount *); xfs_inode_t *xfs_inode_incore(struct xfs_mount *, xfs_ino_t, struct xfs_trans *); +void xfs_inode_lock_init(xfs_inode_t *, bhv_vnode_t *); int xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, uint, uint, xfs_inode_t **, xfs_daddr_t); void xfs_iput(xfs_inode_t *, uint); @@ -528,7 +545,7 @@ void xfs_dinode_to_disk(struct xfs_dinode_core *, struct xfs_icdinode *); uint xfs_ip2xflags(struct xfs_inode *); -uint xfs_dic2xflags(struct xfs_dinode *); +uint xfs_dic2xflags(struct xfs_dinode_core *); int xfs_ifree(struct xfs_trans *, xfs_inode_t *, struct xfs_bmap_free *); int xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t); @@ -550,12 +567,13 @@ void xfs_iunpin(xfs_inode_t *); int xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_t *, int); int xfs_iflush(xfs_inode_t *, uint); void xfs_iflush_all(struct xfs_mount *); +int xfs_iaccess(xfs_inode_t *, mode_t, cred_t *); +uint xfs_iroundup(uint); void xfs_ichgtime(xfs_inode_t *, int); xfs_fsize_t xfs_file_last_byte(xfs_inode_t *); void xfs_lock_inodes(xfs_inode_t **, int, int, uint); void xfs_synchronize_atime(xfs_inode_t *); -void xfs_mark_inode_dirty_sync(xfs_inode_t *); xfs_bmbt_rec_host_t *xfs_iext_get_ext(xfs_ifork_t *, xfs_extnum_t); void xfs_iext_insert(xfs_ifork_t *, xfs_extnum_t, xfs_extnum_t, diff --git a/trunk/fs/xfs/xfs_inode_item.c b/trunk/fs/xfs/xfs_inode_item.c index 034ca7202295..565d470a6b4a 100644 --- a/trunk/fs/xfs/xfs_inode_item.c +++ b/trunk/fs/xfs/xfs_inode_item.c @@ -274,11 +274,6 @@ xfs_inode_item_format( */ xfs_synchronize_atime(ip); - /* - * make sure the linux inode is dirty - */ - xfs_mark_inode_dirty_sync(ip); - vecp->i_addr = (xfs_caddr_t)&ip->i_d; vecp->i_len = sizeof(xfs_dinode_core_t); XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_ICORE); @@ -620,7 +615,7 @@ xfs_inode_item_trylock( return XFS_ITEM_PUSHBUF; } else { /* - * We hold the AIL lock, so we must specify the + * We hold the AIL_LOCK, so we must specify the * NONOTIFY flag so that we won't double trip. */ xfs_iunlock(ip, XFS_ILOCK_SHARED|XFS_IUNLOCK_NONOTIFY); @@ -754,7 +749,7 @@ xfs_inode_item_committed( * marked delayed write. If that's the case, we'll initiate a bawrite on that * buffer to expedite the process. * - * We aren't holding the AIL lock (or the flush lock) when this gets called, + * We aren't holding the AIL_LOCK (or the flush lock) when this gets called, * so it is inherently race-y. */ STATIC void @@ -797,7 +792,7 @@ xfs_inode_item_pushbuf( if (XFS_BUF_ISDELAYWRITE(bp)) { /* * We were racing with iflush because we don't hold - * the AIL lock or the flush lock. However, at this point, + * the AIL_LOCK or the flush lock. However, at this point, * we have the buffer, and we know that it's dirty. * So, it's possible that iflush raced with us, and * this item is already taken off the AIL. @@ -973,6 +968,7 @@ xfs_iflush_done( xfs_inode_log_item_t *iip) { xfs_inode_t *ip; + SPLDECL(s); ip = iip->ili_inode; @@ -987,15 +983,15 @@ xfs_iflush_done( */ if (iip->ili_logged && (iip->ili_item.li_lsn == iip->ili_flush_lsn)) { - spin_lock(&ip->i_mount->m_ail_lock); + AIL_LOCK(ip->i_mount, s); if (iip->ili_item.li_lsn == iip->ili_flush_lsn) { /* * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(ip->i_mount, - (xfs_log_item_t*)iip); + (xfs_log_item_t*)iip, s); } else { - spin_unlock(&ip->i_mount->m_ail_lock); + AIL_UNLOCK(ip->i_mount, s); } } @@ -1029,19 +1025,21 @@ xfs_iflush_abort( { xfs_inode_log_item_t *iip; xfs_mount_t *mp; + SPLDECL(s); iip = ip->i_itemp; mp = ip->i_mount; if (iip) { if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp, s); if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { /* * xfs_trans_delete_ail() drops the AIL lock. */ - xfs_trans_delete_ail(mp, (xfs_log_item_t *)iip); + xfs_trans_delete_ail(mp, (xfs_log_item_t *)iip, + s); } else - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); } iip->ili_logged = 0; /* diff --git a/trunk/fs/xfs/xfs_iocore.c b/trunk/fs/xfs/xfs_iocore.c new file mode 100644 index 000000000000..b27b5d5be841 --- /dev/null +++ b/trunk/fs/xfs/xfs_iocore.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would 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 the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_types.h" +#include "xfs_bit.h" +#include "xfs_log.h" +#include "xfs_inum.h" +#include "xfs_trans.h" +#include "xfs_sb.h" +#include "xfs_ag.h" +#include "xfs_dir2.h" +#include "xfs_dfrag.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_alloc_btree.h" +#include "xfs_ialloc_btree.h" +#include "xfs_dir2_sf.h" +#include "xfs_attr_sf.h" +#include "xfs_dinode.h" +#include "xfs_inode.h" +#include "xfs_inode_item.h" +#include "xfs_itable.h" +#include "xfs_btree.h" +#include "xfs_alloc.h" +#include "xfs_ialloc.h" +#include "xfs_bmap.h" +#include "xfs_error.h" +#include "xfs_rw.h" +#include "xfs_quota.h" +#include "xfs_trans_space.h" +#include "xfs_iomap.h" + + +STATIC xfs_fsize_t +xfs_size_fn( + xfs_inode_t *ip) +{ + return XFS_ISIZE(ip); +} + +STATIC int +xfs_ioinit( + struct xfs_mount *mp, + struct xfs_mount_args *mntargs, + int flags) +{ + return xfs_mountfs(mp, flags); +} + +xfs_ioops_t xfs_iocore_xfs = { + .xfs_ioinit = (xfs_ioinit_t) xfs_ioinit, + .xfs_bmapi_func = (xfs_bmapi_t) xfs_bmapi, + .xfs_bunmapi_func = (xfs_bunmapi_t) xfs_bunmapi, + .xfs_bmap_eof_func = (xfs_bmap_eof_t) xfs_bmap_eof, + .xfs_iomap_write_direct = + (xfs_iomap_write_direct_t) xfs_iomap_write_direct, + .xfs_iomap_write_delay = + (xfs_iomap_write_delay_t) xfs_iomap_write_delay, + .xfs_iomap_write_allocate = + (xfs_iomap_write_allocate_t) xfs_iomap_write_allocate, + .xfs_iomap_write_unwritten = + (xfs_iomap_write_unwritten_t) xfs_iomap_write_unwritten, + .xfs_ilock = (xfs_lock_t) xfs_ilock, + .xfs_lck_map_shared = (xfs_lck_map_shared_t) xfs_ilock_map_shared, + .xfs_ilock_demote = (xfs_lock_demote_t) xfs_ilock_demote, + .xfs_ilock_nowait = (xfs_lock_nowait_t) xfs_ilock_nowait, + .xfs_unlock = (xfs_unlk_t) xfs_iunlock, + .xfs_size_func = (xfs_size_t) xfs_size_fn, + .xfs_iodone = (xfs_iodone_t) fs_noerr, + .xfs_swap_extents_func = (xfs_swap_extents_t) xfs_swap_extents, +}; + +void +xfs_iocore_inode_reinit( + xfs_inode_t *ip) +{ + xfs_iocore_t *io = &ip->i_iocore; + + io->io_flags = 0; + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) + io->io_flags |= XFS_IOCORE_RT; + io->io_dmevmask = ip->i_d.di_dmevmask; + io->io_dmstate = ip->i_d.di_dmstate; +} + +void +xfs_iocore_inode_init( + xfs_inode_t *ip) +{ + xfs_iocore_t *io = &ip->i_iocore; + xfs_mount_t *mp = ip->i_mount; + + io->io_mount = mp; +#ifdef DEBUG + io->io_lock = &ip->i_lock; + io->io_iolock = &ip->i_iolock; +#endif + + io->io_obj = (void *)ip; + + xfs_iocore_inode_reinit(ip); +} diff --git a/trunk/fs/xfs/xfs_iomap.c b/trunk/fs/xfs/xfs_iomap.c index fde37f87d52f..72786e356d56 100644 --- a/trunk/fs/xfs/xfs_iomap.c +++ b/trunk/fs/xfs/xfs_iomap.c @@ -53,10 +53,12 @@ void xfs_iomap_enter_trace( int tag, - xfs_inode_t *ip, + xfs_iocore_t *io, xfs_off_t offset, ssize_t count) { + xfs_inode_t *ip = XFS_IO_INODE(io); + if (!ip->i_rwtrace) return; @@ -68,8 +70,8 @@ xfs_iomap_enter_trace( (void *)((unsigned long)((offset >> 32) & 0xffffffff)), (void *)((unsigned long)(offset & 0xffffffff)), (void *)((unsigned long)count), - (void *)((unsigned long)((ip->i_new_size >> 32) & 0xffffffff)), - (void *)((unsigned long)(ip->i_new_size & 0xffffffff)), + (void *)((unsigned long)((io->io_new_size >> 32) & 0xffffffff)), + (void *)((unsigned long)(io->io_new_size & 0xffffffff)), (void *)((unsigned long)current_pid()), (void *)NULL, (void *)NULL, @@ -82,13 +84,15 @@ xfs_iomap_enter_trace( void xfs_iomap_map_trace( int tag, - xfs_inode_t *ip, + xfs_iocore_t *io, xfs_off_t offset, ssize_t count, xfs_iomap_t *iomapp, xfs_bmbt_irec_t *imapp, int flags) { + xfs_inode_t *ip = XFS_IO_INODE(io); + if (!ip->i_rwtrace) return; @@ -122,7 +126,7 @@ xfs_iomap_map_trace( STATIC int xfs_imap_to_bmap( - xfs_inode_t *ip, + xfs_iocore_t *io, xfs_off_t offset, xfs_bmbt_irec_t *imap, xfs_iomap_t *iomapp, @@ -130,10 +134,11 @@ xfs_imap_to_bmap( int iomaps, /* Number of iomap entries */ int flags) { - xfs_mount_t *mp = ip->i_mount; + xfs_mount_t *mp; int pbm; xfs_fsblock_t start_block; + mp = io->io_mount; for (pbm = 0; imaps && pbm < iomaps; imaps--, iomapp++, imap++, pbm++) { iomapp->iomap_offset = XFS_FSB_TO_B(mp, imap->br_startoff); @@ -141,7 +146,7 @@ xfs_imap_to_bmap( iomapp->iomap_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount); iomapp->iomap_flags = flags; - if (XFS_IS_REALTIME_INODE(ip)) { + if (io->io_flags & XFS_IOCORE_RT) { iomapp->iomap_flags |= IOMAP_REALTIME; iomapp->iomap_target = mp->m_rtdev_targp; } else { @@ -155,7 +160,7 @@ xfs_imap_to_bmap( iomapp->iomap_bn = IOMAP_DADDR_NULL; iomapp->iomap_flags |= IOMAP_DELAY; } else { - iomapp->iomap_bn = XFS_FSB_TO_DB(ip, start_block); + iomapp->iomap_bn = XFS_FSB_TO_DB_IO(io, start_block); if (ISUNWRITTEN(imap)) iomapp->iomap_flags |= IOMAP_UNWRITTEN; } @@ -167,14 +172,14 @@ xfs_imap_to_bmap( int xfs_iomap( - xfs_inode_t *ip, + xfs_iocore_t *io, xfs_off_t offset, ssize_t count, int flags, xfs_iomap_t *iomapp, int *niomaps) { - xfs_mount_t *mp = ip->i_mount; + xfs_mount_t *mp = io->io_mount; xfs_fileoff_t offset_fsb, end_fsb; int error = 0; int lockmode = 0; @@ -183,37 +188,45 @@ xfs_iomap( int bmapi_flags = 0; int iomap_flags = 0; - ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG); - if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); - switch (flags & (BMAPI_READ | BMAPI_WRITE | BMAPI_ALLOCATE)) { + switch (flags & + (BMAPI_READ | BMAPI_WRITE | BMAPI_ALLOCATE | + BMAPI_UNWRITTEN | BMAPI_DEVICE)) { case BMAPI_READ: - xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, ip, offset, count); - lockmode = xfs_ilock_map_shared(ip); + xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, io, offset, count); + lockmode = XFS_LCK_MAP_SHARED(mp, io); bmapi_flags = XFS_BMAPI_ENTIRE; break; case BMAPI_WRITE: - xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, ip, offset, count); + xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, io, offset, count); lockmode = XFS_ILOCK_EXCL|XFS_EXTSIZE_WR; if (flags & BMAPI_IGNSTATE) bmapi_flags |= XFS_BMAPI_IGSTATE|XFS_BMAPI_ENTIRE; - xfs_ilock(ip, lockmode); + XFS_ILOCK(mp, io, lockmode); break; case BMAPI_ALLOCATE: - xfs_iomap_enter_trace(XFS_IOMAP_ALLOC_ENTER, ip, offset, count); + xfs_iomap_enter_trace(XFS_IOMAP_ALLOC_ENTER, io, offset, count); lockmode = XFS_ILOCK_SHARED|XFS_EXTSIZE_RD; bmapi_flags = XFS_BMAPI_ENTIRE; - /* Attempt non-blocking lock */ if (flags & BMAPI_TRYLOCK) { - if (!xfs_ilock_nowait(ip, lockmode)) + if (!XFS_ILOCK_NOWAIT(mp, io, lockmode)) return XFS_ERROR(EAGAIN); } else { - xfs_ilock(ip, lockmode); + XFS_ILOCK(mp, io, lockmode); } break; + case BMAPI_UNWRITTEN: + goto phase2; + case BMAPI_DEVICE: + lockmode = XFS_LCK_MAP_SHARED(mp, io); + iomapp->iomap_target = io->io_flags & XFS_IOCORE_RT ? + mp->m_rtdev_targp : mp->m_ddev_targp; + error = 0; + *niomaps = 1; + goto out; default: BUG(); } @@ -224,7 +237,7 @@ xfs_iomap( end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); offset_fsb = XFS_B_TO_FSBT(mp, offset); - error = xfs_bmapi(NULL, ip, offset_fsb, + error = XFS_BMAPI(mp, NULL, io, offset_fsb, (xfs_filblks_t)(end_fsb - offset_fsb), bmapi_flags, NULL, 0, &imap, &nimaps, NULL, NULL); @@ -232,48 +245,54 @@ xfs_iomap( if (error) goto out; - switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE)) { +phase2: + switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE|BMAPI_UNWRITTEN)) { case BMAPI_WRITE: /* If we found an extent, return it */ if (nimaps && (imap.br_startblock != HOLESTARTBLOCK) && (imap.br_startblock != DELAYSTARTBLOCK)) { - xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, ip, + xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io, offset, count, iomapp, &imap, flags); break; } if (flags & (BMAPI_DIRECT|BMAPI_MMAP)) { - error = xfs_iomap_write_direct(ip, offset, count, flags, - &imap, &nimaps, nimaps); + error = XFS_IOMAP_WRITE_DIRECT(mp, io, offset, + count, flags, &imap, &nimaps, nimaps); } else { - error = xfs_iomap_write_delay(ip, offset, count, flags, - &imap, &nimaps); + error = XFS_IOMAP_WRITE_DELAY(mp, io, offset, count, + flags, &imap, &nimaps); } if (!error) { - xfs_iomap_map_trace(XFS_IOMAP_ALLOC_MAP, ip, + xfs_iomap_map_trace(XFS_IOMAP_ALLOC_MAP, io, offset, count, iomapp, &imap, flags); } iomap_flags = IOMAP_NEW; break; case BMAPI_ALLOCATE: /* If we found an extent, return it */ - xfs_iunlock(ip, lockmode); + XFS_IUNLOCK(mp, io, lockmode); lockmode = 0; if (nimaps && !ISNULLSTARTBLOCK(imap.br_startblock)) { - xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, ip, + xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io, offset, count, iomapp, &imap, flags); break; } - error = xfs_iomap_write_allocate(ip, offset, count, + error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, offset, count, &imap, &nimaps); break; + case BMAPI_UNWRITTEN: + lockmode = 0; + error = XFS_IOMAP_WRITE_UNWRITTEN(mp, io, offset, count); + nimaps = 0; + break; } if (nimaps) { - *niomaps = xfs_imap_to_bmap(ip, offset, &imap, + *niomaps = xfs_imap_to_bmap(io, offset, &imap, iomapp, nimaps, *niomaps, iomap_flags); } else if (niomaps) { *niomaps = 0; @@ -281,15 +300,14 @@ xfs_iomap( out: if (lockmode) - xfs_iunlock(ip, lockmode); + XFS_IUNLOCK(mp, io, lockmode); return XFS_ERROR(error); } - STATIC int xfs_iomap_eof_align_last_fsb( xfs_mount_t *mp, - xfs_inode_t *ip, + xfs_iocore_t *io, xfs_fsize_t isize, xfs_extlen_t extsize, xfs_fileoff_t *last_fsb) @@ -298,7 +316,7 @@ xfs_iomap_eof_align_last_fsb( xfs_extlen_t align; int eof, error; - if (XFS_IS_REALTIME_INODE(ip)) + if (io->io_flags & XFS_IOCORE_RT) ; /* * If mounted with the "-o swalloc" option, roundup the allocation @@ -329,7 +347,7 @@ xfs_iomap_eof_align_last_fsb( } if (new_last_fsb) { - error = xfs_bmap_eof(ip, new_last_fsb, XFS_DATA_FORK, &eof); + error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof); if (error) return error; if (eof) @@ -398,6 +416,7 @@ xfs_iomap_write_direct( int found) { xfs_mount_t *mp = ip->i_mount; + xfs_iocore_t *io = &ip->i_iocore; xfs_fileoff_t offset_fsb; xfs_fileoff_t last_fsb; xfs_filblks_t count_fsb, resaligned; @@ -427,13 +446,13 @@ xfs_iomap_write_direct( extsz = xfs_get_extsz_hint(ip); isize = ip->i_size; - if (ip->i_new_size > isize) - isize = ip->i_new_size; + if (io->io_new_size > isize) + isize = io->io_new_size; offset_fsb = XFS_B_TO_FSBT(mp, offset); last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); if ((offset + count) > isize) { - error = xfs_iomap_eof_align_last_fsb(mp, ip, isize, extsz, + error = xfs_iomap_eof_align_last_fsb(mp, io, isize, extsz, &last_fsb); if (error) goto error_out; @@ -500,7 +519,7 @@ xfs_iomap_write_direct( */ XFS_BMAP_INIT(&free_list, &firstfsb); nimaps = 1; - error = xfs_bmapi(tp, ip, offset_fsb, count_fsb, bmapi_flag, + error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb, bmapi_flag, &firstfsb, 0, &imap, &nimaps, &free_list, NULL); if (error) goto error0; @@ -523,8 +542,7 @@ xfs_iomap_write_direct( goto error_out; } - if (unlikely(!imap.br_startblock && - !(XFS_IS_REALTIME_INODE(ip)))) { + if (unlikely(!imap.br_startblock && !(io->io_flags & XFS_IOCORE_RT))) { error = xfs_cmn_err_fsblock_zero(ip, &imap); goto error_out; } @@ -559,7 +577,7 @@ xfs_iomap_write_direct( STATIC int xfs_iomap_eof_want_preallocate( xfs_mount_t *mp, - xfs_inode_t *ip, + xfs_iocore_t *io, xfs_fsize_t isize, xfs_off_t offset, size_t count, @@ -586,7 +604,7 @@ xfs_iomap_eof_want_preallocate( while (count_fsb > 0) { imaps = nimaps; firstblock = NULLFSBLOCK; - error = xfs_bmapi(NULL, ip, start_fsb, count_fsb, 0, + error = XFS_BMAPI(mp, NULL, io, start_fsb, count_fsb, 0, &firstblock, 0, imap, &imaps, NULL, NULL); if (error) return error; @@ -612,6 +630,7 @@ xfs_iomap_write_delay( int *nmaps) { xfs_mount_t *mp = ip->i_mount; + xfs_iocore_t *io = &ip->i_iocore; xfs_fileoff_t offset_fsb; xfs_fileoff_t last_fsb; xfs_off_t aligned_offset; @@ -639,10 +658,10 @@ xfs_iomap_write_delay( retry: isize = ip->i_size; - if (ip->i_new_size > isize) - isize = ip->i_new_size; + if (io->io_new_size > isize) + isize = io->io_new_size; - error = xfs_iomap_eof_want_preallocate(mp, ip, isize, offset, count, + error = xfs_iomap_eof_want_preallocate(mp, io, isize, offset, count, ioflag, imap, XFS_WRITE_IMAPS, &prealloc); if (error) return error; @@ -656,7 +675,7 @@ xfs_iomap_write_delay( } if (prealloc || extsz) { - error = xfs_iomap_eof_align_last_fsb(mp, ip, isize, extsz, + error = xfs_iomap_eof_align_last_fsb(mp, io, isize, extsz, &last_fsb); if (error) return error; @@ -664,7 +683,7 @@ xfs_iomap_write_delay( nimaps = XFS_WRITE_IMAPS; firstblock = NULLFSBLOCK; - error = xfs_bmapi(NULL, ip, offset_fsb, + error = XFS_BMAPI(mp, NULL, io, offset_fsb, (xfs_filblks_t)(last_fsb - offset_fsb), XFS_BMAPI_DELAY | XFS_BMAPI_WRITE | XFS_BMAPI_ENTIRE, &firstblock, 1, imap, @@ -678,7 +697,7 @@ xfs_iomap_write_delay( */ if (nimaps == 0) { xfs_iomap_enter_trace(XFS_IOMAP_WRITE_NOSPACE, - ip, offset, count); + io, offset, count); if (xfs_flush_space(ip, &fsynced, &ioflag)) return XFS_ERROR(ENOSPC); @@ -686,8 +705,7 @@ xfs_iomap_write_delay( goto retry; } - if (unlikely(!imap[0].br_startblock && - !(XFS_IS_REALTIME_INODE(ip)))) + if (unlikely(!imap[0].br_startblock && !(io->io_flags & XFS_IOCORE_RT))) return xfs_cmn_err_fsblock_zero(ip, &imap[0]); *ret_imap = imap[0]; @@ -702,9 +720,6 @@ xfs_iomap_write_delay( * the originating callers request. * * Called without a lock on the inode. - * - * We no longer bother to look at the incoming map - all we have to - * guarantee is that whatever we allocate fills the required range. */ int xfs_iomap_write_allocate( @@ -715,14 +730,15 @@ xfs_iomap_write_allocate( int *retmap) { xfs_mount_t *mp = ip->i_mount; + xfs_iocore_t *io = &ip->i_iocore; xfs_fileoff_t offset_fsb, last_block; xfs_fileoff_t end_fsb, map_start_fsb; xfs_fsblock_t first_block; xfs_bmap_free_t free_list; xfs_filblks_t count_fsb; - xfs_bmbt_irec_t imap; + xfs_bmbt_irec_t imap[XFS_STRAT_WRITE_IMAPS]; xfs_trans_t *tp; - int nimaps, committed; + int i, nimaps, committed; int error = 0; int nres; @@ -769,38 +785,13 @@ xfs_iomap_write_allocate( XFS_BMAP_INIT(&free_list, &first_block); + nimaps = XFS_STRAT_WRITE_IMAPS; /* - * it is possible that the extents have changed since - * we did the read call as we dropped the ilock for a - * while. We have to be careful about truncates or hole - * punchs here - we are not allowed to allocate - * non-delalloc blocks here. - * - * The only protection against truncation is the pages - * for the range we are being asked to convert are - * locked and hence a truncate will block on them - * first. - * - * As a result, if we go beyond the range we really - * need and hit an delalloc extent boundary followed by - * a hole while we have excess blocks in the map, we - * will fill the hole incorrectly and overrun the - * transaction reservation. - * - * Using a single map prevents this as we are forced to - * check each map we look for overlap with the desired - * range and abort as soon as we find it. Also, given - * that we only return a single map, having one beyond - * what we can return is probably a bit silly. - * - * We also need to check that we don't go beyond EOF; - * this is a truncate optimisation as a truncate sets - * the new file size before block on the pages we - * currently have locked under writeback. Because they - * are about to be tossed, we don't need to write them - * back.... + * Ensure we don't go beyond eof - it is possible + * the extents changed since we did the read call, + * we dropped the ilock in the interim. */ - nimaps = 1; + end_fsb = XFS_B_TO_FSB(mp, ip->i_size); xfs_bmap_last_offset(NULL, ip, &last_block, XFS_DATA_FORK); @@ -814,9 +805,9 @@ xfs_iomap_write_allocate( } /* Go get the actual blocks */ - error = xfs_bmapi(tp, ip, map_start_fsb, count_fsb, + error = XFS_BMAPI(mp, tp, io, map_start_fsb, count_fsb, XFS_BMAPI_WRITE, &first_block, 1, - &imap, &nimaps, &free_list, NULL); + imap, &nimaps, &free_list, NULL); if (error) goto trans_cancel; @@ -835,24 +826,27 @@ xfs_iomap_write_allocate( * See if we were able to allocate an extent that * covers at least part of the callers request */ - if (unlikely(!imap.br_startblock && - XFS_IS_REALTIME_INODE(ip))) - return xfs_cmn_err_fsblock_zero(ip, &imap); - if ((offset_fsb >= imap.br_startoff) && - (offset_fsb < (imap.br_startoff + - imap.br_blockcount))) { - *map = imap; - *retmap = 1; - XFS_STATS_INC(xs_xstrat_quick); - return 0; + for (i = 0; i < nimaps; i++) { + if (unlikely(!imap[i].br_startblock && + !(io->io_flags & XFS_IOCORE_RT))) + return xfs_cmn_err_fsblock_zero(ip, &imap[i]); + if ((offset_fsb >= imap[i].br_startoff) && + (offset_fsb < (imap[i].br_startoff + + imap[i].br_blockcount))) { + *map = imap[i]; + *retmap = 1; + XFS_STATS_INC(xs_xstrat_quick); + return 0; + } + count_fsb -= imap[i].br_blockcount; } - /* - * So far we have not mapped the requested part of the + /* So far we have not mapped the requested part of the * file, just surrounding data, try again. */ - count_fsb -= imap.br_blockcount; - map_start_fsb = imap.br_startoff + imap.br_blockcount; + nimaps--; + map_start_fsb = imap[nimaps].br_startoff + + imap[nimaps].br_blockcount; } trans_cancel: @@ -870,6 +864,7 @@ xfs_iomap_write_unwritten( size_t count) { xfs_mount_t *mp = ip->i_mount; + xfs_iocore_t *io = &ip->i_iocore; xfs_fileoff_t offset_fsb; xfs_filblks_t count_fsb; xfs_filblks_t numblks_fsb; @@ -882,7 +877,8 @@ xfs_iomap_write_unwritten( int committed; int error; - xfs_iomap_enter_trace(XFS_IOMAP_UNWRITTEN, ip, offset, count); + xfs_iomap_enter_trace(XFS_IOMAP_UNWRITTEN, + &ip->i_iocore, offset, count); offset_fsb = XFS_B_TO_FSBT(mp, offset); count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); @@ -916,7 +912,7 @@ xfs_iomap_write_unwritten( */ XFS_BMAP_INIT(&free_list, &firstfsb); nimaps = 1; - error = xfs_bmapi(tp, ip, offset_fsb, count_fsb, + error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb, XFS_BMAPI_WRITE|XFS_BMAPI_CONVERT, &firstfsb, 1, &imap, &nimaps, &free_list, NULL); if (error) @@ -932,7 +928,7 @@ xfs_iomap_write_unwritten( return XFS_ERROR(error); if (unlikely(!imap.br_startblock && - !(XFS_IS_REALTIME_INODE(ip)))) + !(io->io_flags & XFS_IOCORE_RT))) return xfs_cmn_err_fsblock_zero(ip, &imap); if ((numblks_fsb = imap.br_blockcount) == 0) { diff --git a/trunk/fs/xfs/xfs_iomap.h b/trunk/fs/xfs/xfs_iomap.h index ee1a0c134cc2..f5c09887fe93 100644 --- a/trunk/fs/xfs/xfs_iomap.h +++ b/trunk/fs/xfs/xfs_iomap.h @@ -36,12 +36,14 @@ typedef enum { BMAPI_READ = (1 << 0), /* read extents */ BMAPI_WRITE = (1 << 1), /* create extents */ BMAPI_ALLOCATE = (1 << 2), /* delayed allocate to real extents */ + BMAPI_UNWRITTEN = (1 << 3), /* unwritten extents to real extents */ /* modifiers */ BMAPI_IGNSTATE = (1 << 4), /* ignore unwritten state on read */ BMAPI_DIRECT = (1 << 5), /* direct instead of buffered write */ BMAPI_MMAP = (1 << 6), /* allocate for mmap write */ BMAPI_SYNC = (1 << 7), /* sync write to flush delalloc space */ BMAPI_TRYLOCK = (1 << 8), /* non-blocking request */ + BMAPI_DEVICE = (1 << 9), /* we only want to know the device */ } bmapi_flags_t; @@ -71,10 +73,11 @@ typedef struct xfs_iomap { iomap_flags_t iomap_flags; } xfs_iomap_t; +struct xfs_iocore; struct xfs_inode; struct xfs_bmbt_irec; -extern int xfs_iomap(struct xfs_inode *, xfs_off_t, ssize_t, int, +extern int xfs_iomap(struct xfs_iocore *, xfs_off_t, ssize_t, int, struct xfs_iomap *, int *); extern int xfs_iomap_write_direct(struct xfs_inode *, xfs_off_t, size_t, int, struct xfs_bmbt_irec *, int *, int); diff --git a/trunk/fs/xfs/xfs_itable.c b/trunk/fs/xfs/xfs_itable.c index 658aab6b1bbf..9fc4c2886529 100644 --- a/trunk/fs/xfs/xfs_itable.c +++ b/trunk/fs/xfs/xfs_itable.c @@ -170,7 +170,7 @@ xfs_bulkstat_one_dinode( buf->bs_mtime.tv_nsec = be32_to_cpu(dic->di_mtime.t_nsec); buf->bs_ctime.tv_sec = be32_to_cpu(dic->di_ctime.t_sec); buf->bs_ctime.tv_nsec = be32_to_cpu(dic->di_ctime.t_nsec); - buf->bs_xflags = xfs_dic2xflags(dip); + buf->bs_xflags = xfs_dic2xflags(dic); buf->bs_extsize = be32_to_cpu(dic->di_extsize) << mp->m_sb.sb_blocklog; buf->bs_extents = be32_to_cpu(dic->di_nextents); buf->bs_gen = be32_to_cpu(dic->di_gen); @@ -291,7 +291,7 @@ xfs_bulkstat_use_dinode( dip = (xfs_dinode_t *) xfs_buf_offset(bp, clustidx << mp->m_sb.sb_inodelog); /* - * Check the buffer containing the on-disk inode for di_mode == 0. + * Check the buffer containing the on-disk inode for di_nlink == 0. * This is to prevent xfs_bulkstat from picking up just reclaimed * inodes that have their in-core state initialized but not flushed * to disk yet. This is a temporary hack that would require a proper @@ -299,7 +299,7 @@ xfs_bulkstat_use_dinode( */ if (be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC || !XFS_DINODE_GOOD_VERSION(dip->di_core.di_version) || - !dip->di_core.di_mode) + !dip->di_core.di_nlink) return 0; if (flags & BULKSTAT_FG_QUICK) { *dipp = dip; @@ -307,7 +307,7 @@ xfs_bulkstat_use_dinode( } /* BULKSTAT_FG_INLINE: if attr fork is local, or not there, use it */ aformat = dip->di_core.di_aformat; - if ((XFS_DFORK_Q(dip) == 0) || + if ((XFS_CFORK_Q(&dip->di_core) == 0) || (aformat == XFS_DINODE_FMT_LOCAL) || (aformat == XFS_DINODE_FMT_EXTENTS && !dip->di_core.di_anextents)) { *dipp = dip; @@ -399,7 +399,7 @@ xfs_bulkstat( (XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog); nimask = ~(nicluster - 1); nbcluster = nicluster >> mp->m_sb.sb_inopblog; - irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4, + irbuf = kmem_zalloc_greedy(&irbsize, NBPC, NBPC * 4, KM_SLEEP | KM_MAYFAIL | KM_LARGE); nirbuf = irbsize / sizeof(*irbuf); @@ -830,7 +830,7 @@ xfs_inumbers( agino = XFS_INO_TO_AGINO(mp, ino); left = *count; *count = 0; - bcount = MIN(left, (int)(PAGE_SIZE / sizeof(*buffer))); + bcount = MIN(left, (int)(NBPP / sizeof(*buffer))); buffer = kmem_alloc(bcount * sizeof(*buffer), KM_SLEEP); error = bufidx = 0; cur = NULL; diff --git a/trunk/fs/xfs/xfs_log.c b/trunk/fs/xfs/xfs_log.c index b3ac3805d3c4..77c12715a7d0 100644 --- a/trunk/fs/xfs/xfs_log.c +++ b/trunk/fs/xfs/xfs_log.c @@ -399,10 +399,10 @@ xfs_log_notify(xfs_mount_t *mp, /* mount of partition */ { xlog_t *log = mp->m_log; xlog_in_core_t *iclog = (xlog_in_core_t *)iclog_hndl; - int abortflg; + int abortflg, spl; cb->cb_next = NULL; - spin_lock(&log->l_icloglock); + spl = LOG_LOCK(log); abortflg = (iclog->ic_state & XLOG_STATE_IOERROR); if (!abortflg) { ASSERT_ALWAYS((iclog->ic_state == XLOG_STATE_ACTIVE) || @@ -411,7 +411,7 @@ xfs_log_notify(xfs_mount_t *mp, /* mount of partition */ *(iclog->ic_callback_tail) = cb; iclog->ic_callback_tail = &(cb->cb_next); } - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, spl); return abortflg; } /* xfs_log_notify */ @@ -498,14 +498,11 @@ xfs_log_reserve(xfs_mount_t *mp, * Return error or zero. */ int -xfs_log_mount( - xfs_mount_t *mp, - xfs_buftarg_t *log_target, - xfs_daddr_t blk_offset, - int num_bblks) +xfs_log_mount(xfs_mount_t *mp, + xfs_buftarg_t *log_target, + xfs_daddr_t blk_offset, + int num_bblks) { - int error; - if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) cmn_err(CE_NOTE, "XFS mounting filesystem %s", mp->m_fsname); else { @@ -517,22 +514,12 @@ xfs_log_mount( mp->m_log = xlog_alloc_log(mp, log_target, blk_offset, num_bblks); - /* - * Initialize the AIL now we have a log. - */ - spin_lock_init(&mp->m_ail_lock); - error = xfs_trans_ail_init(mp); - if (error) { - cmn_err(CE_WARN, "XFS: AIL initialisation failed: error %d", error); - goto error; - } - /* * skip log recovery on a norecovery mount. pretend it all * just worked. */ if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) { - int readonly = (mp->m_flags & XFS_MOUNT_RDONLY); + int error, readonly = (mp->m_flags & XFS_MOUNT_RDONLY); if (readonly) mp->m_flags &= ~XFS_MOUNT_RDONLY; @@ -543,7 +530,8 @@ xfs_log_mount( mp->m_flags |= XFS_MOUNT_RDONLY; if (error) { cmn_err(CE_WARN, "XFS: log mount/recovery failed: error %d", error); - goto error; + xlog_dealloc_log(mp->m_log); + return error; } } @@ -552,9 +540,6 @@ xfs_log_mount( /* End mounting message in xfs_log_mount_finish */ return 0; -error: - xfs_log_unmount_dealloc(mp); - return error; } /* xfs_log_mount */ /* @@ -621,6 +606,7 @@ xfs_log_unmount_write(xfs_mount_t *mp) xfs_log_ticket_t tic = NULL; xfs_lsn_t lsn; int error; + SPLDECL(s); /* the data section must be 32 bit size aligned */ struct { @@ -673,24 +659,24 @@ xfs_log_unmount_write(xfs_mount_t *mp) } - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); iclog = log->l_iclog; iclog->ic_refcnt++; - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); xlog_state_want_sync(log, iclog); (void) xlog_state_release_iclog(log, iclog); - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); if (!(iclog->ic_state == XLOG_STATE_ACTIVE || iclog->ic_state == XLOG_STATE_DIRTY)) { if (!XLOG_FORCED_SHUTDOWN(log)) { sv_wait(&iclog->ic_forcesema, PMEM, &log->l_icloglock, s); } else { - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); } } else { - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); } if (tic) { xlog_trace_loggrant(log, tic, "unmount rec"); @@ -711,15 +697,15 @@ xfs_log_unmount_write(xfs_mount_t *mp) * a file system that went into forced_shutdown as * the result of an unmount.. */ - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); iclog = log->l_iclog; iclog->ic_refcnt++; - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); xlog_state_want_sync(log, iclog); (void) xlog_state_release_iclog(log, iclog); - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); if ( ! ( iclog->ic_state == XLOG_STATE_ACTIVE || iclog->ic_state == XLOG_STATE_DIRTY @@ -728,7 +714,7 @@ xfs_log_unmount_write(xfs_mount_t *mp) sv_wait(&iclog->ic_forcesema, PMEM, &log->l_icloglock, s); } else { - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); } } @@ -737,14 +723,10 @@ xfs_log_unmount_write(xfs_mount_t *mp) /* * Deallocate log structures for unmount/relocation. - * - * We need to stop the aild from running before we destroy - * and deallocate the log as the aild references the log. */ void xfs_log_unmount_dealloc(xfs_mount_t *mp) { - xfs_trans_ail_destroy(mp); xlog_dealloc_log(mp->m_log); } @@ -780,18 +762,20 @@ xfs_log_move_tail(xfs_mount_t *mp, xlog_ticket_t *tic; xlog_t *log = mp->m_log; int need_bytes, free_bytes, cycle, bytes; + SPLDECL(s); if (XLOG_FORCED_SHUTDOWN(log)) return; + ASSERT(!XFS_FORCED_SHUTDOWN(mp)); if (tail_lsn == 0) { /* needed since sync_lsn is 64 bits */ - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); tail_lsn = log->l_last_sync_lsn; - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); } - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); /* Also an invalid lsn. 1 implies that we aren't passing in a valid * tail_lsn. @@ -840,7 +824,7 @@ xfs_log_move_tail(xfs_mount_t *mp, tic = tic->t_next; } while (tic != log->l_reserve_headq); } - spin_unlock(&log->l_grant_lock); + GRANT_UNLOCK(log, s); } /* xfs_log_move_tail */ /* @@ -852,13 +836,14 @@ xfs_log_move_tail(xfs_mount_t *mp, int xfs_log_need_covered(xfs_mount_t *mp) { + SPLDECL(s); int needed = 0, gen; xlog_t *log = mp->m_log; if (!xfs_fs_writable(mp)) return 0; - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); if (((log->l_covered_state == XLOG_STATE_COVER_NEED) || (log->l_covered_state == XLOG_STATE_COVER_NEED2)) && !xfs_trans_first_ail(mp, &gen) @@ -871,7 +856,7 @@ xfs_log_need_covered(xfs_mount_t *mp) } needed = 1; } - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); return needed; } @@ -896,16 +881,17 @@ xfs_lsn_t xlog_assign_tail_lsn(xfs_mount_t *mp) { xfs_lsn_t tail_lsn; + SPLDECL(s); xlog_t *log = mp->m_log; tail_lsn = xfs_trans_tail_ail(mp); - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); if (tail_lsn != 0) { log->l_tail_lsn = tail_lsn; } else { tail_lsn = log->l_tail_lsn = log->l_last_sync_lsn; } - spin_unlock(&log->l_grant_lock); + GRANT_UNLOCK(log, s); return tail_lsn; } /* xlog_assign_tail_lsn */ @@ -925,7 +911,7 @@ xlog_assign_tail_lsn(xfs_mount_t *mp) * the tail. The details of this case are described below, but the end * result is that we return the size of the log as the amount of space left. */ -STATIC int +int xlog_space_left(xlog_t *log, int cycle, int bytes) { int free_bytes; @@ -1179,7 +1165,7 @@ xlog_alloc_log(xfs_mount_t *mp, log->l_flags |= XLOG_ACTIVE_RECOVERY; log->l_prev_block = -1; - log->l_tail_lsn = xlog_assign_lsn(1, 0); + ASSIGN_ANY_LSN_HOST(log->l_tail_lsn, 1, 0); /* log->l_tail_lsn = 0x100000000LL; cycle = 1; current block = 0 */ log->l_last_sync_lsn = log->l_tail_lsn; log->l_curr_cycle = 1; /* 0 is bad since this is initial value */ @@ -1207,8 +1193,8 @@ xlog_alloc_log(xfs_mount_t *mp, ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); log->l_xbuf = bp; - spin_lock_init(&log->l_icloglock); - spin_lock_init(&log->l_grant_lock); + spinlock_init(&log->l_icloglock, "iclog"); + spinlock_init(&log->l_grant_lock, "grhead_iclog"); initnsema(&log->l_flushsema, 0, "ic-flush"); xlog_state_ticket_alloc(log); /* wait until after icloglock inited */ @@ -1245,12 +1231,12 @@ xlog_alloc_log(xfs_mount_t *mp, head = &iclog->ic_header; memset(head, 0, sizeof(xlog_rec_header_t)); - head->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM); - head->h_version = cpu_to_be32( + INT_SET(head->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM); + INT_SET(head->h_version, ARCH_CONVERT, XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? 2 : 1); - head->h_size = cpu_to_be32(log->l_iclog_size); + INT_SET(head->h_size, ARCH_CONVERT, log->l_iclog_size); /* new fields */ - head->h_fmt = cpu_to_be32(XLOG_FMT); + INT_SET(head->h_fmt, ARCH_CONVERT, XLOG_FMT); memcpy(&head->h_fs_uuid, &mp->m_sb.sb_uuid, sizeof(uuid_t)); @@ -1307,7 +1293,7 @@ xlog_commit_record(xfs_mount_t *mp, * pushes on an lsn which is further along in the log once we reach the high * water mark. In this manner, we would be creating a low water mark. */ -STATIC void +void xlog_grant_push_ail(xfs_mount_t *mp, int need_bytes) { @@ -1319,10 +1305,11 @@ xlog_grant_push_ail(xfs_mount_t *mp, int threshold_block; /* block in lsn we'd like to be at */ int threshold_cycle; /* lsn cycle we'd like to be at */ int free_threshold; + SPLDECL(s); ASSERT(BTOBB(need_bytes) < log->l_logBBsize); - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); free_bytes = xlog_space_left(log, log->l_grant_reserve_cycle, log->l_grant_reserve_bytes); @@ -1344,7 +1331,8 @@ xlog_grant_push_ail(xfs_mount_t *mp, threshold_block -= log->l_logBBsize; threshold_cycle += 1; } - threshold_lsn = xlog_assign_lsn(threshold_cycle, threshold_block); + ASSIGN_ANY_LSN_HOST(threshold_lsn, threshold_cycle, + threshold_block); /* Don't pass in an lsn greater than the lsn of the last * log record known to be on disk. @@ -1352,7 +1340,7 @@ xlog_grant_push_ail(xfs_mount_t *mp, if (XFS_LSN_CMP(threshold_lsn, log->l_last_sync_lsn) > 0) threshold_lsn = log->l_last_sync_lsn; } - spin_unlock(&log->l_grant_lock); + GRANT_UNLOCK(log, s); /* * Get the transaction layer to kick the dirty buffers out to @@ -1390,18 +1378,19 @@ xlog_grant_push_ail(xfs_mount_t *mp, * is added immediately before calling bwrite(). */ -STATIC int +int xlog_sync(xlog_t *log, xlog_in_core_t *iclog) { xfs_caddr_t dptr; /* pointer to byte sized element */ xfs_buf_t *bp; - int i; + int i, ops; uint count; /* byte count of bwrite */ uint count_init; /* initial count before roundup */ int roundoff; /* roundoff to BB or stripe */ int split = 0; /* split write into two regions */ int error; + SPLDECL(s); int v2 = XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb); XFS_STATS_INC(xs_log_writes); @@ -1426,26 +1415,30 @@ xlog_sync(xlog_t *log, roundoff < BBTOB(1))); /* move grant heads by roundoff in sync */ - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); xlog_grant_add_space(log, roundoff); - spin_unlock(&log->l_grant_lock); + GRANT_UNLOCK(log, s); /* put cycle number in every block */ xlog_pack_data(log, iclog, roundoff); /* real byte length */ if (v2) { - iclog->ic_header.h_len = - cpu_to_be32(iclog->ic_offset + roundoff); + INT_SET(iclog->ic_header.h_len, + ARCH_CONVERT, + iclog->ic_offset + roundoff); } else { - iclog->ic_header.h_len = - cpu_to_be32(iclog->ic_offset); + INT_SET(iclog->ic_header.h_len, ARCH_CONVERT, iclog->ic_offset); } + /* put ops count in correct order */ + ops = iclog->ic_header.h_num_logops; + INT_SET(iclog->ic_header.h_num_logops, ARCH_CONVERT, ops); + bp = iclog->ic_bp; ASSERT(XFS_BUF_FSPRIVATE2(bp, unsigned long) == (unsigned long)1); XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)2); - XFS_BUF_SET_ADDR(bp, BLOCK_LSN(be64_to_cpu(iclog->ic_header.h_lsn))); + XFS_BUF_SET_ADDR(bp, BLOCK_LSN(INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT))); XFS_STATS_ADD(xs_log_blocks, BTOBB(count)); @@ -1508,10 +1501,10 @@ xlog_sync(xlog_t *log, * a new cycle. Watch out for the header magic number * case, though. */ - for (i = 0; i < split; i += BBSIZE) { - be32_add((__be32 *)dptr, 1); - if (be32_to_cpu(*(__be32 *)dptr) == XLOG_HEADER_MAGIC_NUM) - be32_add((__be32 *)dptr, 1); + for (i=0; il_iclog; for (i=0; il_iclog_bufs; i++) { sv_destroy(&iclog->ic_forcesema); @@ -1571,7 +1565,7 @@ xlog_dealloc_log(xlog_t *log) tic = log->l_unmount_free; while (tic) { next_tic = tic->t_next; - kmem_free(tic, PAGE_SIZE); + kmem_free(tic, NBPP); tic = next_tic; } } @@ -1598,12 +1592,14 @@ xlog_state_finish_copy(xlog_t *log, int record_cnt, int copy_bytes) { - spin_lock(&log->l_icloglock); + SPLDECL(s); - be32_add(&iclog->ic_header.h_num_logops, record_cnt); + s = LOG_LOCK(log); + + iclog->ic_header.h_num_logops += record_cnt; iclog->ic_offset += copy_bytes; - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); } /* xlog_state_finish_copy */ @@ -1756,7 +1752,7 @@ xlog_print_tic_res(xfs_mount_t *mp, xlog_ticket_t *ticket) * we don't update ic_offset until the end when we know exactly how many * bytes have been written out. */ -STATIC int +int xlog_write(xfs_mount_t * mp, xfs_log_iovec_t reg[], int nentries, @@ -1827,7 +1823,7 @@ xlog_write(xfs_mount_t * mp, /* start_lsn is the first lsn written to. That's all we need. */ if (! *start_lsn) - *start_lsn = be64_to_cpu(iclog->ic_header.h_lsn); + *start_lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT); /* This loop writes out as many regions as can fit in the amount * of space which was allocated by xlog_state_get_iclog_space(). @@ -1843,7 +1839,7 @@ xlog_write(xfs_mount_t * mp, */ if (ticket->t_flags & XLOG_TIC_INITED) { logop_head = (xlog_op_header_t *)ptr; - logop_head->oh_tid = cpu_to_be32(ticket->t_tid); + INT_SET(logop_head->oh_tid, ARCH_CONVERT, ticket->t_tid); logop_head->oh_clientid = ticket->t_clientid; logop_head->oh_len = 0; logop_head->oh_flags = XLOG_START_TRANS; @@ -1857,7 +1853,7 @@ xlog_write(xfs_mount_t * mp, /* Copy log operation header directly into data section */ logop_head = (xlog_op_header_t *)ptr; - logop_head->oh_tid = cpu_to_be32(ticket->t_tid); + INT_SET(logop_head->oh_tid, ARCH_CONVERT, ticket->t_tid); logop_head->oh_clientid = ticket->t_clientid; logop_head->oh_res2 = 0; @@ -1892,14 +1888,13 @@ xlog_write(xfs_mount_t * mp, copy_off = partial_copy_len; if (need_copy <= iclog->ic_size - log_offset) { /*complete write */ - copy_len = need_copy; - logop_head->oh_len = cpu_to_be32(copy_len); + INT_SET(logop_head->oh_len, ARCH_CONVERT, copy_len = need_copy); if (partial_copy) logop_head->oh_flags|= (XLOG_END_TRANS|XLOG_WAS_CONT_TRANS); partial_copy_len = partial_copy = 0; } else { /* partial write */ copy_len = iclog->ic_size - log_offset; - logop_head->oh_len = cpu_to_be32(copy_len); + INT_SET(logop_head->oh_len, ARCH_CONVERT, copy_len); logop_head->oh_flags |= XLOG_CONTINUE_TRANS; if (partial_copy) logop_head->oh_flags |= XLOG_WAS_CONT_TRANS; @@ -1997,8 +1992,7 @@ xlog_state_clean_log(xlog_t *log) * We don't need to cover the dummy. */ if (!changed && - (be32_to_cpu(iclog->ic_header.h_num_logops) == - XLOG_COVER_OPS)) { + (INT_GET(iclog->ic_header.h_num_logops, ARCH_CONVERT) == XLOG_COVER_OPS)) { changed = 1; } else { /* @@ -2066,7 +2060,7 @@ xlog_get_lowest_lsn( lowest_lsn = 0; do { if (!(lsn_log->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_DIRTY))) { - lsn = be64_to_cpu(lsn_log->ic_header.h_lsn); + lsn = INT_GET(lsn_log->ic_header.h_lsn, ARCH_CONVERT); if ((lsn && !lowest_lsn) || (XFS_LSN_CMP(lsn, lowest_lsn) < 0)) { lowest_lsn = lsn; @@ -2095,8 +2089,9 @@ xlog_state_do_callback( int funcdidcallbacks; /* flag: function did callbacks */ int repeats; /* for issuing console warnings if * looping too many times */ + SPLDECL(s); - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); first_iclog = iclog = log->l_iclog; ioerrors = 0; funcdidcallbacks = 0; @@ -2141,7 +2136,7 @@ xlog_state_do_callback( * to DO_CALLBACK, we will not process it when * we retry since a previous iclog is in the * CALLBACK and the state cannot change since - * we are holding the l_icloglock. + * we are holding the LOG_LOCK. */ if (!(iclog->ic_state & (XLOG_STATE_DONE_SYNC | @@ -2167,9 +2162,11 @@ xlog_state_do_callback( */ lowest_lsn = xlog_get_lowest_lsn(log); - if (lowest_lsn && - XFS_LSN_CMP(lowest_lsn, - be64_to_cpu(iclog->ic_header.h_lsn)) < 0) { + if (lowest_lsn && ( + XFS_LSN_CMP( + lowest_lsn, + INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT) + )<0)) { iclog = iclog->ic_next; continue; /* Leave this iclog for * another thread */ @@ -2177,18 +2174,19 @@ xlog_state_do_callback( iclog->ic_state = XLOG_STATE_CALLBACK; - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); /* l_last_sync_lsn field protected by - * l_grant_lock. Don't worry about iclog's lsn. + * GRANT_LOCK. Don't worry about iclog's lsn. * No one else can be here except us. */ - spin_lock(&log->l_grant_lock); - ASSERT(XFS_LSN_CMP(log->l_last_sync_lsn, - be64_to_cpu(iclog->ic_header.h_lsn)) <= 0); - log->l_last_sync_lsn = - be64_to_cpu(iclog->ic_header.h_lsn); - spin_unlock(&log->l_grant_lock); + s = GRANT_LOCK(log); + ASSERT(XFS_LSN_CMP( + log->l_last_sync_lsn, + INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT) + )<=0); + log->l_last_sync_lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT); + GRANT_UNLOCK(log, s); /* * Keep processing entries in the callback list @@ -2197,7 +2195,7 @@ xlog_state_do_callback( * empty and change the state to DIRTY so that * we don't miss any more callbacks being added. */ - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); } else { ioerrors++; } @@ -2206,14 +2204,14 @@ xlog_state_do_callback( while (cb) { iclog->ic_callback_tail = &(iclog->ic_callback); iclog->ic_callback = NULL; - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); /* perform callbacks in the order given */ for (; cb; cb = cb_next) { cb_next = cb->cb_next; cb->cb_func(cb->cb_arg, aborted); } - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); cb = iclog->ic_callback; } @@ -2260,7 +2258,7 @@ xlog_state_do_callback( * * SYNCING - i/o completion will go through logs * DONE_SYNC - interrupt thread should be waiting for - * l_icloglock + * LOG_LOCK * IOERROR - give up hope all ye who enter here */ if (iclog->ic_state == XLOG_STATE_WANT_SYNC || @@ -2278,7 +2276,7 @@ xlog_state_do_callback( flushcnt = log->l_flushcnt; log->l_flushcnt = 0; } - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); while (flushcnt--) vsema(&log->l_flushsema); } /* xlog_state_do_callback */ @@ -2298,14 +2296,15 @@ xlog_state_do_callback( * global state machine log lock. Assume that the calls to cvsema won't * take a long time. At least we know it won't sleep. */ -STATIC void +void xlog_state_done_syncing( xlog_in_core_t *iclog, int aborted) { xlog_t *log = iclog->ic_log; + SPLDECL(s); - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); ASSERT(iclog->ic_state == XLOG_STATE_SYNCING || iclog->ic_state == XLOG_STATE_IOERROR); @@ -2321,7 +2320,7 @@ xlog_state_done_syncing( */ if (iclog->ic_state != XLOG_STATE_IOERROR) { if (--iclog->ic_bwritecnt == 1) { - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); return; } iclog->ic_state = XLOG_STATE_DONE_SYNC; @@ -2333,7 +2332,7 @@ xlog_state_done_syncing( * I/O, the others get to wait for the result. */ sv_broadcast(&iclog->ic_writesema); - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); xlog_state_do_callback(log, aborted, iclog); /* also cleans log */ } /* xlog_state_done_syncing */ @@ -2358,7 +2357,7 @@ xlog_state_done_syncing( * needs to be incremented, depending on the amount of data which * is copied. */ -STATIC int +int xlog_state_get_iclog_space(xlog_t *log, int len, xlog_in_core_t **iclogp, @@ -2366,22 +2365,23 @@ xlog_state_get_iclog_space(xlog_t *log, int *continued_write, int *logoffsetp) { + SPLDECL(s); int log_offset; xlog_rec_header_t *head; xlog_in_core_t *iclog; int error; restart: - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); if (XLOG_FORCED_SHUTDOWN(log)) { - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); return XFS_ERROR(EIO); } iclog = log->l_iclog; if (! (iclog->ic_state == XLOG_STATE_ACTIVE)) { log->l_flushcnt++; - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); xlog_trace_iclog(iclog, XLOG_TRACE_SLEEP_FLUSH); XFS_STATS_INC(xs_log_noiclogs); /* Ensure that log writes happen */ @@ -2404,9 +2404,8 @@ xlog_state_get_iclog_space(xlog_t *log, xlog_tic_add_region(ticket, log->l_iclog_hsize, XLOG_REG_TYPE_LRHEADER); - head->h_cycle = cpu_to_be32(log->l_curr_cycle); - head->h_lsn = cpu_to_be64( - xlog_assign_lsn(log->l_curr_cycle, log->l_curr_block)); + INT_SET(head->h_cycle, ARCH_CONVERT, log->l_curr_cycle); + ASSIGN_LSN(head->h_lsn, log); ASSERT(log->l_curr_block >= 0); } @@ -2424,12 +2423,12 @@ xlog_state_get_iclog_space(xlog_t *log, /* If I'm the only one writing to this iclog, sync it to disk */ if (iclog->ic_refcnt == 1) { - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); if ((error = xlog_state_release_iclog(log, iclog))) return error; } else { iclog->ic_refcnt--; - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); } goto restart; } @@ -2450,7 +2449,7 @@ xlog_state_get_iclog_space(xlog_t *log, *iclogp = iclog; ASSERT(iclog->ic_offset <= iclog->ic_size); - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); *logoffsetp = log_offset; return 0; @@ -2468,6 +2467,7 @@ xlog_grant_log_space(xlog_t *log, { int free_bytes; int need_bytes; + SPLDECL(s); #ifdef DEBUG xfs_lsn_t tail_lsn; #endif @@ -2479,7 +2479,7 @@ xlog_grant_log_space(xlog_t *log, #endif /* Is there space or do we need to sleep? */ - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); xlog_trace_loggrant(log, tic, "xlog_grant_log_space: enter"); /* something is already sleeping; insert new transaction at end */ @@ -2502,7 +2502,7 @@ xlog_grant_log_space(xlog_t *log, */ xlog_trace_loggrant(log, tic, "xlog_grant_log_space: wake 1"); - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); } if (tic->t_flags & XFS_LOG_PERM_RESERV) need_bytes = tic->t_unit_res*tic->t_ocnt; @@ -2524,14 +2524,14 @@ xlog_grant_log_space(xlog_t *log, sv_wait(&tic->t_sema, PINOD|PLTWAIT, &log->l_grant_lock, s); if (XLOG_FORCED_SHUTDOWN(log)) { - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); goto error_return; } xlog_trace_loggrant(log, tic, "xlog_grant_log_space: wake 2"); xlog_grant_push_ail(log->l_mp, need_bytes); - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); goto redo; } else if (tic->t_flags & XLOG_TIC_IN_Q) xlog_del_ticketq(&log->l_reserve_headq, tic); @@ -2553,7 +2553,7 @@ xlog_grant_log_space(xlog_t *log, #endif xlog_trace_loggrant(log, tic, "xlog_grant_log_space: exit"); xlog_verify_grant_head(log, 1); - spin_unlock(&log->l_grant_lock); + GRANT_UNLOCK(log, s); return 0; error_return: @@ -2567,7 +2567,7 @@ xlog_grant_log_space(xlog_t *log, */ tic->t_curr_res = 0; tic->t_cnt = 0; /* ungrant will give back unit_res * t_cnt. */ - spin_unlock(&log->l_grant_lock); + GRANT_UNLOCK(log, s); return XFS_ERROR(EIO); } /* xlog_grant_log_space */ @@ -2581,6 +2581,7 @@ STATIC int xlog_regrant_write_log_space(xlog_t *log, xlog_ticket_t *tic) { + SPLDECL(s); int free_bytes, need_bytes; xlog_ticket_t *ntic; #ifdef DEBUG @@ -2598,7 +2599,7 @@ xlog_regrant_write_log_space(xlog_t *log, panic("regrant Recovery problem"); #endif - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); xlog_trace_loggrant(log, tic, "xlog_regrant_write_log_space: enter"); if (XLOG_FORCED_SHUTDOWN(log)) @@ -2637,14 +2638,14 @@ xlog_regrant_write_log_space(xlog_t *log, /* If we're shutting down, this tic is already * off the queue */ if (XLOG_FORCED_SHUTDOWN(log)) { - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); goto error_return; } xlog_trace_loggrant(log, tic, "xlog_regrant_write_log_space: wake 1"); xlog_grant_push_ail(log->l_mp, tic->t_unit_res); - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); } } @@ -2664,14 +2665,14 @@ xlog_regrant_write_log_space(xlog_t *log, /* If we're shutting down, this tic is already off the queue */ if (XLOG_FORCED_SHUTDOWN(log)) { - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); goto error_return; } xlog_trace_loggrant(log, tic, "xlog_regrant_write_log_space: wake 2"); xlog_grant_push_ail(log->l_mp, need_bytes); - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); goto redo; } else if (tic->t_flags & XLOG_TIC_IN_Q) xlog_del_ticketq(&log->l_write_headq, tic); @@ -2688,7 +2689,7 @@ xlog_regrant_write_log_space(xlog_t *log, xlog_trace_loggrant(log, tic, "xlog_regrant_write_log_space: exit"); xlog_verify_grant_head(log, 1); - spin_unlock(&log->l_grant_lock); + GRANT_UNLOCK(log, s); return 0; @@ -2703,7 +2704,7 @@ xlog_regrant_write_log_space(xlog_t *log, */ tic->t_curr_res = 0; tic->t_cnt = 0; /* ungrant will give back unit_res * t_cnt. */ - spin_unlock(&log->l_grant_lock); + GRANT_UNLOCK(log, s); return XFS_ERROR(EIO); } /* xlog_regrant_write_log_space */ @@ -2719,12 +2720,14 @@ STATIC void xlog_regrant_reserve_log_space(xlog_t *log, xlog_ticket_t *ticket) { + SPLDECL(s); + xlog_trace_loggrant(log, ticket, "xlog_regrant_reserve_log_space: enter"); if (ticket->t_cnt > 0) ticket->t_cnt--; - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); xlog_grant_sub_space(log, ticket->t_curr_res); ticket->t_curr_res = ticket->t_unit_res; xlog_tic_reset_res(ticket); @@ -2734,7 +2737,7 @@ xlog_regrant_reserve_log_space(xlog_t *log, /* just return if we still have some of the pre-reserved space */ if (ticket->t_cnt > 0) { - spin_unlock(&log->l_grant_lock); + GRANT_UNLOCK(log, s); return; } @@ -2742,7 +2745,7 @@ xlog_regrant_reserve_log_space(xlog_t *log, xlog_trace_loggrant(log, ticket, "xlog_regrant_reserve_log_space: exit"); xlog_verify_grant_head(log, 0); - spin_unlock(&log->l_grant_lock); + GRANT_UNLOCK(log, s); ticket->t_curr_res = ticket->t_unit_res; xlog_tic_reset_res(ticket); } /* xlog_regrant_reserve_log_space */ @@ -2766,10 +2769,12 @@ STATIC void xlog_ungrant_log_space(xlog_t *log, xlog_ticket_t *ticket) { + SPLDECL(s); + if (ticket->t_cnt > 0) ticket->t_cnt--; - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); xlog_trace_loggrant(log, ticket, "xlog_ungrant_log_space: enter"); xlog_grant_sub_space(log, ticket->t_curr_res); @@ -2786,7 +2791,7 @@ xlog_ungrant_log_space(xlog_t *log, xlog_trace_loggrant(log, ticket, "xlog_ungrant_log_space: exit"); xlog_verify_grant_head(log, 1); - spin_unlock(&log->l_grant_lock); + GRANT_UNLOCK(log, s); xfs_log_move_tail(log->l_mp, 1); } /* xlog_ungrant_log_space */ @@ -2794,13 +2799,15 @@ xlog_ungrant_log_space(xlog_t *log, /* * Atomically put back used ticket. */ -STATIC void +void xlog_state_put_ticket(xlog_t *log, xlog_ticket_t *tic) { - spin_lock(&log->l_icloglock); + unsigned long s; + + s = LOG_LOCK(log); xlog_ticket_put(log, tic); - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); } /* xlog_state_put_ticket */ /* @@ -2812,18 +2819,19 @@ xlog_state_put_ticket(xlog_t *log, * * */ -STATIC int +int xlog_state_release_iclog(xlog_t *log, xlog_in_core_t *iclog) { + SPLDECL(s); int sync = 0; /* do we sync? */ xlog_assign_tail_lsn(log->l_mp); - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); if (iclog->ic_state & XLOG_STATE_IOERROR) { - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); return XFS_ERROR(EIO); } @@ -2835,12 +2843,12 @@ xlog_state_release_iclog(xlog_t *log, iclog->ic_state == XLOG_STATE_WANT_SYNC) { sync++; iclog->ic_state = XLOG_STATE_SYNCING; - iclog->ic_header.h_tail_lsn = cpu_to_be64(log->l_tail_lsn); + INT_SET(iclog->ic_header.h_tail_lsn, ARCH_CONVERT, log->l_tail_lsn); xlog_verify_tail_lsn(log, iclog, log->l_tail_lsn); /* cycle incremented when incrementing curr_block */ } - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); /* * We let the log lock go, so it's possible that we hit a log I/O @@ -2873,7 +2881,7 @@ xlog_state_switch_iclogs(xlog_t *log, if (!eventual_size) eventual_size = iclog->ic_offset; iclog->ic_state = XLOG_STATE_WANT_SYNC; - iclog->ic_header.h_prev_block = cpu_to_be32(log->l_prev_block); + INT_SET(iclog->ic_header.h_prev_block, ARCH_CONVERT, log->l_prev_block); log->l_prev_block = log->l_curr_block; log->l_prev_cycle = log->l_curr_cycle; @@ -2931,12 +2939,13 @@ xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed) { xlog_in_core_t *iclog; xfs_lsn_t lsn; + SPLDECL(s); - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); iclog = log->l_iclog; if (iclog->ic_state & XLOG_STATE_IOERROR) { - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); return XFS_ERROR(EIO); } @@ -2969,15 +2978,15 @@ xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed) * the previous sync. */ iclog->ic_refcnt++; - lsn = be64_to_cpu(iclog->ic_header.h_lsn); + lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT); xlog_state_switch_iclogs(log, iclog, 0); - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); if (xlog_state_release_iclog(log, iclog)) return XFS_ERROR(EIO); *log_flushed = 1; - spin_lock(&log->l_icloglock); - if (be64_to_cpu(iclog->ic_header.h_lsn) == lsn && + s = LOG_LOCK(log); + if (INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT) == lsn && iclog->ic_state != XLOG_STATE_DIRTY) goto maybe_sleep; else @@ -3002,12 +3011,12 @@ xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed) if (flags & XFS_LOG_SYNC) { /* * We must check if we're shutting down here, before - * we wait, while we're holding the l_icloglock. + * we wait, while we're holding the LOG_LOCK. * Then we check again after waking up, in case our * sleep was disturbed by a bad news. */ if (iclog->ic_state & XLOG_STATE_IOERROR) { - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); return XFS_ERROR(EIO); } XFS_STATS_INC(xs_log_force_sleep); @@ -3024,7 +3033,7 @@ xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed) } else { no_sleep: - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); } return 0; } /* xlog_state_sync_all */ @@ -3042,7 +3051,7 @@ xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed) * If filesystem activity goes to zero, the iclog will get flushed only by * bdflush(). */ -STATIC int +int xlog_state_sync(xlog_t *log, xfs_lsn_t lsn, uint flags, @@ -3050,24 +3059,26 @@ xlog_state_sync(xlog_t *log, { xlog_in_core_t *iclog; int already_slept = 0; + SPLDECL(s); + try_again: - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); iclog = log->l_iclog; if (iclog->ic_state & XLOG_STATE_IOERROR) { - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); return XFS_ERROR(EIO); } do { - if (be64_to_cpu(iclog->ic_header.h_lsn) != lsn) { - iclog = iclog->ic_next; - continue; + if (INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT) != lsn) { + iclog = iclog->ic_next; + continue; } if (iclog->ic_state == XLOG_STATE_DIRTY) { - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); return 0; } @@ -3102,11 +3113,11 @@ xlog_state_sync(xlog_t *log, } else { iclog->ic_refcnt++; xlog_state_switch_iclogs(log, iclog, 0); - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); if (xlog_state_release_iclog(log, iclog)) return XFS_ERROR(EIO); *log_flushed = 1; - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); } } @@ -3118,7 +3129,7 @@ xlog_state_sync(xlog_t *log, * gotten a log write error. */ if (iclog->ic_state & XLOG_STATE_IOERROR) { - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); return XFS_ERROR(EIO); } XFS_STATS_INC(xs_log_force_sleep); @@ -3132,13 +3143,13 @@ xlog_state_sync(xlog_t *log, return XFS_ERROR(EIO); *log_flushed = 1; } else { /* just return */ - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); } return 0; } while (iclog != log->l_iclog); - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); return 0; } /* xlog_state_sync */ @@ -3147,10 +3158,12 @@ xlog_state_sync(xlog_t *log, * Called when we want to mark the current iclog as being ready to sync to * disk. */ -STATIC void +void xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog) { - spin_lock(&log->l_icloglock); + SPLDECL(s); + + s = LOG_LOCK(log); if (iclog->ic_state == XLOG_STATE_ACTIVE) { xlog_state_switch_iclogs(log, iclog, 0); @@ -3159,7 +3172,7 @@ xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog) (XLOG_STATE_WANT_SYNC|XLOG_STATE_IOERROR)); } - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); } /* xlog_state_want_sync */ @@ -3180,15 +3193,16 @@ xlog_state_ticket_alloc(xlog_t *log) xlog_ticket_t *t_list; xlog_ticket_t *next; xfs_caddr_t buf; - uint i = (PAGE_SIZE / sizeof(xlog_ticket_t)) - 2; + uint i = (NBPP / sizeof(xlog_ticket_t)) - 2; + SPLDECL(s); /* * The kmem_zalloc may sleep, so we shouldn't be holding the * global lock. XXXmiken: may want to use zone allocator. */ - buf = (xfs_caddr_t) kmem_zalloc(PAGE_SIZE, KM_SLEEP); + buf = (xfs_caddr_t) kmem_zalloc(NBPP, KM_SLEEP); - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); /* Attach 1st ticket to Q, so we can keep track of allocated memory */ t_list = (xlog_ticket_t *)buf; @@ -3217,7 +3231,7 @@ xlog_state_ticket_alloc(xlog_t *log) } t_list->t_next = NULL; log->l_tail = t_list; - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); } /* xlog_state_ticket_alloc */ @@ -3259,7 +3273,7 @@ xlog_ticket_put(xlog_t *log, /* * Grab ticket off freelist or allocation some more */ -STATIC xlog_ticket_t * +xlog_ticket_t * xlog_ticket_get(xlog_t *log, int unit_bytes, int cnt, @@ -3268,14 +3282,15 @@ xlog_ticket_get(xlog_t *log, { xlog_ticket_t *tic; uint num_headers; + SPLDECL(s); alloc: if (log->l_freelist == NULL) xlog_state_ticket_alloc(log); /* potentially sleep */ - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); if (log->l_freelist == NULL) { - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); goto alloc; } tic = log->l_freelist; @@ -3283,7 +3298,7 @@ xlog_ticket_get(xlog_t *log, if (log->l_freelist == NULL) log->l_tail = NULL; log->l_ticket_cnt--; - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); /* * Permanent reservations have up to 'cnt'-1 active log operations @@ -3458,9 +3473,10 @@ xlog_verify_iclog(xlog_t *log, __uint8_t clientid; int len, i, j, k, op_len; int idx; + SPLDECL(s); /* check validity of iclog pointers */ - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); icptr = log->l_iclog; for (i=0; i < log->l_iclog_bufs; i++) { if (icptr == NULL) @@ -3469,21 +3485,21 @@ xlog_verify_iclog(xlog_t *log, } if (icptr != log->l_iclog) xlog_panic("xlog_verify_iclog: corrupt iclog ring"); - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); /* check log magic numbers */ - if (be32_to_cpu(iclog->ic_header.h_magicno) != XLOG_HEADER_MAGIC_NUM) + ptr = (xfs_caddr_t) &(iclog->ic_header); + if (INT_GET(*(uint *)ptr, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) xlog_panic("xlog_verify_iclog: invalid magic num"); - ptr = (xfs_caddr_t) &iclog->ic_header; - for (ptr += BBSIZE; ptr < ((xfs_caddr_t)&iclog->ic_header) + count; + for (ptr += BBSIZE; ptr < ((xfs_caddr_t)&(iclog->ic_header))+count; ptr += BBSIZE) { - if (be32_to_cpu(*(__be32 *)ptr) == XLOG_HEADER_MAGIC_NUM) + if (INT_GET(*(uint *)ptr, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) xlog_panic("xlog_verify_iclog: unexpected magic num"); } /* check fields */ - len = be32_to_cpu(iclog->ic_header.h_num_logops); + len = INT_GET(iclog->ic_header.h_num_logops, ARCH_CONVERT); ptr = iclog->ic_datap; base_ptr = ptr; ophead = (xlog_op_header_t *)ptr; @@ -3501,11 +3517,9 @@ xlog_verify_iclog(xlog_t *log, if (idx >= (XLOG_HEADER_CYCLE_SIZE / BBSIZE)) { j = idx / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); k = idx % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - clientid = xlog_get_client_id( - xhdr[j].hic_xheader.xh_cycle_data[k]); + clientid = GET_CLIENT_ID(xhdr[j].hic_xheader.xh_cycle_data[k], ARCH_CONVERT); } else { - clientid = xlog_get_client_id( - iclog->ic_header.h_cycle_data[idx]); + clientid = GET_CLIENT_ID(iclog->ic_header.h_cycle_data[idx], ARCH_CONVERT); } } if (clientid != XFS_TRANSACTION && clientid != XFS_LOG) @@ -3517,16 +3531,16 @@ xlog_verify_iclog(xlog_t *log, field_offset = (__psint_t) ((xfs_caddr_t)&(ophead->oh_len) - base_ptr); if (syncing == B_FALSE || (field_offset & 0x1ff)) { - op_len = be32_to_cpu(ophead->oh_len); + op_len = INT_GET(ophead->oh_len, ARCH_CONVERT); } else { idx = BTOBBT((__psint_t)&ophead->oh_len - (__psint_t)iclog->ic_datap); if (idx >= (XLOG_HEADER_CYCLE_SIZE / BBSIZE)) { j = idx / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); k = idx % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - op_len = be32_to_cpu(xhdr[j].hic_xheader.xh_cycle_data[k]); + op_len = INT_GET(xhdr[j].hic_xheader.xh_cycle_data[k], ARCH_CONVERT); } else { - op_len = be32_to_cpu(iclog->ic_header.h_cycle_data[idx]); + op_len = INT_GET(iclog->ic_header.h_cycle_data[idx], ARCH_CONVERT); } } ptr += sizeof(xlog_op_header_t) + op_len; @@ -3535,7 +3549,7 @@ xlog_verify_iclog(xlog_t *log, #endif /* - * Mark all iclogs IOERROR. l_icloglock is held by the caller. + * Mark all iclogs IOERROR. LOG_LOCK is held by the caller. */ STATIC int xlog_state_ioerror( @@ -3583,6 +3597,8 @@ xfs_log_force_umount( xlog_t *log; int retval; int dummy; + SPLDECL(s); + SPLDECL(s2); log = mp->m_log; @@ -3611,8 +3627,8 @@ xfs_log_force_umount( * before we mark the filesystem SHUTDOWN and wake * everybody up to tell the bad news. */ - spin_lock(&log->l_grant_lock); - spin_lock(&log->l_icloglock); + s = GRANT_LOCK(log); + s2 = LOG_LOCK(log); mp->m_flags |= XFS_MOUNT_FS_SHUTDOWN; XFS_BUF_DONE(mp->m_sb_bp); /* @@ -3628,7 +3644,7 @@ xfs_log_force_umount( */ if (logerror) retval = xlog_state_ioerror(log); - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s2); /* * We don't want anybody waiting for log reservations @@ -3651,7 +3667,7 @@ xfs_log_force_umount( tic = tic->t_next; } while (tic != log->l_write_headq); } - spin_unlock(&log->l_grant_lock); + GRANT_UNLOCK(log, s); if (! (log->l_iclog->ic_state & XLOG_STATE_IOERROR)) { ASSERT(!logerror); @@ -3660,9 +3676,9 @@ xfs_log_force_umount( * log down completely. */ xlog_state_sync_all(log, XFS_LOG_FORCE|XFS_LOG_SYNC, &dummy); - spin_lock(&log->l_icloglock); + s2 = LOG_LOCK(log); retval = xlog_state_ioerror(log); - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s2); } /* * Wake up everybody waiting on xfs_log_force. @@ -3675,13 +3691,13 @@ xfs_log_force_umount( { xlog_in_core_t *iclog; - spin_lock(&log->l_icloglock); + s = LOG_LOCK(log); iclog = log->l_iclog; do { ASSERT(iclog->ic_callback == 0); iclog = iclog->ic_next; } while (iclog != log->l_iclog); - spin_unlock(&log->l_icloglock); + LOG_UNLOCK(log, s); } #endif /* return non-zero if log IOERROR transition had already happened */ diff --git a/trunk/fs/xfs/xfs_log.h b/trunk/fs/xfs/xfs_log.h index 4cdac048df5e..ebbe93f4f97b 100644 --- a/trunk/fs/xfs/xfs_log.h +++ b/trunk/fs/xfs/xfs_log.h @@ -22,9 +22,8 @@ #define CYCLE_LSN(lsn) ((uint)((lsn)>>32)) #define BLOCK_LSN(lsn) ((uint)(lsn)) - /* this is used in a spot where we might otherwise double-endian-flip */ -#define CYCLE_LSN_DISK(lsn) (((__be32 *)&(lsn))[0]) +#define CYCLE_LSN_DISK(lsn) (((uint *)&(lsn))[0]) #ifdef __KERNEL__ /* diff --git a/trunk/fs/xfs/xfs_log_priv.h b/trunk/fs/xfs/xfs_log_priv.h index e008233ee249..752f964b3699 100644 --- a/trunk/fs/xfs/xfs_log_priv.h +++ b/trunk/fs/xfs/xfs_log_priv.h @@ -55,22 +55,33 @@ struct xfs_mount; BTOBB(XLOG_MAX_ICLOGS << (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? \ XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT)) +/* + * set lsns + */ -static inline xfs_lsn_t xlog_assign_lsn(uint cycle, uint block) -{ - return ((xfs_lsn_t)cycle << 32) | block; -} - -static inline uint xlog_get_cycle(char *ptr) -{ - if (be32_to_cpu(*(__be32 *)ptr) == XLOG_HEADER_MAGIC_NUM) - return be32_to_cpu(*((__be32 *)ptr + 1)); - else - return be32_to_cpu(*(__be32 *)ptr); -} +#define ASSIGN_ANY_LSN_HOST(lsn,cycle,block) \ + { \ + (lsn) = ((xfs_lsn_t)(cycle)<<32)|(block); \ + } +#define ASSIGN_ANY_LSN_DISK(lsn,cycle,block) \ + { \ + INT_SET(((uint *)&(lsn))[0], ARCH_CONVERT, (cycle)); \ + INT_SET(((uint *)&(lsn))[1], ARCH_CONVERT, (block)); \ + } +#define ASSIGN_LSN(lsn,log) \ + ASSIGN_ANY_LSN_DISK(lsn,(log)->l_curr_cycle,(log)->l_curr_block); + +#define XLOG_SET(f,b) (((f) & (b)) == (b)) + +#define GET_CYCLE(ptr, arch) \ + (INT_GET(*(uint *)(ptr), arch) == XLOG_HEADER_MAGIC_NUM ? \ + INT_GET(*((uint *)(ptr)+1), arch) : \ + INT_GET(*(uint *)(ptr), arch) \ + ) #define BLK_AVG(blk1, blk2) ((blk1+blk2) >> 1) + #ifdef __KERNEL__ /* @@ -85,10 +96,19 @@ static inline uint xlog_get_cycle(char *ptr) * * this has endian issues, of course. */ -static inline uint xlog_get_client_id(__be32 i) -{ - return be32_to_cpu(i) >> 24; -} + +#ifndef XFS_NATIVE_HOST +#define GET_CLIENT_ID(i,arch) \ + ((i) & 0xff) +#else +#define GET_CLIENT_ID(i,arch) \ + ((i) >> 24) +#endif + +#define GRANT_LOCK(log) mutex_spinlock(&(log)->l_grant_lock) +#define GRANT_UNLOCK(log, s) mutex_spinunlock(&(log)->l_grant_lock, s) +#define LOG_LOCK(log) mutex_spinlock(&(log)->l_icloglock) +#define LOG_UNLOCK(log, s) mutex_spinunlock(&(log)->l_icloglock, s) #define xlog_panic(args...) cmn_err(CE_PANIC, ## args) #define xlog_exit(args...) cmn_err(CE_PANIC, ## args) @@ -265,11 +285,11 @@ typedef struct xlog_ticket { typedef struct xlog_op_header { - __be32 oh_tid; /* transaction id of operation : 4 b */ - __be32 oh_len; /* bytes in data region : 4 b */ - __u8 oh_clientid; /* who sent me this : 1 b */ - __u8 oh_flags; /* : 1 b */ - __u16 oh_res2; /* 32 bit align : 2 b */ + xlog_tid_t oh_tid; /* transaction id of operation : 4 b */ + int oh_len; /* bytes in data region : 4 b */ + __uint8_t oh_clientid; /* who sent me this : 1 b */ + __uint8_t oh_flags; /* : 1 b */ + ushort oh_res2; /* 32 bit align : 2 b */ } xlog_op_header_t; @@ -287,25 +307,25 @@ typedef struct xlog_op_header { #endif typedef struct xlog_rec_header { - __be32 h_magicno; /* log record (LR) identifier : 4 */ - __be32 h_cycle; /* write cycle of log : 4 */ - __be32 h_version; /* LR version : 4 */ - __be32 h_len; /* len in bytes; should be 64-bit aligned: 4 */ - __be64 h_lsn; /* lsn of this LR : 8 */ - __be64 h_tail_lsn; /* lsn of 1st LR w/ buffers not committed: 8 */ - __be32 h_chksum; /* may not be used; non-zero if used : 4 */ - __be32 h_prev_block; /* block number to previous LR : 4 */ - __be32 h_num_logops; /* number of log operations in this LR : 4 */ - __be32 h_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; + uint h_magicno; /* log record (LR) identifier : 4 */ + uint h_cycle; /* write cycle of log : 4 */ + int h_version; /* LR version : 4 */ + int h_len; /* len in bytes; should be 64-bit aligned: 4 */ + xfs_lsn_t h_lsn; /* lsn of this LR : 8 */ + xfs_lsn_t h_tail_lsn; /* lsn of 1st LR w/ buffers not committed: 8 */ + uint h_chksum; /* may not be used; non-zero if used : 4 */ + int h_prev_block; /* block number to previous LR : 4 */ + int h_num_logops; /* number of log operations in this LR : 4 */ + uint h_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* new fields */ - __be32 h_fmt; /* format of log record : 4 */ - uuid_t h_fs_uuid; /* uuid of FS : 16 */ - __be32 h_size; /* iclog size : 4 */ + int h_fmt; /* format of log record : 4 */ + uuid_t h_fs_uuid; /* uuid of FS : 16 */ + int h_size; /* iclog size : 4 */ } xlog_rec_header_t; typedef struct xlog_rec_ext_header { - __be32 xh_cycle; /* write cycle of log : 4 */ - __be32 xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* : 256 */ + uint xh_cycle; /* write cycle of log : 4 */ + uint xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* : 256 */ } xlog_rec_ext_header_t; #ifdef __KERNEL__ @@ -395,7 +415,7 @@ typedef struct log { xlog_ticket_t *l_unmount_free;/* kmem_free these addresses */ xlog_ticket_t *l_tail; /* free list of tickets */ xlog_in_core_t *l_iclog; /* head log queue */ - spinlock_t l_icloglock; /* grab to change iclog state */ + lock_t l_icloglock; /* grab to change iclog state */ xfs_lsn_t l_tail_lsn; /* lsn of 1st LR with unflushed * buffers */ xfs_lsn_t l_last_sync_lsn;/* lsn of last LR on disk */ @@ -419,7 +439,7 @@ typedef struct log { char *l_iclog_bak[XLOG_MAX_ICLOGS]; /* The following block of fields are changed while holding grant_lock */ - spinlock_t l_grant_lock; + lock_t l_grant_lock; xlog_ticket_t *l_reserve_headq; xlog_ticket_t *l_write_headq; int l_grant_reserve_cycle; diff --git a/trunk/fs/xfs/xfs_log_recover.c b/trunk/fs/xfs/xfs_log_recover.c index b82d5d4d2462..851eca8a7150 100644 --- a/trunk/fs/xfs/xfs_log_recover.c +++ b/trunk/fs/xfs/xfs_log_recover.c @@ -198,7 +198,7 @@ xlog_header_check_dump( cmn_err(CE_DEBUG, " log : uuid = "); for (b = 0; b < 16; b++) cmn_err(CE_DEBUG, "%02x",((uchar_t *)&head->h_fs_uuid)[b]); - cmn_err(CE_DEBUG, ", fmt = %d\n", be32_to_cpu(head->h_fmt)); + cmn_err(CE_DEBUG, ", fmt = %d\n", INT_GET(head->h_fmt, ARCH_CONVERT)); } #else #define xlog_header_check_dump(mp, head) @@ -212,14 +212,14 @@ xlog_header_check_recover( xfs_mount_t *mp, xlog_rec_header_t *head) { - ASSERT(be32_to_cpu(head->h_magicno) == XLOG_HEADER_MAGIC_NUM); + ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); /* * IRIX doesn't write the h_fmt field and leaves it zeroed * (XLOG_FMT_UNKNOWN). This stops us from trying to recover * a dirty log created in IRIX. */ - if (unlikely(be32_to_cpu(head->h_fmt) != XLOG_FMT)) { + if (unlikely(INT_GET(head->h_fmt, ARCH_CONVERT) != XLOG_FMT)) { xlog_warn( "XFS: dirty log written in incompatible format - can't recover"); xlog_header_check_dump(mp, head); @@ -245,7 +245,7 @@ xlog_header_check_mount( xfs_mount_t *mp, xlog_rec_header_t *head) { - ASSERT(be32_to_cpu(head->h_magicno) == XLOG_HEADER_MAGIC_NUM); + ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); if (uuid_is_nil(&head->h_fs_uuid)) { /* @@ -293,7 +293,7 @@ xlog_recover_iodone( * Note that the algorithm can not be perfect because the disk will not * necessarily be perfect. */ -STATIC int +int xlog_find_cycle_start( xlog_t *log, xfs_buf_t *bp, @@ -311,7 +311,7 @@ xlog_find_cycle_start( if ((error = xlog_bread(log, mid_blk, 1, bp))) return error; offset = xlog_align(log, mid_blk, 1, bp); - mid_cycle = xlog_get_cycle(offset); + mid_cycle = GET_CYCLE(offset, ARCH_CONVERT); if (mid_cycle == cycle) { *last_blk = mid_blk; /* last_half_cycle == mid_cycle */ @@ -371,7 +371,7 @@ xlog_find_verify_cycle( buf = xlog_align(log, i, bcount, bp); for (j = 0; j < bcount; j++) { - cycle = xlog_get_cycle(buf); + cycle = GET_CYCLE(buf, ARCH_CONVERT); if (cycle == stop_on_cycle_no) { *new_blk = i+j; goto out; @@ -447,7 +447,8 @@ xlog_find_verify_log_record( head = (xlog_rec_header_t *)offset; - if (XLOG_HEADER_MAGIC_NUM == be32_to_cpu(head->h_magicno)) + if (XLOG_HEADER_MAGIC_NUM == + INT_GET(head->h_magicno, ARCH_CONVERT)) break; if (!smallmem) @@ -479,7 +480,7 @@ xlog_find_verify_log_record( * record do we update last_blk. */ if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { - uint h_size = be32_to_cpu(head->h_size); + uint h_size = INT_GET(head->h_size, ARCH_CONVERT); xhdrs = h_size / XLOG_HEADER_CYCLE_SIZE; if (h_size % XLOG_HEADER_CYCLE_SIZE) @@ -488,8 +489,8 @@ xlog_find_verify_log_record( xhdrs = 1; } - if (*last_blk - i + extra_bblks != - BTOBB(be32_to_cpu(head->h_len)) + xhdrs) + if (*last_blk - i + extra_bblks + != BTOBB(INT_GET(head->h_len, ARCH_CONVERT)) + xhdrs) *last_blk = i; out: @@ -549,13 +550,13 @@ xlog_find_head( if ((error = xlog_bread(log, 0, 1, bp))) goto bp_err; offset = xlog_align(log, 0, 1, bp); - first_half_cycle = xlog_get_cycle(offset); + first_half_cycle = GET_CYCLE(offset, ARCH_CONVERT); last_blk = head_blk = log_bbnum - 1; /* get cycle # of last block */ if ((error = xlog_bread(log, last_blk, 1, bp))) goto bp_err; offset = xlog_align(log, last_blk, 1, bp); - last_half_cycle = xlog_get_cycle(offset); + last_half_cycle = GET_CYCLE(offset, ARCH_CONVERT); ASSERT(last_half_cycle != 0); /* @@ -807,7 +808,7 @@ xlog_find_tail( if ((error = xlog_bread(log, 0, 1, bp))) goto bread_err; offset = xlog_align(log, 0, 1, bp); - if (xlog_get_cycle(offset) == 0) { + if (GET_CYCLE(offset, ARCH_CONVERT) == 0) { *tail_blk = 0; /* leave all other log inited values alone */ goto exit; @@ -822,7 +823,8 @@ xlog_find_tail( if ((error = xlog_bread(log, i, 1, bp))) goto bread_err; offset = xlog_align(log, i, 1, bp); - if (XLOG_HEADER_MAGIC_NUM == be32_to_cpu(*(__be32 *)offset)) { + if (XLOG_HEADER_MAGIC_NUM == + INT_GET(*(uint *)offset, ARCH_CONVERT)) { found = 1; break; } @@ -839,7 +841,7 @@ xlog_find_tail( goto bread_err; offset = xlog_align(log, i, 1, bp); if (XLOG_HEADER_MAGIC_NUM == - be32_to_cpu(*(__be32 *)offset)) { + INT_GET(*(uint*)offset, ARCH_CONVERT)) { found = 2; break; } @@ -853,7 +855,7 @@ xlog_find_tail( /* find blk_no of tail of log */ rhead = (xlog_rec_header_t *)offset; - *tail_blk = BLOCK_LSN(be64_to_cpu(rhead->h_tail_lsn)); + *tail_blk = BLOCK_LSN(INT_GET(rhead->h_tail_lsn, ARCH_CONVERT)); /* * Reset log values according to the state of the log when we @@ -867,11 +869,11 @@ xlog_find_tail( */ log->l_prev_block = i; log->l_curr_block = (int)*head_blk; - log->l_curr_cycle = be32_to_cpu(rhead->h_cycle); + log->l_curr_cycle = INT_GET(rhead->h_cycle, ARCH_CONVERT); if (found == 2) log->l_curr_cycle++; - log->l_tail_lsn = be64_to_cpu(rhead->h_tail_lsn); - log->l_last_sync_lsn = be64_to_cpu(rhead->h_lsn); + log->l_tail_lsn = INT_GET(rhead->h_tail_lsn, ARCH_CONVERT); + log->l_last_sync_lsn = INT_GET(rhead->h_lsn, ARCH_CONVERT); log->l_grant_reserve_cycle = log->l_curr_cycle; log->l_grant_reserve_bytes = BBTOB(log->l_curr_block); log->l_grant_write_cycle = log->l_curr_cycle; @@ -889,8 +891,8 @@ xlog_find_tail( * unmount record rather than the block after it. */ if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { - int h_size = be32_to_cpu(rhead->h_size); - int h_version = be32_to_cpu(rhead->h_version); + int h_size = INT_GET(rhead->h_size, ARCH_CONVERT); + int h_version = INT_GET(rhead->h_version, ARCH_CONVERT); if ((h_version & XLOG_VERSION_2) && (h_size > XLOG_HEADER_CYCLE_SIZE)) { @@ -904,10 +906,10 @@ xlog_find_tail( hblks = 1; } after_umount_blk = (i + hblks + (int) - BTOBB(be32_to_cpu(rhead->h_len))) % log->l_logBBsize; + BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT))) % log->l_logBBsize; tail_lsn = log->l_tail_lsn; if (*head_blk == after_umount_blk && - be32_to_cpu(rhead->h_num_logops) == 1) { + INT_GET(rhead->h_num_logops, ARCH_CONVERT) == 1) { umount_data_blk = (i + hblks) % log->l_logBBsize; if ((error = xlog_bread(log, umount_data_blk, 1, bp))) { goto bread_err; @@ -920,12 +922,10 @@ xlog_find_tail( * log records will point recovery to after the * current unmount record. */ - log->l_tail_lsn = - xlog_assign_lsn(log->l_curr_cycle, - after_umount_blk); - log->l_last_sync_lsn = - xlog_assign_lsn(log->l_curr_cycle, - after_umount_blk); + ASSIGN_ANY_LSN_HOST(log->l_tail_lsn, log->l_curr_cycle, + after_umount_blk); + ASSIGN_ANY_LSN_HOST(log->l_last_sync_lsn, log->l_curr_cycle, + after_umount_blk); *tail_blk = after_umount_blk; /* @@ -986,7 +986,7 @@ xlog_find_tail( * -1 => use *blk_no as the first block of the log * >0 => error has occurred */ -STATIC int +int xlog_find_zeroed( xlog_t *log, xfs_daddr_t *blk_no) @@ -1007,7 +1007,7 @@ xlog_find_zeroed( if ((error = xlog_bread(log, 0, 1, bp))) goto bp_err; offset = xlog_align(log, 0, 1, bp); - first_cycle = xlog_get_cycle(offset); + first_cycle = GET_CYCLE(offset, ARCH_CONVERT); if (first_cycle == 0) { /* completely zeroed log */ *blk_no = 0; xlog_put_bp(bp); @@ -1018,7 +1018,7 @@ xlog_find_zeroed( if ((error = xlog_bread(log, log_bbnum-1, 1, bp))) goto bp_err; offset = xlog_align(log, log_bbnum-1, 1, bp); - last_cycle = xlog_get_cycle(offset); + last_cycle = GET_CYCLE(offset, ARCH_CONVERT); if (last_cycle != 0) { /* log completely written to */ xlog_put_bp(bp); return 0; @@ -1098,13 +1098,13 @@ xlog_add_record( xlog_rec_header_t *recp = (xlog_rec_header_t *)buf; memset(buf, 0, BBSIZE); - recp->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM); - recp->h_cycle = cpu_to_be32(cycle); - recp->h_version = cpu_to_be32( + INT_SET(recp->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM); + INT_SET(recp->h_cycle, ARCH_CONVERT, cycle); + INT_SET(recp->h_version, ARCH_CONVERT, XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? 2 : 1); - recp->h_lsn = cpu_to_be64(xlog_assign_lsn(cycle, block)); - recp->h_tail_lsn = cpu_to_be64(xlog_assign_lsn(tail_cycle, tail_block)); - recp->h_fmt = cpu_to_be32(XLOG_FMT); + ASSIGN_ANY_LSN_DISK(recp->h_lsn, cycle, block); + ASSIGN_ANY_LSN_DISK(recp->h_tail_lsn, tail_cycle, tail_block); + INT_SET(recp->h_fmt, ARCH_CONVERT, XLOG_FMT); memcpy(&recp->h_fs_uuid, &log->l_mp->m_sb.sb_uuid, sizeof(uuid_t)); } @@ -2211,7 +2211,7 @@ xlog_recover_do_buffer_trans( * overlap with future reads of those inodes. */ if (XFS_DINODE_MAGIC == - be16_to_cpu(*((__be16 *)xfs_buf_offset(bp, 0))) && + INT_GET(*((__uint16_t *)(xfs_buf_offset(bp, 0))), ARCH_CONVERT) && (XFS_BUF_COUNT(bp) != MAX(log->l_mp->m_sb.sb_blocksize, (__uint32_t)XFS_INODE_CLUSTER_SIZE(log->l_mp)))) { XFS_BUF_STALE(bp); @@ -2581,7 +2581,8 @@ xlog_recover_do_dquot_trans( /* * This type of quotas was turned off, so ignore this record. */ - type = recddq->d_flags & (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP); + type = INT_GET(recddq->d_flags, ARCH_CONVERT) & + (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP); ASSERT(type); if (log->l_quotaoffs_flag & type) return (0); @@ -2659,6 +2660,7 @@ xlog_recover_do_efi_trans( xfs_mount_t *mp; xfs_efi_log_item_t *efip; xfs_efi_log_format_t *efi_formatp; + SPLDECL(s); if (pass == XLOG_RECOVER_PASS1) { return 0; @@ -2676,11 +2678,11 @@ xlog_recover_do_efi_trans( efip->efi_next_extent = efi_formatp->efi_nextents; efip->efi_flags |= XFS_EFI_COMMITTED; - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp,s); /* * xfs_trans_update_ail() drops the AIL lock. */ - xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn); + xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn, s); return 0; } @@ -2705,6 +2707,7 @@ xlog_recover_do_efd_trans( xfs_log_item_t *lip; int gen; __uint64_t efi_id; + SPLDECL(s); if (pass == XLOG_RECOVER_PASS1) { return; @@ -2722,7 +2725,7 @@ xlog_recover_do_efd_trans( * in the AIL. */ mp = log->l_mp; - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp,s); lip = xfs_trans_first_ail(mp, &gen); while (lip != NULL) { if (lip->li_type == XFS_LI_EFI) { @@ -2732,14 +2735,22 @@ xlog_recover_do_efd_trans( * xfs_trans_delete_ail() drops the * AIL lock. */ - xfs_trans_delete_ail(mp, lip); - xfs_efi_item_free(efip); - return; + xfs_trans_delete_ail(mp, lip, s); + break; } } lip = xfs_trans_next_ail(mp, lip, &gen, NULL); } - spin_unlock(&mp->m_ail_lock); + + /* + * If we found it, then free it up. If it wasn't there, it + * must have been overwritten in the log. Oh well. + */ + if (lip != NULL) { + xfs_efi_item_free(efip); + } else { + AIL_UNLOCK(mp, s); + } } /* @@ -2886,8 +2897,8 @@ xlog_recover_process_data( unsigned long hash; uint flags; - lp = dp + be32_to_cpu(rhead->h_len); - num_logops = be32_to_cpu(rhead->h_num_logops); + lp = dp + INT_GET(rhead->h_len, ARCH_CONVERT); + num_logops = INT_GET(rhead->h_num_logops, ARCH_CONVERT); /* check the log format matches our own - else we can't recover */ if (xlog_header_check_recover(log->l_mp, rhead)) @@ -2904,20 +2915,15 @@ xlog_recover_process_data( ASSERT(0); return (XFS_ERROR(EIO)); } - tid = be32_to_cpu(ohead->oh_tid); + tid = INT_GET(ohead->oh_tid, ARCH_CONVERT); hash = XLOG_RHASH(tid); trans = xlog_recover_find_tid(rhash[hash], tid); if (trans == NULL) { /* not found; add new tid */ if (ohead->oh_flags & XLOG_START_TRANS) xlog_recover_new_tid(&rhash[hash], tid, - be64_to_cpu(rhead->h_lsn)); + INT_GET(rhead->h_lsn, ARCH_CONVERT)); } else { - if (dp + be32_to_cpu(ohead->oh_len) > lp) { - xlog_warn( - "XFS: xlog_recover_process_data: bad length"); - WARN_ON(1); - return (XFS_ERROR(EIO)); - } + ASSERT(dp+INT_GET(ohead->oh_len, ARCH_CONVERT) <= lp); flags = ohead->oh_flags & ~XLOG_END_TRANS; if (flags & XLOG_WAS_CONT_TRANS) flags &= ~XLOG_CONTINUE_TRANS; @@ -2931,7 +2937,8 @@ xlog_recover_process_data( break; case XLOG_WAS_CONT_TRANS: error = xlog_recover_add_to_cont_trans(trans, - dp, be32_to_cpu(ohead->oh_len)); + dp, INT_GET(ohead->oh_len, + ARCH_CONVERT)); break; case XLOG_START_TRANS: xlog_warn( @@ -2942,7 +2949,8 @@ xlog_recover_process_data( case 0: case XLOG_CONTINUE_TRANS: error = xlog_recover_add_to_trans(trans, - dp, be32_to_cpu(ohead->oh_len)); + dp, INT_GET(ohead->oh_len, + ARCH_CONVERT)); break; default: xlog_warn( @@ -2954,7 +2962,7 @@ xlog_recover_process_data( if (error) return error; } - dp += be32_to_cpu(ohead->oh_len); + dp += INT_GET(ohead->oh_len, ARCH_CONVERT); num_logops--; } return 0; @@ -3067,9 +3075,10 @@ xlog_recover_process_efis( xfs_efi_log_item_t *efip; int gen; xfs_mount_t *mp; + SPLDECL(s); mp = log->l_mp; - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp,s); lip = xfs_trans_first_ail(mp, &gen); while (lip != NULL) { @@ -3090,12 +3099,12 @@ xlog_recover_process_efis( continue; } - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); xlog_recover_process_efi(mp, efip); - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp,s); lip = xfs_trans_next_ail(mp, lip, &gen, NULL); } - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); } /* @@ -3306,16 +3315,16 @@ xlog_pack_data_checksum( int size) { int i; - __be32 *up; + uint *up; uint chksum = 0; - up = (__be32 *)iclog->ic_datap; + up = (uint *)iclog->ic_datap; /* divide length by 4 to get # words */ for (i = 0; i < (size >> 2); i++) { - chksum ^= be32_to_cpu(*up); + chksum ^= INT_GET(*up, ARCH_CONVERT); up++; } - iclog->ic_header.h_chksum = cpu_to_be32(chksum); + INT_SET(iclog->ic_header.h_chksum, ARCH_CONVERT, chksum); } #else #define xlog_pack_data_checksum(log, iclog, size) @@ -3332,7 +3341,7 @@ xlog_pack_data( { int i, j, k; int size = iclog->ic_offset + roundoff; - __be32 cycle_lsn; + uint cycle_lsn; xfs_caddr_t dp; xlog_in_core_2_t *xhdr; @@ -3343,8 +3352,8 @@ xlog_pack_data( dp = iclog->ic_datap; for (i = 0; i < BTOBB(size) && i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) { - iclog->ic_header.h_cycle_data[i] = *(__be32 *)dp; - *(__be32 *)dp = cycle_lsn; + iclog->ic_header.h_cycle_data[i] = *(uint *)dp; + *(uint *)dp = cycle_lsn; dp += BBSIZE; } @@ -3353,8 +3362,8 @@ xlog_pack_data( for ( ; i < BTOBB(size); i++) { j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - xhdr[j].hic_xheader.xh_cycle_data[k] = *(__be32 *)dp; - *(__be32 *)dp = cycle_lsn; + xhdr[j].hic_xheader.xh_cycle_data[k] = *(uint *)dp; + *(uint *)dp = cycle_lsn; dp += BBSIZE; } @@ -3371,21 +3380,21 @@ xlog_unpack_data_checksum( xfs_caddr_t dp, xlog_t *log) { - __be32 *up = (__be32 *)dp; + uint *up = (uint *)dp; uint chksum = 0; int i; /* divide length by 4 to get # words */ - for (i=0; i < be32_to_cpu(rhead->h_len) >> 2; i++) { - chksum ^= be32_to_cpu(*up); + for (i=0; i < INT_GET(rhead->h_len, ARCH_CONVERT) >> 2; i++) { + chksum ^= INT_GET(*up, ARCH_CONVERT); up++; } - if (chksum != be32_to_cpu(rhead->h_chksum)) { + if (chksum != INT_GET(rhead->h_chksum, ARCH_CONVERT)) { if (rhead->h_chksum || ((log->l_flags & XLOG_CHKSUM_MISMATCH) == 0)) { cmn_err(CE_DEBUG, "XFS: LogR chksum mismatch: was (0x%x) is (0x%x)\n", - be32_to_cpu(rhead->h_chksum), chksum); + INT_GET(rhead->h_chksum, ARCH_CONVERT), chksum); cmn_err(CE_DEBUG, "XFS: Disregard message if filesystem was created with non-DEBUG kernel"); if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { @@ -3409,18 +3418,18 @@ xlog_unpack_data( int i, j, k; xlog_in_core_2_t *xhdr; - for (i = 0; i < BTOBB(be32_to_cpu(rhead->h_len)) && + for (i = 0; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)) && i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) { - *(__be32 *)dp = *(__be32 *)&rhead->h_cycle_data[i]; + *(uint *)dp = *(uint *)&rhead->h_cycle_data[i]; dp += BBSIZE; } if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { xhdr = (xlog_in_core_2_t *)rhead; - for ( ; i < BTOBB(be32_to_cpu(rhead->h_len)); i++) { + for ( ; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); i++) { j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - *(__be32 *)dp = xhdr[j].hic_xheader.xh_cycle_data[k]; + *(uint *)dp = xhdr[j].hic_xheader.xh_cycle_data[k]; dp += BBSIZE; } } @@ -3436,21 +3445,24 @@ xlog_valid_rec_header( { int hlen; - if (unlikely(be32_to_cpu(rhead->h_magicno) != XLOG_HEADER_MAGIC_NUM)) { + if (unlikely( + (INT_GET(rhead->h_magicno, ARCH_CONVERT) != + XLOG_HEADER_MAGIC_NUM))) { XFS_ERROR_REPORT("xlog_valid_rec_header(1)", XFS_ERRLEVEL_LOW, log->l_mp); return XFS_ERROR(EFSCORRUPTED); } if (unlikely( (!rhead->h_version || - (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS))))) { + (INT_GET(rhead->h_version, ARCH_CONVERT) & + (~XLOG_VERSION_OKBITS)) != 0))) { xlog_warn("XFS: %s: unrecognised log version (%d).", - __FUNCTION__, be32_to_cpu(rhead->h_version)); + __FUNCTION__, INT_GET(rhead->h_version, ARCH_CONVERT)); return XFS_ERROR(EIO); } /* LR body must have data or it wouldn't have been written */ - hlen = be32_to_cpu(rhead->h_len); + hlen = INT_GET(rhead->h_len, ARCH_CONVERT); if (unlikely( hlen <= 0 || hlen > INT_MAX )) { XFS_ERROR_REPORT("xlog_valid_rec_header(2)", XFS_ERRLEVEL_LOW, log->l_mp); @@ -3510,8 +3522,9 @@ xlog_do_recovery_pass( error = xlog_valid_rec_header(log, rhead, tail_blk); if (error) goto bread_err1; - h_size = be32_to_cpu(rhead->h_size); - if ((be32_to_cpu(rhead->h_version) & XLOG_VERSION_2) && + h_size = INT_GET(rhead->h_size, ARCH_CONVERT); + if ((INT_GET(rhead->h_version, ARCH_CONVERT) + & XLOG_VERSION_2) && (h_size > XLOG_HEADER_CYCLE_SIZE)) { hblks = h_size / XLOG_HEADER_CYCLE_SIZE; if (h_size % XLOG_HEADER_CYCLE_SIZE) @@ -3548,7 +3561,7 @@ xlog_do_recovery_pass( goto bread_err2; /* blocks in data section */ - bblks = (int)BTOBB(be32_to_cpu(rhead->h_len)); + bblks = (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); error = xlog_bread(log, blk_no + hblks, bblks, dbp); if (error) goto bread_err2; @@ -3623,7 +3636,7 @@ xlog_do_recovery_pass( if (error) goto bread_err2; - bblks = (int)BTOBB(be32_to_cpu(rhead->h_len)); + bblks = (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); blk_no += hblks; /* Read in data for log record */ @@ -3694,7 +3707,7 @@ xlog_do_recovery_pass( error = xlog_valid_rec_header(log, rhead, blk_no); if (error) goto bread_err2; - bblks = (int)BTOBB(be32_to_cpu(rhead->h_len)); + bblks = (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); if ((error = xlog_bread(log, blk_no+hblks, bblks, dbp))) goto bread_err2; offset = xlog_align(log, blk_no+hblks, bblks, dbp); diff --git a/trunk/fs/xfs/xfs_mount.c b/trunk/fs/xfs/xfs_mount.c index 6409b3762995..ebdb76da527c 100644 --- a/trunk/fs/xfs/xfs_mount.c +++ b/trunk/fs/xfs/xfs_mount.c @@ -136,9 +136,15 @@ xfs_mount_init(void) mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB; } - spin_lock_init(&mp->m_sb_lock); + AIL_LOCKINIT(&mp->m_ail_lock, "xfs_ail"); + spinlock_init(&mp->m_sb_lock, "xfs_sb"); mutex_init(&mp->m_ilock); mutex_init(&mp->m_growlock); + /* + * Initialize the AIL. + */ + xfs_trans_ail_init(mp); + atomic_set(&mp->m_active_trans, 0); return mp; @@ -165,7 +171,7 @@ xfs_mount_free( sizeof(xfs_perag_t) * mp->m_sb.sb_agcount); } - spinlock_destroy(&mp->m_ail_lock); + AIL_LOCK_DESTROY(&mp->m_ail_lock); spinlock_destroy(&mp->m_sb_lock); mutex_destroy(&mp->m_ilock); mutex_destroy(&mp->m_growlock); @@ -610,7 +616,7 @@ xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp) int i; mp->m_agfrotor = mp->m_agirotor = 0; - spin_lock_init(&mp->m_agirotor_lock); + spinlock_init(&mp->m_agirotor_lock, "m_agirotor_lock"); mp->m_maxagi = mp->m_sb.sb_agcount; mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG; mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT; @@ -690,6 +696,7 @@ xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount) uint64_t bfreelst = 0; uint64_t btree = 0; int error; + int s; for (index = 0; index < agcount; index++) { /* @@ -714,11 +721,11 @@ xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount) /* * Overwrite incore superblock counters with just-read data */ - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); sbp->sb_ifree = ifree; sbp->sb_icount = ialloc; sbp->sb_fdblocks = bfree + bfreelst + btree; - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); /* Fixup the per-cpu counters as well. */ xfs_icsb_reinit_counters(mp); @@ -727,13 +734,49 @@ xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount) } /* - * Update alignment values based on mount options and sb values + * xfs_mountfs + * + * This function does the following on an initial mount of a file system: + * - reads the superblock from disk and init the mount struct + * - if we're a 32-bit kernel, do a size check on the superblock + * so we don't mount terabyte filesystems + * - init mount struct realtime fields + * - allocate inode hash table for fs + * - init directory manager + * - perform recovery and init the log manager */ -STATIC int -xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags) +int +xfs_mountfs( + xfs_mount_t *mp, + int mfsi_flags) { + xfs_buf_t *bp; xfs_sb_t *sbp = &(mp->m_sb); + xfs_inode_t *rip; + bhv_vnode_t *rvp = NULL; + int readio_log, writeio_log; + xfs_daddr_t d; + __uint64_t resblks; + __int64_t update_flags; + uint quotamount, quotaflags; + int agno; + int uuid_mounted = 0; + int error = 0; + if (mp->m_sb_bp == NULL) { + if ((error = xfs_readsb(mp, mfsi_flags))) { + return error; + } + } + xfs_mount_common(mp, sbp); + + /* + * Check if sb_agblocks is aligned at stripe boundary + * If sb_agblocks is NOT aligned turn off m_dalign since + * allocator alignment is within an ag, therefore ag has + * to be aligned at stripe boundary. + */ + update_flags = 0LL; if (mp->m_dalign && !(mfsi_flags & XFS_MFSI_SECOND)) { /* * If stripe unit and stripe width are not multiples @@ -744,7 +787,8 @@ xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags) if (mp->m_flags & XFS_MOUNT_RETERR) { cmn_err(CE_WARN, "XFS: alignment check 1 failed"); - return XFS_ERROR(EINVAL); + error = XFS_ERROR(EINVAL); + goto error1; } mp->m_dalign = mp->m_swidth = 0; } else { @@ -754,7 +798,8 @@ xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags) mp->m_dalign = XFS_BB_TO_FSBT(mp, mp->m_dalign); if (mp->m_dalign && (sbp->sb_agblocks % mp->m_dalign)) { if (mp->m_flags & XFS_MOUNT_RETERR) { - return XFS_ERROR(EINVAL); + error = XFS_ERROR(EINVAL); + goto error1; } xfs_fs_cmn_err(CE_WARN, mp, "stripe alignment turned off: sunit(%d)/swidth(%d) incompatible with agsize(%d)", @@ -771,7 +816,8 @@ xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags) "stripe alignment turned off: sunit(%d) less than bsize(%d)", mp->m_dalign, mp->m_blockmask +1); - return XFS_ERROR(EINVAL); + error = XFS_ERROR(EINVAL); + goto error1; } mp->m_swidth = 0; } @@ -784,11 +830,11 @@ xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags) if (XFS_SB_VERSION_HASDALIGN(sbp)) { if (sbp->sb_unit != mp->m_dalign) { sbp->sb_unit = mp->m_dalign; - *update_flags |= XFS_SB_UNIT; + update_flags |= XFS_SB_UNIT; } if (sbp->sb_width != mp->m_swidth) { sbp->sb_width = mp->m_swidth; - *update_flags |= XFS_SB_WIDTH; + update_flags |= XFS_SB_WIDTH; } } } else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN && @@ -797,45 +843,49 @@ xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags) mp->m_swidth = sbp->sb_width; } - return 0; -} - -/* - * Set the maximum inode count for this filesystem - */ -STATIC void -xfs_set_maxicount(xfs_mount_t *mp) -{ - xfs_sb_t *sbp = &(mp->m_sb); - __uint64_t icount; + xfs_alloc_compute_maxlevels(mp); + xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK); + xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK); + xfs_ialloc_compute_maxlevels(mp); if (sbp->sb_imax_pct) { - /* - * Make sure the maximum inode count is a multiple - * of the units we allocate inodes in. + __uint64_t icount; + + /* Make sure the maximum inode count is a multiple of the + * units we allocate inodes in. */ + icount = sbp->sb_dblocks * sbp->sb_imax_pct; do_div(icount, 100); do_div(icount, mp->m_ialloc_blks); mp->m_maxicount = (icount * mp->m_ialloc_blks) << sbp->sb_inopblog; - } else { + } else mp->m_maxicount = 0; - } -} -/* - * Set the default minimum read and write sizes unless - * already specified in a mount option. - * We use smaller I/O sizes when the file system - * is being used for NFS service (wsync mount option). - */ -STATIC void -xfs_set_rw_sizes(xfs_mount_t *mp) -{ - xfs_sb_t *sbp = &(mp->m_sb); - int readio_log, writeio_log; + mp->m_maxioffset = xfs_max_file_offset(sbp->sb_blocklog); + /* + * XFS uses the uuid from the superblock as the unique + * identifier for fsid. We can not use the uuid from the volume + * since a single partition filesystem is identical to a single + * partition volume/filesystem. + */ + if ((mfsi_flags & XFS_MFSI_SECOND) == 0 && + (mp->m_flags & XFS_MOUNT_NOUUID) == 0) { + if (xfs_uuid_mount(mp)) { + error = XFS_ERROR(EINVAL); + goto error1; + } + uuid_mounted=1; + } + + /* + * Set the default minimum read and write sizes unless + * already specified in a mount option. + * We use smaller I/O sizes when the file system + * is being used for NFS service (wsync mount option). + */ if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)) { if (mp->m_flags & XFS_MOUNT_WSYNC) { readio_log = XFS_WSYNC_READIO_LOG; @@ -861,14 +911,17 @@ xfs_set_rw_sizes(xfs_mount_t *mp) mp->m_writeio_log = writeio_log; } mp->m_writeio_blocks = 1 << (mp->m_writeio_log - sbp->sb_blocklog); -} -/* - * Set whether we're using inode alignment. - */ -STATIC void -xfs_set_inoalignment(xfs_mount_t *mp) -{ + /* + * Set the inode cluster size. + * This may still be overridden by the file system + * block size if it is larger than the chosen cluster size. + */ + mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; + + /* + * Set whether we're using inode alignment. + */ if (XFS_SB_VERSION_HASALIGN(&mp->m_sb) && mp->m_sb.sb_inoalignmt >= XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) @@ -884,22 +937,14 @@ xfs_set_inoalignment(xfs_mount_t *mp) mp->m_sinoalign = mp->m_dalign; else mp->m_sinoalign = 0; -} - -/* - * Check that the data (and log if separate) are an ok size. - */ -STATIC int -xfs_check_sizes(xfs_mount_t *mp, int mfsi_flags) -{ - xfs_buf_t *bp; - xfs_daddr_t d; - int error; - + /* + * Check that the data (and log if separate) are an ok size. + */ d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks); if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) { cmn_err(CE_WARN, "XFS: size check 1 failed"); - return XFS_ERROR(E2BIG); + error = XFS_ERROR(E2BIG); + goto error1; } error = xfs_read_buf(mp, mp->m_ddev_targp, d - XFS_FSS_TO_BB(mp, 1), @@ -908,9 +953,10 @@ xfs_check_sizes(xfs_mount_t *mp, int mfsi_flags) xfs_buf_relse(bp); } else { cmn_err(CE_WARN, "XFS: size check 2 failed"); - if (error == ENOSPC) + if (error == ENOSPC) { error = XFS_ERROR(E2BIG); - return error; + } + goto error1; } if (((mfsi_flags & XFS_MFSI_CLIENT) == 0) && @@ -918,7 +964,8 @@ xfs_check_sizes(xfs_mount_t *mp, int mfsi_flags) d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) { cmn_err(CE_WARN, "XFS: size check 3 failed"); - return XFS_ERROR(E2BIG); + error = XFS_ERROR(E2BIG); + goto error1; } error = xfs_read_buf(mp, mp->m_logdev_targp, d - XFS_FSB_TO_BB(mp, 1), @@ -927,111 +974,17 @@ xfs_check_sizes(xfs_mount_t *mp, int mfsi_flags) xfs_buf_relse(bp); } else { cmn_err(CE_WARN, "XFS: size check 3 failed"); - if (error == ENOSPC) + if (error == ENOSPC) { error = XFS_ERROR(E2BIG); - return error; - } - } - return 0; -} - -/* - * xfs_mountfs - * - * This function does the following on an initial mount of a file system: - * - reads the superblock from disk and init the mount struct - * - if we're a 32-bit kernel, do a size check on the superblock - * so we don't mount terabyte filesystems - * - init mount struct realtime fields - * - allocate inode hash table for fs - * - init directory manager - * - perform recovery and init the log manager - */ -int -xfs_mountfs( - xfs_mount_t *mp, - int mfsi_flags) -{ - xfs_sb_t *sbp = &(mp->m_sb); - xfs_inode_t *rip; - bhv_vnode_t *rvp = NULL; - __uint64_t resblks; - __int64_t update_flags = 0LL; - uint quotamount, quotaflags; - int agno; - int uuid_mounted = 0; - int error = 0; - - if (mp->m_sb_bp == NULL) { - error = xfs_readsb(mp, mfsi_flags); - if (error) - return error; - } - xfs_mount_common(mp, sbp); - - /* - * Check if sb_agblocks is aligned at stripe boundary - * If sb_agblocks is NOT aligned turn off m_dalign since - * allocator alignment is within an ag, therefore ag has - * to be aligned at stripe boundary. - */ - error = xfs_update_alignment(mp, mfsi_flags, &update_flags); - if (error) - goto error1; - - xfs_alloc_compute_maxlevels(mp); - xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK); - xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK); - xfs_ialloc_compute_maxlevels(mp); - - xfs_set_maxicount(mp); - - mp->m_maxioffset = xfs_max_file_offset(sbp->sb_blocklog); - - /* - * XFS uses the uuid from the superblock as the unique - * identifier for fsid. We can not use the uuid from the volume - * since a single partition filesystem is identical to a single - * partition volume/filesystem. - */ - if ((mfsi_flags & XFS_MFSI_SECOND) == 0 && - (mp->m_flags & XFS_MOUNT_NOUUID) == 0) { - if (xfs_uuid_mount(mp)) { - error = XFS_ERROR(EINVAL); + } goto error1; } - uuid_mounted=1; } - /* - * Set the minimum read and write sizes - */ - xfs_set_rw_sizes(mp); - - /* - * Set the inode cluster size. - * This may still be overridden by the file system - * block size if it is larger than the chosen cluster size. - */ - mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; - - /* - * Set inode alignment fields - */ - xfs_set_inoalignment(mp); - - /* - * Check that the data (and log if separate) are an ok size. - */ - error = xfs_check_sizes(mp, mfsi_flags); - if (error) - goto error1; - /* * Initialize realtime fields in the mount structure */ - error = xfs_rtmount_init(mp); - if (error) { + if ((error = xfs_rtmount_init(mp))) { cmn_err(CE_WARN, "XFS: RT mount failed"); goto error1; } @@ -1149,8 +1102,7 @@ xfs_mountfs( /* * Initialize realtime inode pointers in the mount structure */ - error = xfs_rtmount_inodes(mp); - if (error) { + if ((error = xfs_rtmount_inodes(mp))) { /* * Free up the root inode. */ @@ -1168,8 +1120,7 @@ xfs_mountfs( /* * Initialise the XFS quota management subsystem for this mount */ - error = XFS_QM_INIT(mp, "amount, "aflags); - if (error) + if ((error = XFS_QM_INIT(mp, "amount, "aflags))) goto error4; /* @@ -1186,8 +1137,7 @@ xfs_mountfs( /* * Complete the quota initialisation, post-log-replay component. */ - error = XFS_QM_MOUNT(mp, quotamount, quotaflags, mfsi_flags); - if (error) + if ((error = XFS_QM_MOUNT(mp, quotamount, quotaflags, mfsi_flags))) goto error4; /* @@ -1305,6 +1255,7 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) #if defined(DEBUG) || defined(INDUCE_IO_ERROR) xfs_errortag_clearall(mp, 0); #endif + XFS_IODONE(mp); xfs_mount_free(mp); return 0; } @@ -1490,7 +1441,7 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields) * Fields are not allowed to dip below zero, so if the delta would * do this do not apply it and return EINVAL. * - * The m_sb_lock must be held when this routine is called. + * The SB_LOCK must be held when this routine is called. */ int xfs_mod_incore_sb_unlocked( @@ -1655,7 +1606,7 @@ xfs_mod_incore_sb_unlocked( /* * xfs_mod_incore_sb() is used to change a field in the in-core * superblock structure by the specified delta. This modification - * is protected by the m_sb_lock. Just use the xfs_mod_incore_sb_unlocked() + * is protected by the SB_LOCK. Just use the xfs_mod_incore_sb_unlocked() * routine to do the work. */ int @@ -1665,6 +1616,7 @@ xfs_mod_incore_sb( int64_t delta, int rsvd) { + unsigned long s; int status; /* check for per-cpu counters */ @@ -1681,9 +1633,9 @@ xfs_mod_incore_sb( /* FALLTHROUGH */ #endif default: - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd); - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); break; } @@ -1704,6 +1656,7 @@ xfs_mod_incore_sb( int xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd) { + unsigned long s; int status=0; xfs_mod_sb_t *msbp; @@ -1711,10 +1664,10 @@ xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd) * Loop through the array of mod structures and apply each * individually. If any fail, then back out all those * which have already been applied. Do all of this within - * the scope of the m_sb_lock so that all of the changes will + * the scope of the SB_LOCK so that all of the changes will * be atomic. */ - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); msbp = &msb[0]; for (msbp = &msbp[0]; msbp < (msb + nmsb); msbp++) { /* @@ -1728,11 +1681,11 @@ xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd) case XFS_SBS_IFREE: case XFS_SBS_FDBLOCKS: if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) { - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); status = xfs_icsb_modify_counters(mp, msbp->msb_field, msbp->msb_delta, rsvd); - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); break; } /* FALLTHROUGH */ @@ -1766,12 +1719,12 @@ xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd) case XFS_SBS_IFREE: case XFS_SBS_FDBLOCKS: if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) { - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); status = xfs_icsb_modify_counters(mp, msbp->msb_field, -(msbp->msb_delta), rsvd); - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); break; } /* FALLTHROUGH */ @@ -1787,7 +1740,7 @@ xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd) msbp--; } } - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); return status; } @@ -1935,12 +1888,12 @@ xfs_mount_log_sbunit( * * Locking rules: * - * 1. m_sb_lock before picking up per-cpu locks + * 1. XFS_SB_LOCK() before picking up per-cpu locks * 2. per-cpu locks always picked up via for_each_online_cpu() order - * 3. accurate counter sync requires m_sb_lock + per cpu locks + * 3. accurate counter sync requires XFS_SB_LOCK + per cpu locks * 4. modifying per-cpu counters requires holding per-cpu lock - * 5. modifying global counters requires holding m_sb_lock - * 6. enabling or disabling a counter requires holding the m_sb_lock + * 5. modifying global counters requires holding XFS_SB_LOCK + * 6. enabling or disabling a counter requires holding the XFS_SB_LOCK * and _none_ of the per-cpu locks. * * Disabled counters are only ever re-enabled by a balance operation @@ -1967,6 +1920,7 @@ xfs_icsb_cpu_notify( { xfs_icsb_cnts_t *cntp; xfs_mount_t *mp; + int s; mp = (xfs_mount_t *)container_of(nfb, xfs_mount_t, m_icsb_notifier); cntp = (xfs_icsb_cnts_t *) @@ -1992,7 +1946,7 @@ xfs_icsb_cpu_notify( * count into the total on the global superblock and * re-enable the counters. */ xfs_icsb_lock(mp); - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); xfs_icsb_disable_counter(mp, XFS_SBS_ICOUNT); xfs_icsb_disable_counter(mp, XFS_SBS_IFREE); xfs_icsb_disable_counter(mp, XFS_SBS_FDBLOCKS); @@ -2009,7 +1963,7 @@ xfs_icsb_cpu_notify( XFS_ICSB_SB_LOCKED, 0); xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, XFS_ICSB_SB_LOCKED, 0); - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); xfs_icsb_unlock(mp); break; } @@ -2240,10 +2194,11 @@ xfs_icsb_sync_counters_flags( int flags) { xfs_icsb_cnts_t cnt; + int s; /* Pass 1: lock all counters */ if ((flags & XFS_ICSB_SB_LOCKED) == 0) - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); xfs_icsb_count(mp, &cnt, flags); @@ -2256,7 +2211,7 @@ xfs_icsb_sync_counters_flags( mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks; if ((flags & XFS_ICSB_SB_LOCKED) == 0) - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); } /* @@ -2297,10 +2252,11 @@ xfs_icsb_balance_counter( { uint64_t count, resid; int weight = num_online_cpus(); + int s; uint64_t min = (uint64_t)min_per_cpu; if (!(flags & XFS_ICSB_SB_LOCKED)) - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); /* disable counter and sync counter */ xfs_icsb_disable_counter(mp, field); @@ -2334,10 +2290,10 @@ xfs_icsb_balance_counter( xfs_icsb_enable_counter(mp, field, count, resid); out: if (!(flags & XFS_ICSB_SB_LOCKED)) - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); } -STATIC int +int xfs_icsb_modify_counters( xfs_mount_t *mp, xfs_sb_field_t field, @@ -2346,7 +2302,7 @@ xfs_icsb_modify_counters( { xfs_icsb_cnts_t *icsbp; long long lcounter; /* long counter for 64 bit fields */ - int cpu, ret = 0; + int cpu, ret = 0, s; might_sleep(); again: @@ -2424,15 +2380,15 @@ xfs_icsb_modify_counters( * running atomically here, we know a rebalance cannot * be in progress. Hence we can go straight to operating * on the global superblock. We do not call xfs_mod_incore_sb() - * here even though we need to get the m_sb_lock. Doing so + * here even though we need to get the SB_LOCK. Doing so * will cause us to re-enter this function and deadlock. - * Hence we get the m_sb_lock ourselves and then call + * Hence we get the SB_LOCK ourselves and then call * xfs_mod_incore_sb_unlocked() as the unlocked path operates * directly on the global counters. */ - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); ret = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd); - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); /* * Now that we've modified the global superblock, we diff --git a/trunk/fs/xfs/xfs_mount.h b/trunk/fs/xfs/xfs_mount.h index f7c620ec6e69..c618f7cb5f0e 100644 --- a/trunk/fs/xfs/xfs_mount.h +++ b/trunk/fs/xfs/xfs_mount.h @@ -56,12 +56,20 @@ struct cred; struct log; struct xfs_mount_args; struct xfs_inode; +struct xfs_iocore; struct xfs_bmbt_irec; struct xfs_bmap_free; struct xfs_extdelta; struct xfs_swapext; struct xfs_mru_cache; +#define AIL_LOCK_T lock_t +#define AIL_LOCKINIT(x,y) spinlock_init(x,y) +#define AIL_LOCK_DESTROY(x) spinlock_destroy(x) +#define AIL_LOCK(mp,s) s=mutex_spinlock(&(mp)->m_ail_lock) +#define AIL_UNLOCK(mp,s) mutex_spinunlock(&(mp)->m_ail_lock, s) + + /* * Prototypes and functions for the Data Migration subsystem. */ @@ -188,6 +196,105 @@ typedef struct xfs_qmops { #define XFS_QM_QUOTACTL(mp, cmd, id, addr) \ (*(mp)->m_qm_ops->xfs_quotactl)(mp, cmd, id, addr) + +/* + * Prototypes and functions for I/O core modularization. + */ + +typedef int (*xfs_ioinit_t)(struct xfs_mount *, + struct xfs_mount_args *, int); +typedef int (*xfs_bmapi_t)(struct xfs_trans *, void *, + xfs_fileoff_t, xfs_filblks_t, int, + xfs_fsblock_t *, xfs_extlen_t, + struct xfs_bmbt_irec *, int *, + struct xfs_bmap_free *, struct xfs_extdelta *); +typedef int (*xfs_bunmapi_t)(struct xfs_trans *, + void *, xfs_fileoff_t, + xfs_filblks_t, int, xfs_extnum_t, + xfs_fsblock_t *, struct xfs_bmap_free *, + struct xfs_extdelta *, int *); +typedef int (*xfs_bmap_eof_t)(void *, xfs_fileoff_t, int, int *); +typedef int (*xfs_iomap_write_direct_t)( + void *, xfs_off_t, size_t, int, + struct xfs_bmbt_irec *, int *, int); +typedef int (*xfs_iomap_write_delay_t)( + void *, xfs_off_t, size_t, int, + struct xfs_bmbt_irec *, int *); +typedef int (*xfs_iomap_write_allocate_t)( + void *, xfs_off_t, size_t, + struct xfs_bmbt_irec *, int *); +typedef int (*xfs_iomap_write_unwritten_t)( + void *, xfs_off_t, size_t); +typedef uint (*xfs_lck_map_shared_t)(void *); +typedef void (*xfs_lock_t)(void *, uint); +typedef void (*xfs_lock_demote_t)(void *, uint); +typedef int (*xfs_lock_nowait_t)(void *, uint); +typedef void (*xfs_unlk_t)(void *, unsigned int); +typedef xfs_fsize_t (*xfs_size_t)(void *); +typedef xfs_fsize_t (*xfs_iodone_t)(struct xfs_mount *); +typedef int (*xfs_swap_extents_t)(void *, void *, + struct xfs_swapext*); + +typedef struct xfs_ioops { + xfs_ioinit_t xfs_ioinit; + xfs_bmapi_t xfs_bmapi_func; + xfs_bunmapi_t xfs_bunmapi_func; + xfs_bmap_eof_t xfs_bmap_eof_func; + xfs_iomap_write_direct_t xfs_iomap_write_direct; + xfs_iomap_write_delay_t xfs_iomap_write_delay; + xfs_iomap_write_allocate_t xfs_iomap_write_allocate; + xfs_iomap_write_unwritten_t xfs_iomap_write_unwritten; + xfs_lock_t xfs_ilock; + xfs_lck_map_shared_t xfs_lck_map_shared; + xfs_lock_demote_t xfs_ilock_demote; + xfs_lock_nowait_t xfs_ilock_nowait; + xfs_unlk_t xfs_unlock; + xfs_size_t xfs_size_func; + xfs_iodone_t xfs_iodone; + xfs_swap_extents_t xfs_swap_extents_func; +} xfs_ioops_t; + +#define XFS_IOINIT(mp, args, flags) \ + (*(mp)->m_io_ops.xfs_ioinit)(mp, args, flags) +#define XFS_BMAPI(mp, trans,io,bno,len,f,first,tot,mval,nmap,flist,delta) \ + (*(mp)->m_io_ops.xfs_bmapi_func) \ + (trans,(io)->io_obj,bno,len,f,first,tot,mval,nmap,flist,delta) +#define XFS_BUNMAPI(mp, trans,io,bno,len,f,nexts,first,flist,delta,done) \ + (*(mp)->m_io_ops.xfs_bunmapi_func) \ + (trans,(io)->io_obj,bno,len,f,nexts,first,flist,delta,done) +#define XFS_BMAP_EOF(mp, io, endoff, whichfork, eof) \ + (*(mp)->m_io_ops.xfs_bmap_eof_func) \ + ((io)->io_obj, endoff, whichfork, eof) +#define XFS_IOMAP_WRITE_DIRECT(mp, io, offset, count, flags, mval, nmap, found)\ + (*(mp)->m_io_ops.xfs_iomap_write_direct) \ + ((io)->io_obj, offset, count, flags, mval, nmap, found) +#define XFS_IOMAP_WRITE_DELAY(mp, io, offset, count, flags, mval, nmap) \ + (*(mp)->m_io_ops.xfs_iomap_write_delay) \ + ((io)->io_obj, offset, count, flags, mval, nmap) +#define XFS_IOMAP_WRITE_ALLOCATE(mp, io, offset, count, mval, nmap) \ + (*(mp)->m_io_ops.xfs_iomap_write_allocate) \ + ((io)->io_obj, offset, count, mval, nmap) +#define XFS_IOMAP_WRITE_UNWRITTEN(mp, io, offset, count) \ + (*(mp)->m_io_ops.xfs_iomap_write_unwritten) \ + ((io)->io_obj, offset, count) +#define XFS_LCK_MAP_SHARED(mp, io) \ + (*(mp)->m_io_ops.xfs_lck_map_shared)((io)->io_obj) +#define XFS_ILOCK(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_ilock)((io)->io_obj, mode) +#define XFS_ILOCK_NOWAIT(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_ilock_nowait)((io)->io_obj, mode) +#define XFS_IUNLOCK(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_unlock)((io)->io_obj, mode) +#define XFS_ILOCK_DEMOTE(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_ilock_demote)((io)->io_obj, mode) +#define XFS_SIZE(mp, io) \ + (*(mp)->m_io_ops.xfs_size_func)((io)->io_obj) +#define XFS_IODONE(mp) \ + (*(mp)->m_io_ops.xfs_iodone)(mp) +#define XFS_SWAP_EXTENTS(mp, io, tio, sxp) \ + (*(mp)->m_io_ops.xfs_swap_extents_func) \ + ((io)->io_obj, (tio)->io_obj, sxp) + #ifdef HAVE_PERCPU_SB /* @@ -219,20 +326,14 @@ extern void xfs_icsb_sync_counters_flags(struct xfs_mount *, int); #define xfs_icsb_sync_counters_flags(mp, flags) do { } while (0) #endif -typedef struct xfs_ail { - xfs_ail_entry_t xa_ail; - uint xa_gen; - struct task_struct *xa_task; - xfs_lsn_t xa_target; -} xfs_ail_t; - typedef struct xfs_mount { struct super_block *m_super; xfs_tid_t m_tid; /* next unused tid for fs */ - spinlock_t m_ail_lock; /* fs AIL mutex */ - xfs_ail_t m_ail; /* fs active log item list */ + AIL_LOCK_T m_ail_lock; /* fs AIL mutex */ + xfs_ail_entry_t m_ail; /* fs active log item list */ + uint m_ail_gen; /* fs AIL generation count */ xfs_sb_t m_sb; /* copy of fs superblock */ - spinlock_t m_sb_lock; /* sb counter lock */ + lock_t m_sb_lock; /* sb counter mutex */ struct xfs_buf *m_sb_bp; /* buffer for superblock */ char *m_fsname; /* filesystem name */ int m_fsname_len; /* strlen of fs name */ @@ -241,7 +342,7 @@ typedef struct xfs_mount { int m_bsize; /* fs logical block size */ xfs_agnumber_t m_agfrotor; /* last ag where space found */ xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */ - spinlock_t m_agirotor_lock;/* .. and lock protecting it */ + lock_t m_agirotor_lock;/* .. and lock protecting it */ xfs_agnumber_t m_maxagi; /* highest inode alloc group */ struct xfs_inode *m_inodes; /* active inode list */ struct list_head m_del_inodes; /* inodes to reclaim */ @@ -322,6 +423,7 @@ typedef struct xfs_mount { * hash table */ struct xfs_dmops *m_dm_ops; /* vector of DMI ops */ struct xfs_qmops *m_qm_ops; /* vector of XQM ops */ + struct xfs_ioops m_io_ops; /* vector of I/O ops */ atomic_t m_active_trans; /* number trans frozen */ #ifdef HAVE_PERCPU_SB xfs_icsb_cnts_t *m_sb_cnts; /* per-cpu superblock counters */ @@ -508,6 +610,8 @@ typedef struct xfs_mod_sb { #define XFS_MOUNT_ILOCK(mp) mutex_lock(&((mp)->m_ilock)) #define XFS_MOUNT_IUNLOCK(mp) mutex_unlock(&((mp)->m_ilock)) +#define XFS_SB_LOCK(mp) mutex_spinlock(&(mp)->m_sb_lock) +#define XFS_SB_UNLOCK(mp,s) mutex_spinunlock(&(mp)->m_sb_lock,(s)) extern xfs_mount_t *xfs_mount_init(void); extern void xfs_mod_sb(xfs_trans_t *, __int64_t); @@ -542,6 +646,7 @@ extern int xfs_qmops_get(struct xfs_mount *, struct xfs_mount_args *); extern void xfs_qmops_put(struct xfs_mount *); extern struct xfs_dmops xfs_dmcore_xfs; +extern struct xfs_ioops xfs_iocore_xfs; extern int xfs_init(void); extern void xfs_cleanup(void); diff --git a/trunk/fs/xfs/xfs_mru_cache.c b/trunk/fs/xfs/xfs_mru_cache.c index a0b2c0a2589a..e0b358c1c533 100644 --- a/trunk/fs/xfs/xfs_mru_cache.c +++ b/trunk/fs/xfs/xfs_mru_cache.c @@ -225,14 +225,10 @@ _xfs_mru_cache_list_insert( * list need to be deleted. For each element this involves removing it from the * data store, removing it from the reap list, calling the client's free * function and deleting the element from the element zone. - * - * We get called holding the mru->lock, which we drop and then reacquire. - * Sparse need special help with this to tell it we know what we are doing. */ STATIC void _xfs_mru_cache_clear_reap_list( - xfs_mru_cache_t *mru) __releases(mru->lock) __acquires(mru->lock) - + xfs_mru_cache_t *mru) { xfs_mru_cache_elem_t *elem, *next; struct list_head tmp; @@ -249,7 +245,7 @@ _xfs_mru_cache_clear_reap_list( */ list_move(&elem->list_node, &tmp); } - spin_unlock(&mru->lock); + mutex_spinunlock(&mru->lock, 0); list_for_each_entry_safe(elem, next, &tmp, list_node) { @@ -263,7 +259,7 @@ _xfs_mru_cache_clear_reap_list( kmem_zone_free(xfs_mru_elem_zone, elem); } - spin_lock(&mru->lock); + mutex_spinlock(&mru->lock); } /* @@ -284,7 +280,7 @@ _xfs_mru_cache_reap( if (!mru || !mru->lists) return; - spin_lock(&mru->lock); + mutex_spinlock(&mru->lock); next = _xfs_mru_cache_migrate(mru, jiffies); _xfs_mru_cache_clear_reap_list(mru); @@ -298,7 +294,7 @@ _xfs_mru_cache_reap( queue_delayed_work(xfs_mru_reap_wq, &mru->work, next); } - spin_unlock(&mru->lock); + mutex_spinunlock(&mru->lock, 0); } int @@ -372,7 +368,7 @@ xfs_mru_cache_create( */ INIT_RADIX_TREE(&mru->store, GFP_ATOMIC); INIT_LIST_HEAD(&mru->reap_list); - spin_lock_init(&mru->lock); + spinlock_init(&mru->lock, "xfs_mru_cache"); INIT_DELAYED_WORK(&mru->work, _xfs_mru_cache_reap); mru->grp_time = grp_time; @@ -402,17 +398,17 @@ xfs_mru_cache_flush( if (!mru || !mru->lists) return; - spin_lock(&mru->lock); + mutex_spinlock(&mru->lock); if (mru->queued) { - spin_unlock(&mru->lock); + mutex_spinunlock(&mru->lock, 0); cancel_rearming_delayed_workqueue(xfs_mru_reap_wq, &mru->work); - spin_lock(&mru->lock); + mutex_spinlock(&mru->lock); } _xfs_mru_cache_migrate(mru, jiffies + mru->grp_count * mru->grp_time); _xfs_mru_cache_clear_reap_list(mru); - spin_unlock(&mru->lock); + mutex_spinunlock(&mru->lock, 0); } void @@ -458,13 +454,13 @@ xfs_mru_cache_insert( elem->key = key; elem->value = value; - spin_lock(&mru->lock); + mutex_spinlock(&mru->lock); radix_tree_insert(&mru->store, key, elem); radix_tree_preload_end(); _xfs_mru_cache_list_insert(mru, elem); - spin_unlock(&mru->lock); + mutex_spinunlock(&mru->lock, 0); return 0; } @@ -487,14 +483,14 @@ xfs_mru_cache_remove( if (!mru || !mru->lists) return NULL; - spin_lock(&mru->lock); + mutex_spinlock(&mru->lock); elem = radix_tree_delete(&mru->store, key); if (elem) { value = elem->value; list_del(&elem->list_node); } - spin_unlock(&mru->lock); + mutex_spinunlock(&mru->lock, 0); if (elem) kmem_zone_free(xfs_mru_elem_zone, elem); @@ -532,10 +528,6 @@ xfs_mru_cache_delete( * * If the element isn't found, this function returns NULL and the spinlock is * released. xfs_mru_cache_done() should NOT be called when this occurs. - * - * Because sparse isn't smart enough to know about conditional lock return - * status, we need to help it get it right by annotating the path that does - * not release the lock. */ void * xfs_mru_cache_lookup( @@ -548,14 +540,14 @@ xfs_mru_cache_lookup( if (!mru || !mru->lists) return NULL; - spin_lock(&mru->lock); + mutex_spinlock(&mru->lock); elem = radix_tree_lookup(&mru->store, key); if (elem) { list_del(&elem->list_node); _xfs_mru_cache_list_insert(mru, elem); - __release(mru_lock); /* help sparse not be stupid */ - } else - spin_unlock(&mru->lock); + } + else + mutex_spinunlock(&mru->lock, 0); return elem ? elem->value : NULL; } @@ -579,12 +571,10 @@ xfs_mru_cache_peek( if (!mru || !mru->lists) return NULL; - spin_lock(&mru->lock); + mutex_spinlock(&mru->lock); elem = radix_tree_lookup(&mru->store, key); if (!elem) - spin_unlock(&mru->lock); - else - __release(mru_lock); /* help sparse not be stupid */ + mutex_spinunlock(&mru->lock, 0); return elem ? elem->value : NULL; } @@ -596,7 +586,7 @@ xfs_mru_cache_peek( */ void xfs_mru_cache_done( - xfs_mru_cache_t *mru) __releases(mru->lock) + xfs_mru_cache_t *mru) { - spin_unlock(&mru->lock); + mutex_spinunlock(&mru->lock, 0); } diff --git a/trunk/fs/xfs/xfs_qmops.c b/trunk/fs/xfs/xfs_qmops.c index a294e58db8dd..2ec1d8a27352 100644 --- a/trunk/fs/xfs/xfs_qmops.c +++ b/trunk/fs/xfs/xfs_qmops.c @@ -49,17 +49,18 @@ xfs_mount_reset_sbqflags(xfs_mount_t *mp) { int error; xfs_trans_t *tp; + unsigned long s; mp->m_qflags = 0; /* * It is OK to look at sb_qflags here in mount path, - * without m_sb_lock. + * without SB_LOCK. */ if (mp->m_sb.sb_qflags == 0) return 0; - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); mp->m_sb.sb_qflags = 0; - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); /* * if the fs is readonly, let the incore superblock run diff --git a/trunk/fs/xfs/xfs_rename.c b/trunk/fs/xfs/xfs_rename.c index 7eb157a59f9e..44ea0ba36476 100644 --- a/trunk/fs/xfs/xfs_rename.c +++ b/trunk/fs/xfs/xfs_rename.c @@ -39,7 +39,6 @@ #include "xfs_refcache.h" #include "xfs_utils.h" #include "xfs_trans_space.h" -#include "xfs_vnodeops.h" /* @@ -119,7 +118,7 @@ xfs_lock_for_rename( inum1 = ip1->i_ino; ASSERT(ip1); - xfs_itrace_ref(ip1); + ITRACE(ip1); /* * Unlock dp1 and lock dp2 if they are different. @@ -142,7 +141,7 @@ xfs_lock_for_rename( IRELE (ip1); return error; } else { - xfs_itrace_ref(ip2); + ITRACE(ip2); } /* @@ -248,8 +247,8 @@ xfs_rename( int src_namelen = VNAMELEN(src_vname); int target_namelen = VNAMELEN(target_vname); - xfs_itrace_entry(src_dp); - xfs_itrace_entry(xfs_vtoi(target_dir_vp)); + vn_trace_entry(src_dp, "xfs_rename", (inst_t *)__return_address); + vn_trace_entry(xfs_vtoi(target_dir_vp), "xfs_rename", (inst_t *)__return_address); /* * Find the XFS behavior descriptor for the target directory diff --git a/trunk/fs/xfs/xfs_rtalloc.c b/trunk/fs/xfs/xfs_rtalloc.c index ca83ddf72af4..47082c01872d 100644 --- a/trunk/fs/xfs/xfs_rtalloc.c +++ b/trunk/fs/xfs/xfs_rtalloc.c @@ -72,6 +72,18 @@ STATIC int xfs_rtmodify_summary(xfs_mount_t *, xfs_trans_t *, int, * Internal functions. */ +/* + * xfs_lowbit32: get low bit set out of 32-bit argument, -1 if none set. + */ +STATIC int +xfs_lowbit32( + __uint32_t v) +{ + if (v) + return ffs(v) - 1; + return -1; +} + /* * Allocate space to the bitmap or summary file, and zero it, for growfs. */ @@ -432,7 +444,6 @@ xfs_rtallocate_extent_near( } bbno = XFS_BITTOBLOCK(mp, bno); i = 0; - ASSERT(minlen != 0); log2len = xfs_highbit32(minlen); /* * Loop over all bitmap blocks (bbno + i is current block). @@ -601,8 +612,6 @@ xfs_rtallocate_extent_size( xfs_suminfo_t sum; /* summary information for extents */ ASSERT(minlen % prod == 0 && maxlen % prod == 0); - ASSERT(maxlen != 0); - /* * Loop over all the levels starting with maxlen. * At each level, look at all the bitmap blocks, to see if there @@ -660,9 +669,6 @@ xfs_rtallocate_extent_size( *rtblock = NULLRTBLOCK; return 0; } - ASSERT(minlen != 0); - ASSERT(maxlen != 0); - /* * Loop over sizes, from maxlen down to minlen. * This time, when we do the allocations, allow smaller ones @@ -1948,7 +1954,6 @@ xfs_growfs_rt( nsbp->sb_blocksize * nsbp->sb_rextsize); nsbp->sb_rextents = nsbp->sb_rblocks; do_div(nsbp->sb_rextents, nsbp->sb_rextsize); - ASSERT(nsbp->sb_rextents != 0); nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents); nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1; nrsumsize = diff --git a/trunk/fs/xfs/xfs_rtalloc.h b/trunk/fs/xfs/xfs_rtalloc.h index 8d8dcd215716..799c1f871263 100644 --- a/trunk/fs/xfs/xfs_rtalloc.h +++ b/trunk/fs/xfs/xfs_rtalloc.h @@ -21,6 +21,8 @@ struct xfs_mount; struct xfs_trans; +#define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) + /* Min and max rt extent sizes, specified in bytes */ #define XFS_MAX_RTEXTSIZE (1024 * 1024 * 1024) /* 1GB */ #define XFS_DFL_RTEXTSIZE (64 * 1024) /* 64KB */ diff --git a/trunk/fs/xfs/xfs_rw.h b/trunk/fs/xfs/xfs_rw.h index f87db5344ce6..49875e1d129f 100644 --- a/trunk/fs/xfs/xfs_rw.h +++ b/trunk/fs/xfs/xfs_rw.h @@ -32,10 +32,18 @@ struct xfs_mount; static inline xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb) { - return (XFS_IS_REALTIME_INODE(ip) ? \ + return (((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) ? \ (xfs_daddr_t)XFS_FSB_TO_BB((ip)->i_mount, (fsb)) : \ XFS_FSB_TO_DADDR((ip)->i_mount, (fsb))); } +#define XFS_FSB_TO_DB_IO(io,fsb) xfs_fsb_to_db_io(io,fsb) +static inline xfs_daddr_t +xfs_fsb_to_db_io(struct xfs_iocore *io, xfs_fsblock_t fsb) +{ + return (((io)->io_flags & XFS_IOCORE_RT) ? \ + XFS_FSB_TO_BB((io)->io_mount, (fsb)) : \ + XFS_FSB_TO_DADDR((io)->io_mount, (fsb))); +} /* * Flags for xfs_free_eofblocks @@ -53,7 +61,7 @@ xfs_get_extsz_hint( { xfs_extlen_t extsz; - if (unlikely(XFS_IS_REALTIME_INODE(ip))) { + if (unlikely(ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { extsz = (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) ? ip->i_d.di_extsize : ip->i_mount->m_sb.sb_rextsize; diff --git a/trunk/fs/xfs/xfs_trans.c b/trunk/fs/xfs/xfs_trans.c index 71e4c8dcc69b..8878322ee793 100644 --- a/trunk/fs/xfs/xfs_trans.c +++ b/trunk/fs/xfs/xfs_trans.c @@ -1322,6 +1322,7 @@ xfs_trans_chunk_committed( xfs_lsn_t item_lsn; struct xfs_mount *mp; int i; + SPLDECL(s); lidp = licp->lic_descs; for (i = 0; i < licp->lic_unused; i++, lidp++) { @@ -1362,7 +1363,7 @@ xfs_trans_chunk_committed( * the test below. */ mp = lip->li_mountp; - spin_lock(&mp->m_ail_lock); + AIL_LOCK(mp,s); if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) { /* * This will set the item's lsn to item_lsn @@ -1371,9 +1372,9 @@ xfs_trans_chunk_committed( * * xfs_trans_update_ail() drops the AIL lock. */ - xfs_trans_update_ail(mp, lip, item_lsn); + xfs_trans_update_ail(mp, lip, item_lsn, s); } else { - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); } /* diff --git a/trunk/fs/xfs/xfs_trans.h b/trunk/fs/xfs/xfs_trans.h index 7f40628d85c7..0e26e729023e 100644 --- a/trunk/fs/xfs/xfs_trans.h +++ b/trunk/fs/xfs/xfs_trans.h @@ -992,9 +992,8 @@ int _xfs_trans_commit(xfs_trans_t *, int *); #define xfs_trans_commit(tp, flags) _xfs_trans_commit(tp, flags, NULL) void xfs_trans_cancel(xfs_trans_t *, int); -int xfs_trans_ail_init(struct xfs_mount *); -void xfs_trans_ail_destroy(struct xfs_mount *); -void xfs_trans_push_ail(struct xfs_mount *, xfs_lsn_t); +void xfs_trans_ail_init(struct xfs_mount *); +xfs_lsn_t xfs_trans_push_ail(struct xfs_mount *, xfs_lsn_t); xfs_lsn_t xfs_trans_tail_ail(struct xfs_mount *); void xfs_trans_unlocked_item(struct xfs_mount *, xfs_log_item_t *); @@ -1002,8 +1001,6 @@ xfs_log_busy_slot_t *xfs_trans_add_busy(xfs_trans_t *tp, xfs_agnumber_t ag, xfs_extlen_t idx); -extern kmem_zone_t *xfs_trans_zone; - #endif /* __KERNEL__ */ #endif /* __XFS_TRANS_H__ */ diff --git a/trunk/fs/xfs/xfs_trans_ail.c b/trunk/fs/xfs/xfs_trans_ail.c index 4d6330eddc8d..5b2ff59f19cf 100644 --- a/trunk/fs/xfs/xfs_trans_ail.c +++ b/trunk/fs/xfs/xfs_trans_ail.c @@ -34,9 +34,9 @@ STATIC xfs_log_item_t * xfs_ail_min(xfs_ail_entry_t *); STATIC xfs_log_item_t * xfs_ail_next(xfs_ail_entry_t *, xfs_log_item_t *); #ifdef DEBUG -STATIC void xfs_ail_check(xfs_ail_entry_t *, xfs_log_item_t *); +STATIC void xfs_ail_check(xfs_ail_entry_t *); #else -#define xfs_ail_check(a,l) +#define xfs_ail_check(a) #endif /* DEBUG */ @@ -55,15 +55,16 @@ xfs_trans_tail_ail( { xfs_lsn_t lsn; xfs_log_item_t *lip; + SPLDECL(s); - spin_lock(&mp->m_ail_lock); - lip = xfs_ail_min(&(mp->m_ail.xa_ail)); + AIL_LOCK(mp,s); + lip = xfs_ail_min(&(mp->m_ail)); if (lip == NULL) { lsn = (xfs_lsn_t)0; } else { lsn = lip->li_lsn; } - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); return lsn; } @@ -71,185 +72,120 @@ xfs_trans_tail_ail( /* * xfs_trans_push_ail * - * This routine is called to move the tail of the AIL forward. It does this by - * trying to flush items in the AIL whose lsns are below the given - * threshold_lsn. + * This routine is called to move the tail of the AIL + * forward. It does this by trying to flush items in the AIL + * whose lsns are below the given threshold_lsn. * - * the push is run asynchronously in a separate thread, so we return the tail - * of the log right now instead of the tail after the push. This means we will - * either continue right away, or we will sleep waiting on the async thread to - * do it's work. - * - * We do this unlocked - we only need to know whether there is anything in the - * AIL at the time we are called. We don't need to access the contents of - * any of the objects, so the lock is not needed. + * The routine returns the lsn of the tail of the log. */ -void +xfs_lsn_t xfs_trans_push_ail( xfs_mount_t *mp, xfs_lsn_t threshold_lsn) { + xfs_lsn_t lsn; xfs_log_item_t *lip; + int gen; + int restarts; + int lock_result; + int flush_log; + SPLDECL(s); - lip = xfs_ail_min(&mp->m_ail.xa_ail); - if (lip && !XFS_FORCED_SHUTDOWN(mp)) { - if (XFS_LSN_CMP(threshold_lsn, mp->m_ail.xa_target) > 0) - xfsaild_wakeup(mp, threshold_lsn); - } -} - -/* - * Return the item in the AIL with the current lsn. - * Return the current tree generation number for use - * in calls to xfs_trans_next_ail(). - */ -STATIC xfs_log_item_t * -xfs_trans_first_push_ail( - xfs_mount_t *mp, - int *gen, - xfs_lsn_t lsn) -{ - xfs_log_item_t *lip; - - lip = xfs_ail_min(&(mp->m_ail.xa_ail)); - *gen = (int)mp->m_ail.xa_gen; - if (lsn == 0) - return lip; - - while (lip && (XFS_LSN_CMP(lip->li_lsn, lsn) < 0)) - lip = lip->li_ail.ail_forw; +#define XFS_TRANS_PUSH_AIL_RESTARTS 1000 - return lip; -} - -/* - * Function that does the work of pushing on the AIL - */ -long -xfsaild_push( - xfs_mount_t *mp, - xfs_lsn_t *last_lsn) -{ - long tout = 1000; /* milliseconds */ - xfs_lsn_t last_pushed_lsn = *last_lsn; - xfs_lsn_t target = mp->m_ail.xa_target; - xfs_lsn_t lsn; - xfs_log_item_t *lip; - int gen; - int restarts; - int flush_log, count, stuck; - -#define XFS_TRANS_PUSH_AIL_RESTARTS 10 - - spin_lock(&mp->m_ail_lock); - lip = xfs_trans_first_push_ail(mp, &gen, *last_lsn); - if (!lip || XFS_FORCED_SHUTDOWN(mp)) { + AIL_LOCK(mp,s); + lip = xfs_trans_first_ail(mp, &gen); + if (lip == NULL || XFS_FORCED_SHUTDOWN(mp)) { /* - * AIL is empty or our push has reached the end. + * Just return if the AIL is empty. */ - spin_unlock(&mp->m_ail_lock); - last_pushed_lsn = 0; - goto out; + AIL_UNLOCK(mp, s); + return (xfs_lsn_t)0; } XFS_STATS_INC(xs_push_ail); /* * While the item we are looking at is below the given threshold - * try to flush it out. We'd like not to stop until we've at least + * try to flush it out. Make sure to limit the number of times + * we allow xfs_trans_next_ail() to restart scanning from the + * beginning of the list. We'd like not to stop until we've at least * tried to push on everything in the AIL with an LSN less than - * the given threshold. - * - * However, we will stop after a certain number of pushes and wait - * for a reduced timeout to fire before pushing further. This - * prevents use from spinning when we can't do anything or there is - * lots of contention on the AIL lists. + * the given threshold. However, we may give up before that if + * we realize that we've been holding the AIL_LOCK for 'too long', + * blocking interrupts. Currently, too long is < 500us roughly. */ - tout = 10; - lsn = lip->li_lsn; - flush_log = stuck = count = restarts = 0; - while ((XFS_LSN_CMP(lip->li_lsn, target) < 0)) { - int lock_result; + flush_log = 0; + restarts = 0; + while (((restarts < XFS_TRANS_PUSH_AIL_RESTARTS) && + (XFS_LSN_CMP(lip->li_lsn, threshold_lsn) < 0))) { /* - * If we can lock the item without sleeping, unlock the AIL - * lock and flush the item. Then re-grab the AIL lock so we - * can look for the next item on the AIL. List changes are - * handled by the AIL lookup functions internally + * If we can lock the item without sleeping, unlock + * the AIL lock and flush the item. Then re-grab the + * AIL lock so we can look for the next item on the + * AIL. Since we unlock the AIL while we flush the + * item, the next routine may start over again at the + * the beginning of the list if anything has changed. + * That is what the generation count is for. * - * If we can't lock the item, either its holder will flush it - * or it is already being flushed or it is being relogged. In - * any of these case it is being taken care of and we can just - * skip to the next item in the list. + * If we can't lock the item, either its holder will flush + * it or it is already being flushed or it is being relogged. + * In any of these case it is being taken care of and we + * can just skip to the next item in the list. */ lock_result = IOP_TRYLOCK(lip); - spin_unlock(&mp->m_ail_lock); switch (lock_result) { - case XFS_ITEM_SUCCESS: + case XFS_ITEM_SUCCESS: + AIL_UNLOCK(mp, s); XFS_STATS_INC(xs_push_ail_success); IOP_PUSH(lip); - last_pushed_lsn = lsn; + AIL_LOCK(mp,s); break; - case XFS_ITEM_PUSHBUF: + case XFS_ITEM_PUSHBUF: + AIL_UNLOCK(mp, s); XFS_STATS_INC(xs_push_ail_pushbuf); +#ifdef XFSRACEDEBUG + delay_for_intr(); + delay(300); +#endif + ASSERT(lip->li_ops->iop_pushbuf); + ASSERT(lip); IOP_PUSHBUF(lip); - last_pushed_lsn = lsn; + AIL_LOCK(mp,s); break; - case XFS_ITEM_PINNED: + case XFS_ITEM_PINNED: XFS_STATS_INC(xs_push_ail_pinned); - stuck++; flush_log = 1; break; - case XFS_ITEM_LOCKED: + case XFS_ITEM_LOCKED: XFS_STATS_INC(xs_push_ail_locked); - last_pushed_lsn = lsn; - stuck++; break; - case XFS_ITEM_FLUSHING: + case XFS_ITEM_FLUSHING: XFS_STATS_INC(xs_push_ail_flushing); - last_pushed_lsn = lsn; - stuck++; break; - default: + default: ASSERT(0); break; } - spin_lock(&mp->m_ail_lock); - /* should we bother continuing? */ - if (XFS_FORCED_SHUTDOWN(mp)) - break; - ASSERT(mp->m_log); - - count++; - - /* - * Are there too many items we can't do anything with? - * If we we are skipping too many items because we can't flush - * them or they are already being flushed, we back off and - * given them time to complete whatever operation is being - * done. i.e. remove pressure from the AIL while we can't make - * progress so traversals don't slow down further inserts and - * removals to/from the AIL. - * - * The value of 100 is an arbitrary magic number based on - * observation. - */ - if (stuck > 100) - break; - lip = xfs_trans_next_ail(mp, lip, &gen, &restarts); - if (lip == NULL) + if (lip == NULL) { break; - if (restarts > XFS_TRANS_PUSH_AIL_RESTARTS) - break; - lsn = lip->li_lsn; + } + if (XFS_FORCED_SHUTDOWN(mp)) { + /* + * Just return if we shut down during the last try. + */ + AIL_UNLOCK(mp, s); + return (xfs_lsn_t)0; + } + } - spin_unlock(&mp->m_ail_lock); if (flush_log) { /* @@ -257,35 +193,22 @@ xfsaild_push( * push out the log so it will become unpinned and * move forward in the AIL. */ + AIL_UNLOCK(mp, s); XFS_STATS_INC(xs_push_ail_flush); xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + AIL_LOCK(mp, s); } - /* - * We reached the target so wait a bit longer for I/O to complete and - * remove pushed items from the AIL before we start the next scan from - * the start of the AIL. - */ - if ((XFS_LSN_CMP(lsn, target) >= 0)) { - tout += 20; - last_pushed_lsn = 0; - } else if ((restarts > XFS_TRANS_PUSH_AIL_RESTARTS) || - (count && ((stuck * 100) / count > 90))) { - /* - * Either there is a lot of contention on the AIL or we - * are stuck due to operations in progress. "Stuck" in this - * case is defined as >90% of the items we tried to push - * were stuck. - * - * Backoff a bit more to allow some I/O to complete before - * continuing from where we were. - */ - tout += 10; + lip = xfs_ail_min(&(mp->m_ail)); + if (lip == NULL) { + lsn = (xfs_lsn_t)0; + } else { + lsn = lip->li_lsn; } -out: - *last_lsn = last_pushed_lsn; - return tout; -} /* xfsaild_push */ + + AIL_UNLOCK(mp, s); + return lsn; +} /* xfs_trans_push_ail */ /* @@ -326,7 +249,7 @@ xfs_trans_unlocked_item( * the call to xfs_log_move_tail() doesn't do anything if there's * not enough free space to wake people up so we're safe calling it. */ - min_lip = xfs_ail_min(&mp->m_ail.xa_ail); + min_lip = xfs_ail_min(&mp->m_ail); if (min_lip == lip) xfs_log_move_tail(mp, 1); @@ -346,19 +269,21 @@ xfs_trans_unlocked_item( * has changed. * * This function must be called with the AIL lock held. The lock - * is dropped before returning. + * is dropped before returning, so the caller must pass in the + * cookie returned by AIL_LOCK. */ void xfs_trans_update_ail( xfs_mount_t *mp, xfs_log_item_t *lip, - xfs_lsn_t lsn) __releases(mp->m_ail_lock) + xfs_lsn_t lsn, + unsigned long s) __releases(mp->m_ail_lock) { xfs_ail_entry_t *ailp; xfs_log_item_t *dlip=NULL; xfs_log_item_t *mlip; /* ptr to minimum lip */ - ailp = &(mp->m_ail.xa_ail); + ailp = &(mp->m_ail); mlip = xfs_ail_min(ailp); if (lip->li_flags & XFS_LI_IN_AIL) { @@ -371,14 +296,14 @@ xfs_trans_update_ail( lip->li_lsn = lsn; xfs_ail_insert(ailp, lip); - mp->m_ail.xa_gen++; + mp->m_ail_gen++; if (mlip == dlip) { - mlip = xfs_ail_min(&(mp->m_ail.xa_ail)); - spin_unlock(&mp->m_ail_lock); + mlip = xfs_ail_min(&(mp->m_ail)); + AIL_UNLOCK(mp, s); xfs_log_move_tail(mp, mlip->li_lsn); } else { - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); } @@ -397,19 +322,21 @@ xfs_trans_update_ail( * has changed. * * This function must be called with the AIL lock held. The lock - * is dropped before returning. + * is dropped before returning, so the caller must pass in the + * cookie returned by AIL_LOCK. */ void xfs_trans_delete_ail( xfs_mount_t *mp, - xfs_log_item_t *lip) __releases(mp->m_ail_lock) + xfs_log_item_t *lip, + unsigned long s) __releases(mp->m_ail_lock) { xfs_ail_entry_t *ailp; xfs_log_item_t *dlip; xfs_log_item_t *mlip; if (lip->li_flags & XFS_LI_IN_AIL) { - ailp = &(mp->m_ail.xa_ail); + ailp = &(mp->m_ail); mlip = xfs_ail_min(ailp); dlip = xfs_ail_delete(ailp, lip); ASSERT(dlip == lip); @@ -417,14 +344,14 @@ xfs_trans_delete_ail( lip->li_flags &= ~XFS_LI_IN_AIL; lip->li_lsn = 0; - mp->m_ail.xa_gen++; + mp->m_ail_gen++; if (mlip == dlip) { - mlip = xfs_ail_min(&(mp->m_ail.xa_ail)); - spin_unlock(&mp->m_ail_lock); + mlip = xfs_ail_min(&(mp->m_ail)); + AIL_UNLOCK(mp, s); xfs_log_move_tail(mp, (mlip ? mlip->li_lsn : 0)); } else { - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); } } else { @@ -433,12 +360,12 @@ xfs_trans_delete_ail( * serious trouble if we get to this stage. */ if (XFS_FORCED_SHUTDOWN(mp)) - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); else { xfs_cmn_err(XFS_PTAG_AILDELETE, CE_ALERT, mp, "%s: attempting to delete a log item that is not in the AIL", __FUNCTION__); - spin_unlock(&mp->m_ail_lock); + AIL_UNLOCK(mp, s); xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); } } @@ -458,10 +385,10 @@ xfs_trans_first_ail( { xfs_log_item_t *lip; - lip = xfs_ail_min(&(mp->m_ail.xa_ail)); - *gen = (int)mp->m_ail.xa_gen; + lip = xfs_ail_min(&(mp->m_ail)); + *gen = (int)mp->m_ail_gen; - return lip; + return (lip); } /* @@ -481,11 +408,11 @@ xfs_trans_next_ail( xfs_log_item_t *nlip; ASSERT(mp && lip && gen); - if (mp->m_ail.xa_gen == *gen) { - nlip = xfs_ail_next(&(mp->m_ail.xa_ail), lip); + if (mp->m_ail_gen == *gen) { + nlip = xfs_ail_next(&(mp->m_ail), lip); } else { - nlip = xfs_ail_min(&(mp->m_ail).xa_ail); - *gen = (int)mp->m_ail.xa_gen; + nlip = xfs_ail_min(&(mp->m_ail)); + *gen = (int)mp->m_ail_gen; if (restarts != NULL) { XFS_STATS_INC(xs_push_ail_restarts); (*restarts)++; @@ -510,20 +437,12 @@ xfs_trans_next_ail( /* * Initialize the doubly linked list to point only to itself. */ -int -xfs_trans_ail_init( - xfs_mount_t *mp) -{ - mp->m_ail.xa_ail.ail_forw = (xfs_log_item_t*)&mp->m_ail.xa_ail; - mp->m_ail.xa_ail.ail_back = (xfs_log_item_t*)&mp->m_ail.xa_ail; - return xfsaild_start(mp); -} - void -xfs_trans_ail_destroy( +xfs_trans_ail_init( xfs_mount_t *mp) { - xfsaild_stop(mp); + mp->m_ail.ail_forw = (xfs_log_item_t*)&(mp->m_ail); + mp->m_ail.ail_back = (xfs_log_item_t*)&(mp->m_ail); } /* @@ -563,7 +482,7 @@ xfs_ail_insert( next_lip->li_ail.ail_forw = lip; lip->li_ail.ail_forw->li_ail.ail_back = lip; - xfs_ail_check(base, lip); + xfs_ail_check(base); return; } @@ -577,12 +496,12 @@ xfs_ail_delete( xfs_log_item_t *lip) /* ARGSUSED */ { - xfs_ail_check(base, lip); lip->li_ail.ail_forw->li_ail.ail_back = lip->li_ail.ail_back; lip->li_ail.ail_back->li_ail.ail_forw = lip->li_ail.ail_forw; lip->li_ail.ail_forw = NULL; lip->li_ail.ail_back = NULL; + xfs_ail_check(base); return lip; } @@ -626,13 +545,13 @@ xfs_ail_next( */ STATIC void xfs_ail_check( - xfs_ail_entry_t *base, - xfs_log_item_t *lip) + xfs_ail_entry_t *base) { + xfs_log_item_t *lip; xfs_log_item_t *prev_lip; - prev_lip = base->ail_forw; - if (prev_lip == (xfs_log_item_t*)base) { + lip = base->ail_forw; + if (lip == (xfs_log_item_t*)base) { /* * Make sure the pointers are correct when the list * is empty. @@ -641,28 +560,10 @@ xfs_ail_check( return; } - /* - * Check the next and previous entries are valid. - */ - ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0); - prev_lip = lip->li_ail.ail_back; - if (prev_lip != (xfs_log_item_t*)base) { - ASSERT(prev_lip->li_ail.ail_forw == lip); - ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0); - } - prev_lip = lip->li_ail.ail_forw; - if (prev_lip != (xfs_log_item_t*)base) { - ASSERT(prev_lip->li_ail.ail_back == lip); - ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) >= 0); - } - - -#ifdef XFS_TRANS_DEBUG /* * Walk the list checking forward and backward pointers, * lsn ordering, and that every entry has the XFS_LI_IN_AIL - * flag set. This is really expensive, so only do it when - * specifically debugging the transaction subsystem. + * flag set. */ prev_lip = (xfs_log_item_t*)base; while (lip != (xfs_log_item_t*)base) { @@ -677,6 +578,5 @@ xfs_ail_check( } ASSERT(lip == (xfs_log_item_t*)base); ASSERT(base->ail_back == prev_lip); -#endif /* XFS_TRANS_DEBUG */ } #endif /* DEBUG */ diff --git a/trunk/fs/xfs/xfs_trans_item.c b/trunk/fs/xfs/xfs_trans_item.c index 66a09f0d894b..2912aac07c7b 100644 --- a/trunk/fs/xfs/xfs_trans_item.c +++ b/trunk/fs/xfs/xfs_trans_item.c @@ -21,7 +21,6 @@ #include "xfs_log.h" #include "xfs_inum.h" #include "xfs_trans.h" -#include "xfs_trans_priv.h" STATIC int xfs_trans_unlock_chunk(xfs_log_item_chunk_t *, int, int, xfs_lsn_t); diff --git a/trunk/fs/xfs/xfs_trans_priv.h b/trunk/fs/xfs/xfs_trans_priv.h index 3c748c456ed4..447ac4308c91 100644 --- a/trunk/fs/xfs/xfs_trans_priv.h +++ b/trunk/fs/xfs/xfs_trans_priv.h @@ -47,22 +47,15 @@ xfs_log_busy_slot_t *xfs_trans_add_busy(xfs_trans_t *tp, * From xfs_trans_ail.c */ void xfs_trans_update_ail(struct xfs_mount *mp, - struct xfs_log_item *lip, xfs_lsn_t lsn) + struct xfs_log_item *lip, xfs_lsn_t lsn, + unsigned long s) __releases(mp->m_ail_lock); void xfs_trans_delete_ail(struct xfs_mount *mp, - struct xfs_log_item *lip) + struct xfs_log_item *lip, unsigned long s) __releases(mp->m_ail_lock); struct xfs_log_item *xfs_trans_first_ail(struct xfs_mount *, int *); struct xfs_log_item *xfs_trans_next_ail(struct xfs_mount *, struct xfs_log_item *, int *, int *); -/* - * AIL push thread support - */ -long xfsaild_push(struct xfs_mount *, xfs_lsn_t *); -void xfsaild_wakeup(struct xfs_mount *, xfs_lsn_t); -int xfsaild_start(struct xfs_mount *); -void xfsaild_stop(struct xfs_mount *); - #endif /* __XFS_TRANS_PRIV_H__ */ diff --git a/trunk/fs/xfs/xfs_utils.c b/trunk/fs/xfs/xfs_utils.c index 45d740df53b7..673b405eaa31 100644 --- a/trunk/fs/xfs/xfs_utils.c +++ b/trunk/fs/xfs/xfs_utils.c @@ -73,7 +73,7 @@ xfs_dir_lookup_int( { int error; - xfs_itrace_entry(dp); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); error = xfs_dir_lookup(NULL, dp, VNAME(dentry), VNAMELEN(dentry), inum); if (!error) { @@ -302,7 +302,6 @@ xfs_droplink( ASSERT (ip->i_d.di_nlink > 0); ip->i_d.di_nlink--; - drop_nlink(ip->i_vnode); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = 0; @@ -331,6 +330,7 @@ xfs_bump_ino_vers2( xfs_inode_t *ip) { xfs_mount_t *mp; + unsigned long s; ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE)); ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1); @@ -340,13 +340,13 @@ xfs_bump_ino_vers2( memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); mp = tp->t_mountp; if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { - spin_lock(&mp->m_sb_lock); + s = XFS_SB_LOCK(mp); if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { XFS_SB_VERSION_ADDNLINK(&mp->m_sb); - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); xfs_mod_sb(tp, XFS_SB_VERSIONNUM); } else { - spin_unlock(&mp->m_sb_lock); + XFS_SB_UNLOCK(mp, s); } } /* Caller must log the inode */ @@ -366,7 +366,6 @@ xfs_bumplink( ASSERT(ip->i_d.di_nlink > 0); ip->i_d.di_nlink++; - inc_nlink(ip->i_vnode); if ((ip->i_d.di_version == XFS_DINODE_VERSION_1) && (ip->i_d.di_nlink > XFS_MAXLINK_1)) { /* diff --git a/trunk/fs/xfs/xfs_utils.h b/trunk/fs/xfs/xfs_utils.h index f857fcccb723..a00b26d8840e 100644 --- a/trunk/fs/xfs/xfs_utils.h +++ b/trunk/fs/xfs/xfs_utils.h @@ -20,6 +20,8 @@ #define IRELE(ip) VN_RELE(XFS_ITOV(ip)) #define IHOLD(ip) VN_HOLD(XFS_ITOV(ip)) +#define ITRACE(ip) vn_trace_ref(ip, __FILE__, __LINE__, \ + (inst_t *)__return_address) extern int xfs_get_dir_entry (bhv_vname_t *, xfs_inode_t **); extern int xfs_dir_lookup_int (xfs_inode_t *, uint, bhv_vname_t *, xfs_ino_t *, diff --git a/trunk/fs/xfs/xfs_vfsops.c b/trunk/fs/xfs/xfs_vfsops.c index 413587f02155..a1544597bcd3 100644 --- a/trunk/fs/xfs/xfs_vfsops.c +++ b/trunk/fs/xfs/xfs_vfsops.c @@ -58,12 +58,17 @@ #include "xfs_vfsops.h" -int __init +int xfs_init(void) { + extern kmem_zone_t *xfs_bmap_free_item_zone; + extern kmem_zone_t *xfs_btree_cur_zone; + extern kmem_zone_t *xfs_trans_zone; + extern kmem_zone_t *xfs_buf_item_zone; + extern kmem_zone_t *xfs_dabuf_zone; #ifdef XFS_DABUF_DEBUG - extern spinlock_t xfs_dabuf_global_lock; - spin_lock_init(&xfs_dabuf_global_lock); + extern lock_t xfs_dabuf_global_lock; + spinlock_init(&xfs_dabuf_global_lock, "xfsda"); #endif /* @@ -147,12 +152,18 @@ xfs_init(void) return 0; } -void __exit +void xfs_cleanup(void) { + extern kmem_zone_t *xfs_bmap_free_item_zone; + extern kmem_zone_t *xfs_btree_cur_zone; extern kmem_zone_t *xfs_inode_zone; + extern kmem_zone_t *xfs_trans_zone; + extern kmem_zone_t *xfs_da_state_zone; + extern kmem_zone_t *xfs_dabuf_zone; extern kmem_zone_t *xfs_efd_zone; extern kmem_zone_t *xfs_efi_zone; + extern kmem_zone_t *xfs_buf_item_zone; extern kmem_zone_t *xfs_icluster_zone; xfs_cleanup_procfs(); @@ -438,6 +449,8 @@ xfs_mount( if (error) return error; + mp->m_io_ops = xfs_iocore_xfs; + if (args->flags & XFSMNT_QUIET) flags |= XFS_MFSI_QUIET; @@ -531,7 +544,7 @@ xfs_mount( if ((error = xfs_filestream_mount(mp))) goto error2; - error = xfs_mountfs(mp, flags); + error = XFS_IOINIT(mp, args, flags); if (error) goto error2; @@ -681,7 +694,7 @@ xfs_quiesce_fs( * care of the metadata. New transactions are already blocked, so we need to * wait for any remaining transactions to drain out before proceding. */ -void +STATIC void xfs_attr_quiesce( xfs_mount_t *mp) { @@ -807,6 +820,80 @@ xfs_unmount_flush( return XFS_ERROR(EFSCORRUPTED); } +/* + * xfs_root extracts the root vnode from a vfs. + * + * vfsp -- the vfs struct for the desired file system + * vpp -- address of the caller's vnode pointer which should be + * set to the desired fs root vnode + */ +int +xfs_root( + xfs_mount_t *mp, + bhv_vnode_t **vpp) +{ + bhv_vnode_t *vp; + + vp = XFS_ITOV(mp->m_rootip); + VN_HOLD(vp); + *vpp = vp; + return 0; +} + +/* + * xfs_statvfs + * + * Fill in the statvfs structure for the given file system. We use + * the superblock lock in the mount structure to ensure a consistent + * snapshot of the counters returned. + */ +int +xfs_statvfs( + xfs_mount_t *mp, + bhv_statvfs_t *statp, + bhv_vnode_t *vp) +{ + __uint64_t fakeinos; + xfs_extlen_t lsize; + xfs_sb_t *sbp; + unsigned long s; + + sbp = &(mp->m_sb); + + statp->f_type = XFS_SB_MAGIC; + + xfs_icsb_sync_counters_flags(mp, XFS_ICSB_LAZY_COUNT); + s = XFS_SB_LOCK(mp); + statp->f_bsize = sbp->sb_blocksize; + lsize = sbp->sb_logstart ? sbp->sb_logblocks : 0; + statp->f_blocks = sbp->sb_dblocks - lsize; + statp->f_bfree = statp->f_bavail = + sbp->sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); + fakeinos = statp->f_bfree << sbp->sb_inopblog; +#if XFS_BIG_INUMS + fakeinos += mp->m_inoadd; +#endif + statp->f_files = + MIN(sbp->sb_icount + fakeinos, (__uint64_t)XFS_MAXINUMBER); + if (mp->m_maxicount) +#if XFS_BIG_INUMS + if (!mp->m_inoadd) +#endif + statp->f_files = min_t(typeof(statp->f_files), + statp->f_files, + mp->m_maxicount); + statp->f_ffree = statp->f_files - (sbp->sb_icount - sbp->sb_ifree); + XFS_SB_UNLOCK(mp, s); + + xfs_statvfs_fsid(statp, mp); + statp->f_namelen = MAXNAMELEN - 1; + + if (vp) + XFS_QM_DQSTATVFS(xfs_vtoi(vp), statp); + return 0; +} + + /* * xfs_sync flushes any pending I/O to file system vfsp. * @@ -894,6 +981,8 @@ xfs_sync_inodes( int *bypassed) { xfs_inode_t *ip = NULL; + xfs_inode_t *ip_next; + xfs_buf_t *bp; bhv_vnode_t *vp = NULL; int error; int last_error; @@ -903,6 +992,7 @@ xfs_sync_inodes( boolean_t mount_locked; boolean_t vnode_refed; int preempt; + xfs_dinode_t *dip; xfs_iptr_t *ipointer; #ifdef DEBUG boolean_t ipointer_in = B_FALSE; @@ -955,8 +1045,6 @@ xfs_sync_inodes( #define XFS_PREEMPT_MASK 0x7f - ASSERT(!(flags & SYNC_BDFLUSH)); - if (bypassed) *bypassed = 0; if (mp->m_flags & XFS_MOUNT_RDONLY) @@ -969,7 +1057,7 @@ xfs_sync_inodes( ipointer = (xfs_iptr_t *)kmem_zalloc(sizeof(xfs_iptr_t), KM_SLEEP); fflag = XFS_B_ASYNC; /* default is don't wait */ - if (flags & SYNC_DELWRI) + if (flags & (SYNC_BDFLUSH | SYNC_DELWRI)) fflag = XFS_B_DELWRI; if (flags & SYNC_WAIT) fflag = 0; /* synchronous overrides all */ @@ -1058,6 +1146,24 @@ xfs_sync_inodes( return 0; } + /* + * If this is just vfs_sync() or pflushd() calling + * then we can skip inodes for which it looks like + * there is nothing to do. Since we don't have the + * inode locked this is racy, but these are periodic + * calls so it doesn't matter. For the others we want + * to know for sure, so we at least try to lock them. + */ + if (flags & SYNC_BDFLUSH) { + if (((ip->i_itemp == NULL) || + !(ip->i_itemp->ili_format.ilf_fields & + XFS_ILOG_ALL)) && + (ip->i_update_core == 0)) { + ip = ip->i_mnext; + continue; + } + } + /* * Try to lock without sleeping. We're out of order with * the inode list lock here, so if we fail we need to drop @@ -1075,7 +1181,7 @@ xfs_sync_inodes( * it. */ if (xfs_ilock_nowait(ip, lock_flags) == 0) { - if (vp == NULL) { + if ((flags & SYNC_BDFLUSH) || (vp == NULL)) { ip = ip->i_mnext; continue; } @@ -1136,27 +1242,160 @@ xfs_sync_inodes( xfs_ilock(ip, XFS_ILOCK_SHARED); } - if ((flags & SYNC_ATTR) && - (ip->i_update_core || - (ip->i_itemp && ip->i_itemp->ili_format.ilf_fields))) { - if (mount_locked) - IPOINTER_INSERT(ip, mp); + if (flags & SYNC_BDFLUSH) { + if ((flags & SYNC_ATTR) && + ((ip->i_update_core) || + ((ip->i_itemp != NULL) && + (ip->i_itemp->ili_format.ilf_fields != 0)))) { + + /* Insert marker and drop lock if not already + * done. + */ + if (mount_locked) { + IPOINTER_INSERT(ip, mp); + } - if (flags & SYNC_WAIT) { - xfs_iflock(ip); - error = xfs_iflush(ip, XFS_IFLUSH_SYNC); + /* + * We don't want the periodic flushing of the + * inodes by vfs_sync() to interfere with + * I/O to the file, especially read I/O + * where it is only the access time stamp + * that is being flushed out. To prevent + * long periods where we have both inode + * locks held shared here while reading the + * inode's buffer in from disk, we drop the + * inode lock while reading in the inode + * buffer. We have to release the buffer + * and reacquire the inode lock so that they + * are acquired in the proper order (inode + * locks first). The buffer will go at the + * end of the lru chain, though, so we can + * expect it to still be there when we go + * for it again in xfs_iflush(). + */ + if ((xfs_ipincount(ip) == 0) && + xfs_iflock_nowait(ip)) { - /* - * If we can't acquire the flush lock, then the inode - * is already being flushed so don't bother waiting. - * - * If we can lock it then do a delwri flush so we can - * combine multiple inode flushes in each disk write. - */ - } else if (xfs_iflock_nowait(ip)) { - error = xfs_iflush(ip, XFS_IFLUSH_DELWRI); - } else if (bypassed) { - (*bypassed)++; + xfs_ifunlock(ip); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + error = xfs_itobp(mp, NULL, ip, + &dip, &bp, 0, 0); + if (!error) { + xfs_buf_relse(bp); + } else { + /* Bailing out, remove the + * marker and free it. + */ + XFS_MOUNT_ILOCK(mp); + IPOINTER_REMOVE(ip, mp); + XFS_MOUNT_IUNLOCK(mp); + + ASSERT(!(lock_flags & + XFS_IOLOCK_SHARED)); + + kmem_free(ipointer, + sizeof(xfs_iptr_t)); + return (0); + } + + /* + * Since we dropped the inode lock, + * the inode may have been reclaimed. + * Therefore, we reacquire the mount + * lock and check to see if we were the + * inode reclaimed. If this happened + * then the ipointer marker will no + * longer point back at us. In this + * case, move ip along to the inode + * after the marker, remove the marker + * and continue. + */ + XFS_MOUNT_ILOCK(mp); + mount_locked = B_TRUE; + + if (ip != ipointer->ip_mprev) { + IPOINTER_REMOVE(ip, mp); + + ASSERT(!vnode_refed); + ASSERT(!(lock_flags & + XFS_IOLOCK_SHARED)); + continue; + } + + ASSERT(ip->i_mount == mp); + + if (xfs_ilock_nowait(ip, + XFS_ILOCK_SHARED) == 0) { + ASSERT(ip->i_mount == mp); + /* + * We failed to reacquire + * the inode lock without + * sleeping, so just skip + * the inode for now. We + * clear the ILOCK bit from + * the lock_flags so that we + * won't try to drop a lock + * we don't hold below. + */ + lock_flags &= ~XFS_ILOCK_SHARED; + IPOINTER_REMOVE(ip_next, mp); + } else if ((xfs_ipincount(ip) == 0) && + xfs_iflock_nowait(ip)) { + ASSERT(ip->i_mount == mp); + /* + * Since this is vfs_sync() + * calling we only flush the + * inode out if we can lock + * it without sleeping and + * it is not pinned. Drop + * the mount lock here so + * that we don't hold it for + * too long. We already have + * a marker in the list here. + */ + XFS_MOUNT_IUNLOCK(mp); + mount_locked = B_FALSE; + error = xfs_iflush(ip, + XFS_IFLUSH_DELWRI); + } else { + ASSERT(ip->i_mount == mp); + IPOINTER_REMOVE(ip_next, mp); + } + } + + } + + } else { + if ((flags & SYNC_ATTR) && + ((ip->i_update_core) || + ((ip->i_itemp != NULL) && + (ip->i_itemp->ili_format.ilf_fields != 0)))) { + if (mount_locked) { + IPOINTER_INSERT(ip, mp); + } + + if (flags & SYNC_WAIT) { + xfs_iflock(ip); + error = xfs_iflush(ip, + XFS_IFLUSH_SYNC); + } else { + /* + * If we can't acquire the flush + * lock, then the inode is already + * being flushed so don't bother + * waiting. If we can lock it then + * do a delwri flush so we can + * combine multiple inode flushes + * in each disk write. + */ + if (xfs_iflock_nowait(ip)) { + error = xfs_iflush(ip, + XFS_IFLUSH_DELWRI); + } + else if (bypassed) + (*bypassed)++; + } } } @@ -1388,3 +1627,499 @@ xfs_syncsub( return XFS_ERROR(last_error); } + +/* + * xfs_vget - called by DMAPI and NFSD to get vnode from file handle + */ +int +xfs_vget( + xfs_mount_t *mp, + bhv_vnode_t **vpp, + xfs_fid_t *xfid) +{ + xfs_inode_t *ip; + int error; + xfs_ino_t ino; + unsigned int igen; + + /* + * Invalid. Since handles can be created in user space and passed in + * via gethandle(), this is not cause for a panic. + */ + if (xfid->fid_len != sizeof(*xfid) - sizeof(xfid->fid_len)) + return XFS_ERROR(EINVAL); + + ino = xfid->fid_ino; + igen = xfid->fid_gen; + + /* + * NFS can sometimes send requests for ino 0. Fail them gracefully. + */ + if (ino == 0) + return XFS_ERROR(ESTALE); + + error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0); + if (error) { + *vpp = NULL; + return error; + } + + if (ip == NULL) { + *vpp = NULL; + return XFS_ERROR(EIO); + } + + if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) { + xfs_iput_new(ip, XFS_ILOCK_SHARED); + *vpp = NULL; + return XFS_ERROR(ENOENT); + } + + *vpp = XFS_ITOV(ip); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return 0; +} + + +#define MNTOPT_LOGBUFS "logbufs" /* number of XFS log buffers */ +#define MNTOPT_LOGBSIZE "logbsize" /* size of XFS log buffers */ +#define MNTOPT_LOGDEV "logdev" /* log device */ +#define MNTOPT_RTDEV "rtdev" /* realtime I/O device */ +#define MNTOPT_BIOSIZE "biosize" /* log2 of preferred buffered io size */ +#define MNTOPT_WSYNC "wsync" /* safe-mode nfs compatible mount */ +#define MNTOPT_INO64 "ino64" /* force inodes into 64-bit range */ +#define MNTOPT_NOALIGN "noalign" /* turn off stripe alignment */ +#define MNTOPT_SWALLOC "swalloc" /* turn on stripe width allocation */ +#define MNTOPT_SUNIT "sunit" /* data volume stripe unit */ +#define MNTOPT_SWIDTH "swidth" /* data volume stripe width */ +#define MNTOPT_NOUUID "nouuid" /* ignore filesystem UUID */ +#define MNTOPT_MTPT "mtpt" /* filesystem mount point */ +#define MNTOPT_GRPID "grpid" /* group-ID from parent directory */ +#define MNTOPT_NOGRPID "nogrpid" /* group-ID from current process */ +#define MNTOPT_BSDGROUPS "bsdgroups" /* group-ID from parent directory */ +#define MNTOPT_SYSVGROUPS "sysvgroups" /* group-ID from current process */ +#define MNTOPT_ALLOCSIZE "allocsize" /* preferred allocation size */ +#define MNTOPT_NORECOVERY "norecovery" /* don't run XFS recovery */ +#define MNTOPT_BARRIER "barrier" /* use writer barriers for log write and + * unwritten extent conversion */ +#define MNTOPT_NOBARRIER "nobarrier" /* .. disable */ +#define MNTOPT_OSYNCISOSYNC "osyncisosync" /* o_sync is REALLY o_sync */ +#define MNTOPT_64BITINODE "inode64" /* inodes can be allocated anywhere */ +#define MNTOPT_IKEEP "ikeep" /* do not free empty inode clusters */ +#define MNTOPT_NOIKEEP "noikeep" /* free empty inode clusters */ +#define MNTOPT_LARGEIO "largeio" /* report large I/O sizes in stat() */ +#define MNTOPT_NOLARGEIO "nolargeio" /* do not report large I/O sizes + * in stat(). */ +#define MNTOPT_ATTR2 "attr2" /* do use attr2 attribute format */ +#define MNTOPT_NOATTR2 "noattr2" /* do not use attr2 attribute format */ +#define MNTOPT_FILESTREAM "filestreams" /* use filestreams allocator */ +#define MNTOPT_QUOTA "quota" /* disk quotas (user) */ +#define MNTOPT_NOQUOTA "noquota" /* no quotas */ +#define MNTOPT_USRQUOTA "usrquota" /* user quota enabled */ +#define MNTOPT_GRPQUOTA "grpquota" /* group quota enabled */ +#define MNTOPT_PRJQUOTA "prjquota" /* project quota enabled */ +#define MNTOPT_UQUOTA "uquota" /* user quota (IRIX variant) */ +#define MNTOPT_GQUOTA "gquota" /* group quota (IRIX variant) */ +#define MNTOPT_PQUOTA "pquota" /* project quota (IRIX variant) */ +#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */ +#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */ +#define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */ +#define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */ +#define MNTOPT_DMAPI "dmapi" /* DMI enabled (DMAPI / XDSM) */ +#define MNTOPT_XDSM "xdsm" /* DMI enabled (DMAPI / XDSM) */ +#define MNTOPT_DMI "dmi" /* DMI enabled (DMAPI / XDSM) */ + +STATIC unsigned long +suffix_strtoul(char *s, char **endp, unsigned int base) +{ + int last, shift_left_factor = 0; + char *value = s; + + last = strlen(value) - 1; + if (value[last] == 'K' || value[last] == 'k') { + shift_left_factor = 10; + value[last] = '\0'; + } + if (value[last] == 'M' || value[last] == 'm') { + shift_left_factor = 20; + value[last] = '\0'; + } + if (value[last] == 'G' || value[last] == 'g') { + shift_left_factor = 30; + value[last] = '\0'; + } + + return simple_strtoul((const char *)s, endp, base) << shift_left_factor; +} + +int +xfs_parseargs( + struct xfs_mount *mp, + char *options, + struct xfs_mount_args *args, + int update) +{ + char *this_char, *value, *eov; + int dsunit, dswidth, vol_dsunit, vol_dswidth; + int iosize; + int ikeep = 0; + + args->flags |= XFSMNT_BARRIER; + args->flags2 |= XFSMNT2_COMPAT_IOSIZE; + + if (!options) + goto done; + + iosize = dsunit = dswidth = vol_dsunit = vol_dswidth = 0; + + while ((this_char = strsep(&options, ",")) != NULL) { + if (!*this_char) + continue; + if ((value = strchr(this_char, '=')) != NULL) + *value++ = 0; + + if (!strcmp(this_char, MNTOPT_LOGBUFS)) { + if (!value || !*value) { + cmn_err(CE_WARN, + "XFS: %s option requires an argument", + this_char); + return EINVAL; + } + args->logbufs = simple_strtoul(value, &eov, 10); + } else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) { + if (!value || !*value) { + cmn_err(CE_WARN, + "XFS: %s option requires an argument", + this_char); + return EINVAL; + } + args->logbufsize = suffix_strtoul(value, &eov, 10); + } else if (!strcmp(this_char, MNTOPT_LOGDEV)) { + if (!value || !*value) { + cmn_err(CE_WARN, + "XFS: %s option requires an argument", + this_char); + return EINVAL; + } + strncpy(args->logname, value, MAXNAMELEN); + } else if (!strcmp(this_char, MNTOPT_MTPT)) { + if (!value || !*value) { + cmn_err(CE_WARN, + "XFS: %s option requires an argument", + this_char); + return EINVAL; + } + strncpy(args->mtpt, value, MAXNAMELEN); + } else if (!strcmp(this_char, MNTOPT_RTDEV)) { + if (!value || !*value) { + cmn_err(CE_WARN, + "XFS: %s option requires an argument", + this_char); + return EINVAL; + } + strncpy(args->rtname, value, MAXNAMELEN); + } else if (!strcmp(this_char, MNTOPT_BIOSIZE)) { + if (!value || !*value) { + cmn_err(CE_WARN, + "XFS: %s option requires an argument", + this_char); + return EINVAL; + } + iosize = simple_strtoul(value, &eov, 10); + args->flags |= XFSMNT_IOSIZE; + args->iosizelog = (uint8_t) iosize; + } else if (!strcmp(this_char, MNTOPT_ALLOCSIZE)) { + if (!value || !*value) { + cmn_err(CE_WARN, + "XFS: %s option requires an argument", + this_char); + return EINVAL; + } + iosize = suffix_strtoul(value, &eov, 10); + args->flags |= XFSMNT_IOSIZE; + args->iosizelog = ffs(iosize) - 1; + } else if (!strcmp(this_char, MNTOPT_GRPID) || + !strcmp(this_char, MNTOPT_BSDGROUPS)) { + mp->m_flags |= XFS_MOUNT_GRPID; + } else if (!strcmp(this_char, MNTOPT_NOGRPID) || + !strcmp(this_char, MNTOPT_SYSVGROUPS)) { + mp->m_flags &= ~XFS_MOUNT_GRPID; + } else if (!strcmp(this_char, MNTOPT_WSYNC)) { + args->flags |= XFSMNT_WSYNC; + } else if (!strcmp(this_char, MNTOPT_OSYNCISOSYNC)) { + args->flags |= XFSMNT_OSYNCISOSYNC; + } else if (!strcmp(this_char, MNTOPT_NORECOVERY)) { + args->flags |= XFSMNT_NORECOVERY; + } else if (!strcmp(this_char, MNTOPT_INO64)) { + args->flags |= XFSMNT_INO64; +#if !XFS_BIG_INUMS + cmn_err(CE_WARN, + "XFS: %s option not allowed on this system", + this_char); + return EINVAL; +#endif + } else if (!strcmp(this_char, MNTOPT_NOALIGN)) { + args->flags |= XFSMNT_NOALIGN; + } else if (!strcmp(this_char, MNTOPT_SWALLOC)) { + args->flags |= XFSMNT_SWALLOC; + } else if (!strcmp(this_char, MNTOPT_SUNIT)) { + if (!value || !*value) { + cmn_err(CE_WARN, + "XFS: %s option requires an argument", + this_char); + return EINVAL; + } + dsunit = simple_strtoul(value, &eov, 10); + } else if (!strcmp(this_char, MNTOPT_SWIDTH)) { + if (!value || !*value) { + cmn_err(CE_WARN, + "XFS: %s option requires an argument", + this_char); + return EINVAL; + } + dswidth = simple_strtoul(value, &eov, 10); + } else if (!strcmp(this_char, MNTOPT_64BITINODE)) { + args->flags &= ~XFSMNT_32BITINODES; +#if !XFS_BIG_INUMS + cmn_err(CE_WARN, + "XFS: %s option not allowed on this system", + this_char); + return EINVAL; +#endif + } else if (!strcmp(this_char, MNTOPT_NOUUID)) { + args->flags |= XFSMNT_NOUUID; + } else if (!strcmp(this_char, MNTOPT_BARRIER)) { + args->flags |= XFSMNT_BARRIER; + } else if (!strcmp(this_char, MNTOPT_NOBARRIER)) { + args->flags &= ~XFSMNT_BARRIER; + } else if (!strcmp(this_char, MNTOPT_IKEEP)) { + ikeep = 1; + args->flags &= ~XFSMNT_IDELETE; + } else if (!strcmp(this_char, MNTOPT_NOIKEEP)) { + args->flags |= XFSMNT_IDELETE; + } else if (!strcmp(this_char, MNTOPT_LARGEIO)) { + args->flags2 &= ~XFSMNT2_COMPAT_IOSIZE; + } else if (!strcmp(this_char, MNTOPT_NOLARGEIO)) { + args->flags2 |= XFSMNT2_COMPAT_IOSIZE; + } else if (!strcmp(this_char, MNTOPT_ATTR2)) { + args->flags |= XFSMNT_ATTR2; + } else if (!strcmp(this_char, MNTOPT_NOATTR2)) { + args->flags &= ~XFSMNT_ATTR2; + } else if (!strcmp(this_char, MNTOPT_FILESTREAM)) { + args->flags2 |= XFSMNT2_FILESTREAMS; + } else if (!strcmp(this_char, MNTOPT_NOQUOTA)) { + args->flags &= ~(XFSMNT_UQUOTAENF|XFSMNT_UQUOTA); + args->flags &= ~(XFSMNT_GQUOTAENF|XFSMNT_GQUOTA); + } else if (!strcmp(this_char, MNTOPT_QUOTA) || + !strcmp(this_char, MNTOPT_UQUOTA) || + !strcmp(this_char, MNTOPT_USRQUOTA)) { + args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_QUOTANOENF) || + !strcmp(this_char, MNTOPT_UQUOTANOENF)) { + args->flags |= XFSMNT_UQUOTA; + args->flags &= ~XFSMNT_UQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_PQUOTA) || + !strcmp(this_char, MNTOPT_PRJQUOTA)) { + args->flags |= XFSMNT_PQUOTA | XFSMNT_PQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) { + args->flags |= XFSMNT_PQUOTA; + args->flags &= ~XFSMNT_PQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_GQUOTA) || + !strcmp(this_char, MNTOPT_GRPQUOTA)) { + args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) { + args->flags |= XFSMNT_GQUOTA; + args->flags &= ~XFSMNT_GQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_DMAPI)) { + args->flags |= XFSMNT_DMAPI; + } else if (!strcmp(this_char, MNTOPT_XDSM)) { + args->flags |= XFSMNT_DMAPI; + } else if (!strcmp(this_char, MNTOPT_DMI)) { + args->flags |= XFSMNT_DMAPI; + } else if (!strcmp(this_char, "ihashsize")) { + cmn_err(CE_WARN, + "XFS: ihashsize no longer used, option is deprecated."); + } else if (!strcmp(this_char, "osyncisdsync")) { + /* no-op, this is now the default */ + cmn_err(CE_WARN, + "XFS: osyncisdsync is now the default, option is deprecated."); + } else if (!strcmp(this_char, "irixsgid")) { + cmn_err(CE_WARN, + "XFS: irixsgid is now a sysctl(2) variable, option is deprecated."); + } else { + cmn_err(CE_WARN, + "XFS: unknown mount option [%s].", this_char); + return EINVAL; + } + } + + if (args->flags & XFSMNT_NORECOVERY) { + if ((mp->m_flags & XFS_MOUNT_RDONLY) == 0) { + cmn_err(CE_WARN, + "XFS: no-recovery mounts must be read-only."); + return EINVAL; + } + } + + if ((args->flags & XFSMNT_NOALIGN) && (dsunit || dswidth)) { + cmn_err(CE_WARN, + "XFS: sunit and swidth options incompatible with the noalign option"); + return EINVAL; + } + + if ((args->flags & XFSMNT_GQUOTA) && (args->flags & XFSMNT_PQUOTA)) { + cmn_err(CE_WARN, + "XFS: cannot mount with both project and group quota"); + return EINVAL; + } + + if ((args->flags & XFSMNT_DMAPI) && *args->mtpt == '\0') { + printk("XFS: %s option needs the mount point option as well\n", + MNTOPT_DMAPI); + return EINVAL; + } + + if ((dsunit && !dswidth) || (!dsunit && dswidth)) { + cmn_err(CE_WARN, + "XFS: sunit and swidth must be specified together"); + return EINVAL; + } + + if (dsunit && (dswidth % dsunit != 0)) { + cmn_err(CE_WARN, + "XFS: stripe width (%d) must be a multiple of the stripe unit (%d)", + dswidth, dsunit); + return EINVAL; + } + + /* + * Applications using DMI filesystems often expect the + * inode generation number to be monotonically increasing. + * If we delete inode chunks we break this assumption, so + * keep unused inode chunks on disk for DMI filesystems + * until we come up with a better solution. + * Note that if "ikeep" or "noikeep" mount options are + * supplied, then they are honored. + */ + if (!(args->flags & XFSMNT_DMAPI) && !ikeep) + args->flags |= XFSMNT_IDELETE; + + if ((args->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) { + if (dsunit) { + args->sunit = dsunit; + args->flags |= XFSMNT_RETERR; + } else { + args->sunit = vol_dsunit; + } + dswidth ? (args->swidth = dswidth) : + (args->swidth = vol_dswidth); + } else { + args->sunit = args->swidth = 0; + } + +done: + if (args->flags & XFSMNT_32BITINODES) + mp->m_flags |= XFS_MOUNT_SMALL_INUMS; + if (args->flags2) + args->flags |= XFSMNT_FLAGS2; + return 0; +} + +int +xfs_showargs( + struct xfs_mount *mp, + struct seq_file *m) +{ + static struct proc_xfs_info { + int flag; + char *str; + } xfs_info[] = { + /* the few simple ones we can get from the mount struct */ + { XFS_MOUNT_WSYNC, "," MNTOPT_WSYNC }, + { XFS_MOUNT_INO64, "," MNTOPT_INO64 }, + { XFS_MOUNT_NOALIGN, "," MNTOPT_NOALIGN }, + { XFS_MOUNT_SWALLOC, "," MNTOPT_SWALLOC }, + { XFS_MOUNT_NOUUID, "," MNTOPT_NOUUID }, + { XFS_MOUNT_NORECOVERY, "," MNTOPT_NORECOVERY }, + { XFS_MOUNT_OSYNCISOSYNC, "," MNTOPT_OSYNCISOSYNC }, + { 0, NULL } + }; + struct proc_xfs_info *xfs_infop; + + for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) { + if (mp->m_flags & xfs_infop->flag) + seq_puts(m, xfs_infop->str); + } + + if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) + seq_printf(m, "," MNTOPT_ALLOCSIZE "=%dk", + (int)(1 << mp->m_writeio_log) >> 10); + + if (mp->m_logbufs > 0) + seq_printf(m, "," MNTOPT_LOGBUFS "=%d", mp->m_logbufs); + if (mp->m_logbsize > 0) + seq_printf(m, "," MNTOPT_LOGBSIZE "=%dk", mp->m_logbsize >> 10); + + if (mp->m_logname) + seq_printf(m, "," MNTOPT_LOGDEV "=%s", mp->m_logname); + if (mp->m_rtname) + seq_printf(m, "," MNTOPT_RTDEV "=%s", mp->m_rtname); + + if (mp->m_dalign > 0) + seq_printf(m, "," MNTOPT_SUNIT "=%d", + (int)XFS_FSB_TO_BB(mp, mp->m_dalign)); + if (mp->m_swidth > 0) + seq_printf(m, "," MNTOPT_SWIDTH "=%d", + (int)XFS_FSB_TO_BB(mp, mp->m_swidth)); + + if (!(mp->m_flags & XFS_MOUNT_IDELETE)) + seq_printf(m, "," MNTOPT_IKEEP); + if (!(mp->m_flags & XFS_MOUNT_COMPAT_IOSIZE)) + seq_printf(m, "," MNTOPT_LARGEIO); + + if (!(mp->m_flags & XFS_MOUNT_SMALL_INUMS)) + seq_printf(m, "," MNTOPT_64BITINODE); + if (mp->m_flags & XFS_MOUNT_GRPID) + seq_printf(m, "," MNTOPT_GRPID); + + if (mp->m_qflags & XFS_UQUOTA_ACCT) { + if (mp->m_qflags & XFS_UQUOTA_ENFD) + seq_puts(m, "," MNTOPT_USRQUOTA); + else + seq_puts(m, "," MNTOPT_UQUOTANOENF); + } + + if (mp->m_qflags & XFS_PQUOTA_ACCT) { + if (mp->m_qflags & XFS_OQUOTA_ENFD) + seq_puts(m, "," MNTOPT_PRJQUOTA); + else + seq_puts(m, "," MNTOPT_PQUOTANOENF); + } + + if (mp->m_qflags & XFS_GQUOTA_ACCT) { + if (mp->m_qflags & XFS_OQUOTA_ENFD) + seq_puts(m, "," MNTOPT_GRPQUOTA); + else + seq_puts(m, "," MNTOPT_GQUOTANOENF); + } + + if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) + seq_puts(m, "," MNTOPT_NOQUOTA); + + if (mp->m_flags & XFS_MOUNT_DMAPI) + seq_puts(m, "," MNTOPT_DMAPI); + return 0; +} + +/* + * Second stage of a freeze. The data is already frozen so we only + * need to take care of themetadata. Once that's done write a dummy + * record to dirty the log in case of a crash while frozen. + */ +void +xfs_freeze( + xfs_mount_t *mp) +{ + xfs_attr_quiesce(mp); + xfs_fs_log_dummy(mp); +} diff --git a/trunk/fs/xfs/xfs_vfsops.h b/trunk/fs/xfs/xfs_vfsops.h index 1688817c55ed..a592fe02a339 100644 --- a/trunk/fs/xfs/xfs_vfsops.h +++ b/trunk/fs/xfs/xfs_vfsops.h @@ -13,9 +13,16 @@ int xfs_mount(struct xfs_mount *mp, struct xfs_mount_args *args, int xfs_unmount(struct xfs_mount *mp, int flags, struct cred *credp); int xfs_mntupdate(struct xfs_mount *mp, int *flags, struct xfs_mount_args *args); +int xfs_root(struct xfs_mount *mp, bhv_vnode_t **vpp); +int xfs_statvfs(struct xfs_mount *mp, struct kstatfs *statp, + bhv_vnode_t *vp); int xfs_sync(struct xfs_mount *mp, int flags); +int xfs_vget(struct xfs_mount *mp, bhv_vnode_t **vpp, struct xfs_fid *xfid); +int xfs_parseargs(struct xfs_mount *mp, char *options, + struct xfs_mount_args *args, int update); +int xfs_showargs(struct xfs_mount *mp, struct seq_file *m); +void xfs_freeze(struct xfs_mount *mp); void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname, int lnnum); -void xfs_attr_quiesce(struct xfs_mount *mp); #endif /* _XFS_VFSOPS_H */ diff --git a/trunk/fs/xfs/xfs_vnodeops.c b/trunk/fs/xfs/xfs_vnodeops.c index 51305242ff8c..efd5aff9eaf6 100644 --- a/trunk/fs/xfs/xfs_vnodeops.c +++ b/trunk/fs/xfs/xfs_vnodeops.c @@ -88,7 +88,7 @@ xfs_getattr( bhv_vnode_t *vp = XFS_ITOV(ip); xfs_mount_t *mp = ip->i_mount; - xfs_itrace_entry(ip); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -136,7 +136,7 @@ xfs_getattr( default: vap->va_rdev = 0; - if (!(XFS_IS_REALTIME_INODE(ip))) { + if (!(ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { vap->va_blocksize = xfs_preferred_iosize(mp); } else { @@ -228,7 +228,7 @@ xfs_setattr( int file_owner; int need_iolock = 1; - xfs_itrace_entry(ip); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); if (mp->m_flags & XFS_MOUNT_RDONLY) return XFS_ERROR(EROFS); @@ -508,7 +508,7 @@ xfs_setattr( */ if ((ip->i_d.di_nextents || ip->i_delayed_blks) && (mask & XFS_AT_XFLAGS) && - (XFS_IS_REALTIME_INODE(ip)) != + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != (vap->va_xflags & XFS_XFLAG_REALTIME)) { code = XFS_ERROR(EINVAL); /* EFBIG? */ goto error_return; @@ -520,7 +520,7 @@ xfs_setattr( if ((mask & XFS_AT_EXTSIZE) && vap->va_extsize != 0) { xfs_extlen_t size; - if (XFS_IS_REALTIME_INODE(ip) || + if ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) || ((mask & XFS_AT_XFLAGS) && (vap->va_xflags & XFS_XFLAG_REALTIME))) { size = mp->m_sb.sb_rextsize << @@ -804,8 +804,12 @@ xfs_setattr( if (vap->va_xflags & XFS_XFLAG_EXTSZINHERIT) di_flags |= XFS_DIFLAG_EXTSZINHERIT; } else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) { - if (vap->va_xflags & XFS_XFLAG_REALTIME) + if (vap->va_xflags & XFS_XFLAG_REALTIME) { di_flags |= XFS_DIFLAG_REALTIME; + ip->i_iocore.io_flags |= XFS_IOCORE_RT; + } else { + ip->i_iocore.io_flags &= ~XFS_IOCORE_RT; + } if (vap->va_xflags & XFS_XFLAG_EXTSIZE) di_flags |= XFS_DIFLAG_EXTSIZE; } @@ -898,6 +902,28 @@ xfs_setattr( return code; } + +/* + * xfs_access + * Null conversion from vnode mode bits to inode mode bits, as in efs. + */ +int +xfs_access( + xfs_inode_t *ip, + int mode, + cred_t *credp) +{ + int error; + + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + + xfs_ilock(ip, XFS_ILOCK_SHARED); + error = xfs_iaccess(ip, mode, credp); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return error; +} + + /* * The maximum pathlen is 1024 bytes. Since the minimum file system * blocksize is 512 bytes, we can get a max of 2 extents back from @@ -961,7 +987,7 @@ xfs_readlink( int pathlen; int error = 0; - xfs_itrace_entry(ip); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -1007,7 +1033,7 @@ xfs_fsync( int error; int log_flushed = 0, changed = 1; - xfs_itrace_entry(ip); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); ASSERT(start >= 0 && stop >= -1); @@ -1123,7 +1149,7 @@ xfs_fsync( * If this inode is on the RT dev we need to flush that * cache as well. */ - if (XFS_IS_REALTIME_INODE(ip)) + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) xfs_blkdev_issue_flush(ip->i_mount->m_rtdev_targp); } @@ -1162,7 +1188,7 @@ xfs_free_eofblocks( nimaps = 1; xfs_ilock(ip, XFS_ILOCK_SHARED); - error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0, + error = XFS_BMAPI(mp, NULL, &ip->i_iocore, end_fsb, map_len, 0, NULL, 0, &imap, &nimaps, NULL, NULL); xfs_iunlock(ip, XFS_ILOCK_SHARED); @@ -1536,6 +1562,9 @@ xfs_release( error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK); if (error) return error; + /* Update linux inode block count after free above */ + vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp, + ip->i_d.di_nblocks + ip->i_delayed_blks); } } @@ -1563,7 +1592,7 @@ xfs_inactive( int error; int truncate; - xfs_itrace_entry(ip); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); /* * If the inode is already free, then there can be nothing @@ -1609,6 +1638,9 @@ xfs_inactive( error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK); if (error) return VN_INACTIVE_CACHE; + /* Update linux inode block count after free above */ + vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp, + ip->i_d.di_nblocks + ip->i_delayed_blks); } goto out; } @@ -1773,7 +1805,7 @@ xfs_lookup( int error; uint lock_mode; - xfs_itrace_entry(dp); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return XFS_ERROR(EIO); @@ -1782,7 +1814,7 @@ xfs_lookup( error = xfs_dir_lookup_int(dp, lock_mode, dentry, &e_inum, &ip); if (!error) { *vpp = XFS_ITOV(ip); - xfs_itrace_ref(ip); + ITRACE(ip); } xfs_iunlock_map_shared(dp, lock_mode); return error; @@ -1816,7 +1848,7 @@ xfs_create( int namelen; ASSERT(!*vpp); - xfs_itrace_entry(dp); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); namelen = VNAMELEN(dentry); @@ -1898,7 +1930,7 @@ xfs_create( goto error_return; goto abort_return; } - xfs_itrace_ref(ip); + ITRACE(ip); /* * At this point, we've gotten a newly allocated inode. @@ -2066,7 +2098,7 @@ xfs_lock_dir_and_entry( e_inum = ip->i_ino; - xfs_itrace_ref(ip); + ITRACE(ip); /* * We want to lock in increasing inum. Since we've already @@ -2289,7 +2321,7 @@ xfs_remove( uint resblks; int namelen; - xfs_itrace_entry(dp); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -2332,8 +2364,9 @@ xfs_remove( dm_di_mode = ip->i_d.di_mode; - xfs_itrace_entry(ip); - xfs_itrace_ref(ip); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + + ITRACE(ip); error = XFS_QM_DQATTACH(mp, dp, 0); if (!error && dp != ip) @@ -2465,7 +2498,8 @@ xfs_remove( if (link_zero && xfs_inode_is_filestream(ip)) xfs_filestream_deassociate(ip); - xfs_itrace_exit(ip); + vn_trace_exit(ip, __FUNCTION__, (inst_t *)__return_address); + IRELE(ip); /* Fall through to std_return with error = 0 */ @@ -2528,8 +2562,8 @@ xfs_link( char *target_name = VNAME(dentry); int target_namelen; - xfs_itrace_entry(tdp); - xfs_itrace_entry(xfs_vtoi(src_vp)); + vn_trace_entry(tdp, __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(xfs_vtoi(src_vp), __FUNCTION__, (inst_t *)__return_address); target_namelen = VNAMELEN(dentry); ASSERT(!VN_ISDIR(src_vp)); @@ -2710,7 +2744,7 @@ xfs_mkdir( /* Return through std_return after this point. */ - xfs_itrace_entry(dp); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); mp = dp->i_mount; udqp = gdqp = NULL; @@ -2776,7 +2810,7 @@ xfs_mkdir( goto error_return; goto abort_return; } - xfs_itrace_ref(cdp); + ITRACE(cdp); /* * Now we add the directory inode to the transaction. @@ -2902,7 +2936,7 @@ xfs_rmdir( int last_cdp_link; uint resblks; - xfs_itrace_entry(dp); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -3007,7 +3041,7 @@ xfs_rmdir( VN_HOLD(dir_vp); } - xfs_itrace_ref(cdp); + ITRACE(cdp); xfs_trans_ijoin(tp, cdp, XFS_ILOCK_EXCL); ASSERT(cdp->i_d.di_nlink >= 2); @@ -3155,7 +3189,8 @@ xfs_symlink( ip = NULL; tp = NULL; - xfs_itrace_entry(dp); + vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); + if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -3282,7 +3317,7 @@ xfs_symlink( goto error_return; goto error1; } - xfs_itrace_ref(ip); + ITRACE(ip); /* * An error after we've joined dp to the transaction will result in the @@ -3430,6 +3465,27 @@ xfs_symlink( goto std_return; } + +int +xfs_fid2( + xfs_inode_t *ip, + xfs_fid_t *xfid) +{ + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + + xfid->fid_len = sizeof(xfs_fid_t) - sizeof(xfid->fid_len); + xfid->fid_pad = 0; + /* + * use memcpy because the inode is a long long and there's no + * assurance that xfid->fid_ino is properly aligned. + */ + memcpy(&xfid->fid_ino, &ip->i_ino, sizeof(xfid->fid_ino)); + xfid->fid_gen = ip->i_d.di_gen; + + return 0; +} + + int xfs_rwlock( xfs_inode_t *ip, @@ -3502,11 +3558,11 @@ xfs_inode_flush( if (iip && iip->ili_last_lsn) { xlog_t *log = mp->m_log; xfs_lsn_t sync_lsn; - int log_flags = XFS_LOG_FORCE; + int s, log_flags = XFS_LOG_FORCE; - spin_lock(&log->l_grant_lock); + s = GRANT_LOCK(log); sync_lsn = log->l_last_sync_lsn; - spin_unlock(&log->l_grant_lock); + GRANT_UNLOCK(log, s); if ((XFS_LSN_CMP(iip->ili_last_lsn, sync_lsn) > 0)) { if (flags & FLUSH_SYNC) @@ -3581,8 +3637,8 @@ xfs_set_dmattrs( xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); - ip->i_d.di_dmevmask = evmask; - ip->i_d.di_dmstate = state; + ip->i_iocore.io_dmevmask = ip->i_d.di_dmevmask = evmask; + ip->i_iocore.io_dmstate = ip->i_d.di_dmstate = state; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); IHOLD(ip); @@ -3597,7 +3653,7 @@ xfs_reclaim( { bhv_vnode_t *vp = XFS_ITOV(ip); - xfs_itrace_entry(ip); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); ASSERT(!VN_MAPPED(vp)); @@ -3815,7 +3871,7 @@ xfs_alloc_file_space( int committed; int error; - xfs_itrace_entry(ip); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -3920,7 +3976,7 @@ xfs_alloc_file_space( * Issue the xfs_bmapi() call to allocate the blocks */ XFS_BMAP_INIT(&free_list, &firstfsb); - error = xfs_bmapi(tp, ip, startoffset_fsb, + error = XFS_BMAPI(mp, tp, &ip->i_iocore, startoffset_fsb, allocatesize_fsb, bmapi_flag, &firstfsb, 0, imapp, &nimaps, &free_list, NULL); @@ -3996,13 +4052,13 @@ xfs_zero_remaining_bytes( int error = 0; bp = xfs_buf_get_noaddr(mp->m_sb.sb_blocksize, - XFS_IS_REALTIME_INODE(ip) ? + ip->i_d.di_flags & XFS_DIFLAG_REALTIME ? mp->m_rtdev_targp : mp->m_ddev_targp); for (offset = startoff; offset <= endoff; offset = lastoffset + 1) { offset_fsb = XFS_B_TO_FSBT(mp, offset); nimap = 1; - error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0, + error = XFS_BMAPI(mp, NULL, &ip->i_iocore, offset_fsb, 1, 0, NULL, 0, &imap, &nimap, NULL, NULL); if (error || nimap < 1) break; @@ -4085,7 +4141,7 @@ xfs_free_file_space( vp = XFS_ITOV(ip); mp = ip->i_mount; - xfs_itrace_entry(ip); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); if ((error = XFS_QM_DQATTACH(mp, ip, 0))) return error; @@ -4093,7 +4149,7 @@ xfs_free_file_space( error = 0; if (len <= 0) /* if nothing being freed */ return error; - rt = XFS_IS_REALTIME_INODE(ip); + rt = (ip->i_d.di_flags & XFS_DIFLAG_REALTIME); startoffset_fsb = XFS_B_TO_FSB(mp, offset); end_dmi_offset = offset + len; endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset); @@ -4116,12 +4172,15 @@ xfs_free_file_space( vn_iowait(ip); /* wait for the completion of any pending DIOs */ } - rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE); + rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, NBPP); ioffset = offset & ~(rounding - 1); if (VN_CACHED(vp) != 0) { - xfs_inval_cached_trace(ip, ioffset, -1, ioffset, -1); - error = xfs_flushinval_pages(ip, ioffset, -1, FI_REMAPF_LOCKED); + xfs_inval_cached_trace(&ip->i_iocore, ioffset, -1, + ctooff(offtoct(ioffset)), -1); + error = xfs_flushinval_pages(ip, + ctooff(offtoct(ioffset)), + -1, FI_REMAPF_LOCKED); if (error) goto out_unlock_iolock; } @@ -4134,7 +4193,7 @@ xfs_free_file_space( */ if (rt && !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) { nimap = 1; - error = xfs_bmapi(NULL, ip, startoffset_fsb, + error = XFS_BMAPI(mp, NULL, &ip->i_iocore, startoffset_fsb, 1, 0, NULL, 0, &imap, &nimap, NULL, NULL); if (error) goto out_unlock_iolock; @@ -4149,7 +4208,7 @@ xfs_free_file_space( startoffset_fsb += mp->m_sb.sb_rextsize - mod; } nimap = 1; - error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, + error = XFS_BMAPI(mp, NULL, &ip->i_iocore, endoffset_fsb - 1, 1, 0, NULL, 0, &imap, &nimap, NULL, NULL); if (error) goto out_unlock_iolock; @@ -4225,7 +4284,7 @@ xfs_free_file_space( * issue the bunmapi() call to free the blocks */ XFS_BMAP_INIT(&free_list, &firstfsb); - error = xfs_bunmapi(tp, ip, startoffset_fsb, + error = XFS_BUNMAPI(mp, tp, &ip->i_iocore, startoffset_fsb, endoffset_fsb - startoffset_fsb, 0, 2, &firstfsb, &free_list, NULL, &done); if (error) { @@ -4288,11 +4347,23 @@ xfs_change_file_space( xfs_trans_t *tp; bhv_vattr_t va; - xfs_itrace_entry(ip); + vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + /* + * must be a regular file and have write permission + */ if (!S_ISREG(ip->i_d.di_mode)) return XFS_ERROR(EINVAL); + xfs_ilock(ip, XFS_ILOCK_SHARED); + + if ((error = xfs_iaccess(ip, S_IWUSR, credp))) { + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return error; + } + + xfs_iunlock(ip, XFS_ILOCK_SHARED); + switch (bf->l_whence) { case 0: /*SEEK_SET*/ break; diff --git a/trunk/fs/xfs/xfs_vnodeops.h b/trunk/fs/xfs/xfs_vnodeops.h index 4e3970f0e5e3..b7e461c40cfb 100644 --- a/trunk/fs/xfs/xfs_vnodeops.h +++ b/trunk/fs/xfs/xfs_vnodeops.h @@ -18,6 +18,7 @@ int xfs_open(struct xfs_inode *ip); int xfs_getattr(struct xfs_inode *ip, struct bhv_vattr *vap, int flags); int xfs_setattr(struct xfs_inode *ip, struct bhv_vattr *vap, int flags, struct cred *credp); +int xfs_access(struct xfs_inode *ip, int mode, struct cred *credp); int xfs_readlink(struct xfs_inode *ip, char *link); int xfs_fsync(struct xfs_inode *ip, int flag, xfs_off_t start, xfs_off_t stop); @@ -38,6 +39,7 @@ int xfs_readdir(struct xfs_inode *dp, void *dirent, size_t bufsize, int xfs_symlink(struct xfs_inode *dp, bhv_vname_t *dentry, char *target_path, mode_t mode, bhv_vnode_t **vpp, struct cred *credp); +int xfs_fid2(struct xfs_inode *ip, struct xfs_fid *xfid); int xfs_rwlock(struct xfs_inode *ip, bhv_vrwlock_t locktype); void xfs_rwunlock(struct xfs_inode *ip, bhv_vrwlock_t locktype); int xfs_inode_flush(struct xfs_inode *ip, int flags); diff --git a/trunk/include/linux/dmi.h b/trunk/include/linux/dmi.h index b1251b2af568..bbc9992ec374 100644 --- a/trunk/include/linux/dmi.h +++ b/trunk/include/linux/dmi.h @@ -79,6 +79,7 @@ extern void dmi_scan_machine(void); extern int dmi_get_year(int field); extern int dmi_name_in_vendors(const char *str); extern int dmi_available; +extern int dmi_walk(void (*decode)(const struct dmi_header *)); #else @@ -89,6 +90,8 @@ static inline const struct dmi_device * dmi_find_device(int type, const char *na static inline int dmi_get_year(int year) { return 0; } static inline int dmi_name_in_vendors(const char *s) { return 0; } #define dmi_available 0 +static inline int dmi_walk(void (*decode)(const struct dmi_header *)) + { return -1; } #endif diff --git a/trunk/include/linux/enclosure.h b/trunk/include/linux/enclosure.h deleted file mode 100644 index a5978f18ca40..000000000000 --- a/trunk/include/linux/enclosure.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Enclosure Services - * - * Copyright (C) 2008 James Bottomley - * -**----------------------------------------------------------------------------- -** -** This program is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License -** version 2 as published by the Free Software Foundation. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -**----------------------------------------------------------------------------- -*/ -#ifndef _LINUX_ENCLOSURE_H_ -#define _LINUX_ENCLOSURE_H_ - -#include -#include - -/* A few generic types ... taken from ses-2 */ -enum enclosure_component_type { - ENCLOSURE_COMPONENT_DEVICE = 0x01, - ENCLOSURE_COMPONENT_ARRAY_DEVICE = 0x17, -}; - -/* ses-2 common element status */ -enum enclosure_status { - ENCLOSURE_STATUS_UNSUPPORTED = 0, - ENCLOSURE_STATUS_OK, - ENCLOSURE_STATUS_CRITICAL, - ENCLOSURE_STATUS_NON_CRITICAL, - ENCLOSURE_STATUS_UNRECOVERABLE, - ENCLOSURE_STATUS_NOT_INSTALLED, - ENCLOSURE_STATUS_UNKNOWN, - ENCLOSURE_STATUS_UNAVAILABLE, -}; - -/* SFF-8485 activity light settings */ -enum enclosure_component_setting { - ENCLOSURE_SETTING_DISABLED = 0, - ENCLOSURE_SETTING_ENABLED = 1, - ENCLOSURE_SETTING_BLINK_A_ON_OFF = 2, - ENCLOSURE_SETTING_BLINK_A_OFF_ON = 3, - ENCLOSURE_SETTING_BLINK_B_ON_OFF = 6, - ENCLOSURE_SETTING_BLINK_B_OFF_ON = 7, -}; - -struct enclosure_device; -struct enclosure_component; -struct enclosure_component_callbacks { - void (*get_status)(struct enclosure_device *, - struct enclosure_component *); - int (*set_status)(struct enclosure_device *, - struct enclosure_component *, - enum enclosure_status); - void (*get_fault)(struct enclosure_device *, - struct enclosure_component *); - int (*set_fault)(struct enclosure_device *, - struct enclosure_component *, - enum enclosure_component_setting); - void (*get_active)(struct enclosure_device *, - struct enclosure_component *); - int (*set_active)(struct enclosure_device *, - struct enclosure_component *, - enum enclosure_component_setting); - void (*get_locate)(struct enclosure_device *, - struct enclosure_component *); - int (*set_locate)(struct enclosure_device *, - struct enclosure_component *, - enum enclosure_component_setting); -}; - - -struct enclosure_component { - void *scratch; - struct class_device cdev; - enum enclosure_component_type type; - int number; - int fault; - int active; - int locate; - enum enclosure_status status; -}; - -struct enclosure_device { - void *scratch; - struct list_head node; - struct class_device cdev; - struct enclosure_component_callbacks *cb; - int components; - struct enclosure_component component[0]; -}; - -static inline struct enclosure_device * -to_enclosure_device(struct class_device *dev) -{ - return container_of(dev, struct enclosure_device, cdev); -} - -static inline struct enclosure_component * -to_enclosure_component(struct class_device *dev) -{ - return container_of(dev, struct enclosure_component, cdev); -} - -struct enclosure_device * -enclosure_register(struct device *, const char *, int, - struct enclosure_component_callbacks *); -void enclosure_unregister(struct enclosure_device *); -struct enclosure_component * -enclosure_component_register(struct enclosure_device *, unsigned int, - enum enclosure_component_type, const char *); -int enclosure_add_device(struct enclosure_device *enclosure, int component, - struct device *dev); -int enclosure_remove_device(struct enclosure_device *enclosure, int component); -struct enclosure_device *enclosure_find(struct device *dev); -int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *), - void *data); - -#endif /* _LINUX_ENCLOSURE_H_ */ diff --git a/trunk/include/linux/hrtimer.h b/trunk/include/linux/hrtimer.h index 203591e23210..8371b664b41f 100644 --- a/trunk/include/linux/hrtimer.h +++ b/trunk/include/linux/hrtimer.h @@ -225,14 +225,11 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer) * idea of the (in)accuracy of timers. Timer values are rounded up to * this resolution values. */ -# define HIGH_RES_NSEC 1 -# define KTIME_HIGH_RES (ktime_t) { .tv64 = HIGH_RES_NSEC } -# define MONOTONIC_RES_NSEC HIGH_RES_NSEC +# define KTIME_HIGH_RES (ktime_t) { .tv64 = 1 } # define KTIME_MONOTONIC_RES KTIME_HIGH_RES #else -# define MONOTONIC_RES_NSEC LOW_RES_NSEC # define KTIME_MONOTONIC_RES KTIME_LOW_RES /* diff --git a/trunk/include/linux/ktime.h b/trunk/include/linux/ktime.h index 36c542b70c6d..a6ddec141f96 100644 --- a/trunk/include/linux/ktime.h +++ b/trunk/include/linux/ktime.h @@ -316,8 +316,7 @@ static inline ktime_t ktime_sub_us(const ktime_t kt, const u64 usec) * idea of the (in)accuracy of timers. Timer values are rounded up to * this resolution values. */ -#define LOW_RES_NSEC TICK_NSEC -#define KTIME_LOW_RES (ktime_t){ .tv64 = LOW_RES_NSEC } +#define KTIME_LOW_RES (ktime_t){ .tv64 = TICK_NSEC } /* Get the monotonic time in timespec format: */ extern void ktime_get_ts(struct timespec *ts); diff --git a/trunk/include/linux/mm_types.h b/trunk/include/linux/mm_types.h index bfee0bd1d435..34023c65d466 100644 --- a/trunk/include/linux/mm_types.h +++ b/trunk/include/linux/mm_types.h @@ -64,10 +64,7 @@ struct page { #if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS spinlock_t ptl; #endif - struct { - struct kmem_cache *slab; /* SLUB: Pointer to slab */ - void *end; /* SLUB: end marker */ - }; + struct kmem_cache *slab; /* SLUB: Pointer to slab */ struct page *first_page; /* Compound tail pages */ }; union { diff --git a/trunk/include/linux/slub_def.h b/trunk/include/linux/slub_def.h index 5e6d3d634d5b..ddb1a706b144 100644 --- a/trunk/include/linux/slub_def.h +++ b/trunk/include/linux/slub_def.h @@ -11,35 +11,12 @@ #include #include -enum stat_item { - ALLOC_FASTPATH, /* Allocation from cpu slab */ - ALLOC_SLOWPATH, /* Allocation by getting a new cpu slab */ - FREE_FASTPATH, /* Free to cpu slub */ - FREE_SLOWPATH, /* Freeing not to cpu slab */ - FREE_FROZEN, /* Freeing to frozen slab */ - FREE_ADD_PARTIAL, /* Freeing moves slab to partial list */ - FREE_REMOVE_PARTIAL, /* Freeing removes last object */ - ALLOC_FROM_PARTIAL, /* Cpu slab acquired from partial list */ - ALLOC_SLAB, /* Cpu slab acquired from page allocator */ - ALLOC_REFILL, /* Refill cpu slab from slab freelist */ - FREE_SLAB, /* Slab freed to the page allocator */ - CPUSLAB_FLUSH, /* Abandoning of the cpu slab */ - DEACTIVATE_FULL, /* Cpu slab was full when deactivated */ - DEACTIVATE_EMPTY, /* Cpu slab was empty when deactivated */ - DEACTIVATE_TO_HEAD, /* Cpu slab was moved to the head of partials */ - DEACTIVATE_TO_TAIL, /* Cpu slab was moved to the tail of partials */ - DEACTIVATE_REMOTE_FREES,/* Slab contained remotely freed objects */ - NR_SLUB_STAT_ITEMS }; - struct kmem_cache_cpu { void **freelist; /* Pointer to first free per cpu object */ struct page *page; /* The slab from which we are allocating */ int node; /* The node of the page (or -1 for debug) */ unsigned int offset; /* Freepointer offset (in word units) */ unsigned int objsize; /* Size of an object (from kmem_cache) */ -#ifdef CONFIG_SLUB_STATS - unsigned stat[NR_SLUB_STAT_ITEMS]; -#endif }; struct kmem_cache_node { diff --git a/trunk/include/scsi/iscsi_proto.h b/trunk/include/scsi/iscsi_proto.h index 5ffec8ad6964..318a909e7ae1 100644 --- a/trunk/include/scsi/iscsi_proto.h +++ b/trunk/include/scsi/iscsi_proto.h @@ -45,8 +45,8 @@ /* initiator tags; opaque for target */ typedef uint32_t __bitwise__ itt_t; /* below makes sense only for initiator that created this tag */ -#define build_itt(itt, age) ((__force itt_t)\ - ((itt) | ((age) << ISCSI_AGE_SHIFT))) +#define build_itt(itt, id, age) ((__force itt_t)\ + ((itt) | ((id) << ISCSI_CID_SHIFT) | ((age) << ISCSI_AGE_SHIFT))) #define get_itt(itt) ((__force uint32_t)(itt_t)(itt) & ISCSI_ITT_MASK) #define RESERVED_ITT ((__force itt_t)0xffffffff) diff --git a/trunk/include/scsi/libiscsi.h b/trunk/include/scsi/libiscsi.h index 7b90b63fb5c7..889f51fabab9 100644 --- a/trunk/include/scsi/libiscsi.h +++ b/trunk/include/scsi/libiscsi.h @@ -70,6 +70,8 @@ enum { #define ISCSI_SUSPEND_BIT 1 #define ISCSI_ITT_MASK (0xfff) +#define ISCSI_CID_SHIFT 12 +#define ISCSI_CID_MASK (0xffff << ISCSI_CID_SHIFT) #define ISCSI_AGE_SHIFT 28 #define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT) @@ -133,14 +135,6 @@ static inline void* iscsi_next_hdr(struct iscsi_cmd_task *ctask) return (void*)ctask->hdr + ctask->hdr_len; } -/* Connection's states */ -enum { - ISCSI_CONN_INITIAL_STAGE, - ISCSI_CONN_STARTED, - ISCSI_CONN_STOPPED, - ISCSI_CONN_CLEANUP_WAIT, -}; - struct iscsi_conn { struct iscsi_cls_conn *cls_conn; /* ptr to class connection */ void *dd_data; /* iscsi_transport data */ @@ -233,17 +227,6 @@ struct iscsi_pool { int max; /* Max number of elements */ }; -/* Session's states */ -enum { - ISCSI_STATE_FREE = 1, - ISCSI_STATE_LOGGED_IN, - ISCSI_STATE_FAILED, - ISCSI_STATE_TERMINATE, - ISCSI_STATE_IN_RECOVERY, - ISCSI_STATE_RECOVERY_FAILED, - ISCSI_STATE_LOGGING_OUT, -}; - struct iscsi_session { /* * Syncs up the scsi eh thread with the iscsi eh thread when sending @@ -342,10 +325,6 @@ extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session, #define session_to_cls(_sess) \ hostdata_session(_sess->host->hostdata) -#define iscsi_session_printk(prefix, _sess, fmt, a...) \ - iscsi_cls_session_printk(prefix, \ - (struct iscsi_cls_session *)session_to_cls(_sess), fmt, ##a) - /* * connection management */ @@ -360,9 +339,6 @@ extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err); extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, char *buf); -#define iscsi_conn_printk(prefix, _c, fmt, a...) \ - iscsi_cls_conn_printk(prefix, _c->cls_conn, fmt, ##a) - /* * pdu and task processing */ @@ -373,6 +349,8 @@ extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *, char *, uint32_t); extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, char *, int); +extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, + char *, int); extern int iscsi_verify_itt(struct iscsi_conn *, struct iscsi_hdr *, uint32_t *); extern void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask); diff --git a/trunk/include/scsi/scsi.h b/trunk/include/scsi/scsi.h index 1f74bcd603fe..82251575a9b4 100644 --- a/trunk/include/scsi/scsi.h +++ b/trunk/include/scsi/scsi.h @@ -235,20 +235,6 @@ static inline int scsi_status_is_good(int status) #define TYPE_RBC 0x0e #define TYPE_NO_LUN 0x7f -/* SCSI protocols; these are taken from SPC-3 section 7.5 */ -enum scsi_protocol { - SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */ - SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */ - SCSI_PROTOCOL_SSA = 2, /* Serial Storage Architecture - Obsolete */ - SCSI_PROTOCOL_SBP = 3, /* firewire */ - SCSI_PROTOCOL_SRP = 4, /* Infiniband RDMA */ - SCSI_PROTOCOL_ISCSI = 5, - SCSI_PROTOCOL_SAS = 6, - SCSI_PROTOCOL_ADT = 7, /* Media Changers */ - SCSI_PROTOCOL_ATA = 8, - SCSI_PROTOCOL_UNSPEC = 0xf, /* No specific protocol */ -}; - /* Returns a human-readable name for the device */ extern const char * scsi_device_type(unsigned type); diff --git a/trunk/include/scsi/scsi_host.h b/trunk/include/scsi/scsi_host.h index d1299e999723..5c58d594126a 100644 --- a/trunk/include/scsi/scsi_host.h +++ b/trunk/include/scsi/scsi_host.h @@ -280,45 +280,39 @@ struct scsi_host_template { * If the host wants to be called before the scan starts, but * after the midlayer has set up ready for the scan, it can fill * in this function. - * - * Status: OPTIONAL */ void (* scan_start)(struct Scsi_Host *); /* - * Fill in this function to allow the queue depth of this host - * to be changeable (on a per device basis). Returns either + * fill in this function to allow the queue depth of this host + * to be changeable (on a per device basis). returns either * the current queue depth setting (may be different from what * was passed in) or an error. An error should only be * returned if the requested depth is legal but the driver was * unable to set it. If the requested depth is illegal, the * driver should set and return the closest legal queue depth. * - * Status: OPTIONAL */ int (* change_queue_depth)(struct scsi_device *, int); /* - * Fill in this function to allow the changing of tag types + * fill in this function to allow the changing of tag types * (this also allows the enabling/disabling of tag command * queueing). An error should only be returned if something * went wrong in the driver while trying to set the tag type. * If the driver doesn't support the requested tag type, then * it should set the closest type it does support without * returning an error. Returns the actual tag type set. - * - * Status: OPTIONAL */ int (* change_queue_type)(struct scsi_device *, int); /* - * This function determines the BIOS parameters for a given + * This function determines the bios parameters for a given * harddisk. These tend to be numbers that are made up by * the host adapter. Parameters: * size, device, list (heads, sectors, cylinders) * - * Status: OPTIONAL - */ + * Status: OPTIONAL */ int (* bios_param)(struct scsi_device *, struct block_device *, sector_t, int []); @@ -357,7 +351,7 @@ struct scsi_host_template { /* * This determines if we will use a non-interrupt driven - * or an interrupt driven scheme. It is set to the maximum number + * or an interrupt driven scheme, It is set to the maximum number * of simultaneous commands a given host adapter will accept. */ int can_queue; @@ -378,12 +372,12 @@ struct scsi_host_template { unsigned short sg_tablesize; /* - * Set this if the host adapter has limitations beside segment count. + * If the host adapter has limitations beside segment count */ unsigned short max_sectors; /* - * DMA scatter gather segment boundary limit. A segment crossing this + * dma scatter gather segment boundary limit. a segment crossing this * boundary will be split in two. */ unsigned long dma_boundary; @@ -392,7 +386,7 @@ struct scsi_host_template { * This specifies "machine infinity" for host templates which don't * limit the transfer size. Note this limit represents an absolute * maximum, and may be over the transfer limits allowed for - * individual devices (e.g. 256 for SCSI-1). + * individual devices (e.g. 256 for SCSI-1) */ #define SCSI_DEFAULT_MAX_SECTORS 1024 @@ -419,12 +413,12 @@ struct scsi_host_template { unsigned supported_mode:2; /* - * True if this host adapter uses unchecked DMA onto an ISA bus. + * true if this host adapter uses unchecked DMA onto an ISA bus. */ unsigned unchecked_isa_dma:1; /* - * True if this host adapter can make good use of clustering. + * true if this host adapter can make good use of clustering. * I originally thought that if the tablesize was large that it * was a waste of CPU cycles to prepare a cluster list, but * it works out that the Buslogic is faster if you use a smaller @@ -434,7 +428,7 @@ struct scsi_host_template { unsigned use_clustering:1; /* - * True for emulated SCSI host adapters (e.g. ATAPI). + * True for emulated SCSI host adapters (e.g. ATAPI) */ unsigned emulated:1; @@ -444,12 +438,12 @@ struct scsi_host_template { unsigned skip_settle_delay:1; /* - * True if we are using ordered write support. + * ordered write support */ unsigned ordered_tag:1; /* - * Countdown for host blocking with no commands outstanding. + * Countdown for host blocking with no commands outstanding */ unsigned int max_host_blocked; @@ -528,8 +522,8 @@ struct Scsi_Host { struct scsi_transport_template *transportt; /* - * Area to keep a shared tag map (if needed, will be - * NULL if not). + * area to keep a shared tag map (if needed, will be + * NULL if not) */ struct blk_queue_tag *bqt; @@ -602,16 +596,16 @@ struct Scsi_Host { /* * Host uses correct SCSI ordering not PC ordering. The bit is * set for the minority of drivers whose authors actually read - * the spec ;). + * the spec ;) */ unsigned reverse_ordering:1; /* - * Ordered write support + * ordered write support */ unsigned ordered_tag:1; - /* Task mgmt function in progress */ + /* task mgmt function in progress */ unsigned tmf_in_progress:1; /* Asynchronous scan in progress */ diff --git a/trunk/include/scsi/scsi_transport_iscsi.h b/trunk/include/scsi/scsi_transport_iscsi.h index dbc96ef4cc72..404f11d331d6 100644 --- a/trunk/include/scsi/scsi_transport_iscsi.h +++ b/trunk/include/scsi/scsi_transport_iscsi.h @@ -149,6 +149,13 @@ extern void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error); extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, char *data, uint32_t data_size); + +/* Connection's states */ +#define ISCSI_CONN_INITIAL_STAGE 0 +#define ISCSI_CONN_STARTED 1 +#define ISCSI_CONN_STOPPED 2 +#define ISCSI_CONN_CLEANUP_WAIT 3 + struct iscsi_cls_conn { struct list_head conn_list; /* item in connlist */ void *dd_data; /* LLD private data */ @@ -162,31 +169,27 @@ struct iscsi_cls_conn { #define iscsi_dev_to_conn(_dev) \ container_of(_dev, struct iscsi_cls_conn, dev) -#define iscsi_conn_to_session(_conn) \ - iscsi_dev_to_session(_conn->dev.parent) - -/* iscsi class session state */ -enum { - ISCSI_SESSION_LOGGED_IN, - ISCSI_SESSION_FAILED, - ISCSI_SESSION_FREE, -}; +/* Session's states */ +#define ISCSI_STATE_FREE 1 +#define ISCSI_STATE_LOGGED_IN 2 +#define ISCSI_STATE_FAILED 3 +#define ISCSI_STATE_TERMINATE 4 +#define ISCSI_STATE_IN_RECOVERY 5 +#define ISCSI_STATE_RECOVERY_FAILED 6 +#define ISCSI_STATE_LOGGING_OUT 7 struct iscsi_cls_session { struct list_head sess_list; /* item in session_list */ struct list_head host_list; struct iscsi_transport *transport; - spinlock_t lock; - struct work_struct scan_work; - struct work_struct unbind_work; /* recovery fields */ int recovery_tmo; struct delayed_work recovery_work; + struct work_struct unbind_work; int target_id; - int state; int sid; /* session id */ void *dd_data; /* LLD private data */ struct device dev; /* sysfs transport/container device */ @@ -203,22 +206,14 @@ struct iscsi_cls_session { struct iscsi_host { struct list_head sessions; - atomic_t nr_scans; struct mutex mutex; - struct workqueue_struct *scan_workq; - char scan_workq_name[KOBJ_NAME_LEN]; + struct workqueue_struct *unbind_workq; + char unbind_workq_name[KOBJ_NAME_LEN]; }; /* * session and connection functions that can be used by HW iSCSI LLDs */ -#define iscsi_cls_session_printk(prefix, _cls_session, fmt, a...) \ - dev_printk(prefix, &(_cls_session)->dev, fmt, ##a) - -#define iscsi_cls_conn_printk(prefix, _cls_conn, fmt, a...) \ - dev_printk(prefix, &(_cls_conn)->dev, fmt, ##a) - -extern int iscsi_session_chkready(struct iscsi_cls_session *session); extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport); extern int iscsi_add_session(struct iscsi_cls_session *session, @@ -236,6 +231,6 @@ extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess, extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); extern void iscsi_unblock_session(struct iscsi_cls_session *session); extern void iscsi_block_session(struct iscsi_cls_session *session); -extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time); + #endif diff --git a/trunk/lib/Kconfig.debug b/trunk/lib/Kconfig.debug index 4f4008fc73e4..0d385be682db 100644 --- a/trunk/lib/Kconfig.debug +++ b/trunk/lib/Kconfig.debug @@ -205,19 +205,6 @@ config SLUB_DEBUG_ON off in a kernel built with CONFIG_SLUB_DEBUG_ON by specifying "slub_debug=-". -config SLUB_STATS - default n - bool "Enable SLUB performance statistics" - depends on SLUB - help - SLUB statistics are useful to debug SLUBs allocation behavior in - order find ways to optimize the allocator. This should never be - enabled for production use since keeping statistics slows down - the allocator by a few percentage points. The slabinfo command - supports the determination of the most active slabs to figure - out which slabs are relevant to a particular load. - Try running: slabinfo -DA - config DEBUG_PREEMPT bool "Debug preemptible kernel" depends on DEBUG_KERNEL && PREEMPT && (TRACE_IRQFLAGS_SUPPORT || PPC64) diff --git a/trunk/mm/slub.c b/trunk/mm/slub.c index e2989ae243b5..3f056677fa8f 100644 --- a/trunk/mm/slub.c +++ b/trunk/mm/slub.c @@ -149,13 +149,6 @@ static inline void ClearSlabDebug(struct page *page) /* Enable to test recovery from slab corruption on boot */ #undef SLUB_RESILIENCY_TEST -/* - * Currently fastpath is not supported if preemption is enabled. - */ -#if defined(CONFIG_FAST_CMPXCHG_LOCAL) && !defined(CONFIG_PREEMPT) -#define SLUB_FASTPATH -#endif - #if PAGE_SHIFT <= 12 /* @@ -250,7 +243,6 @@ enum track_item { TRACK_ALLOC, TRACK_FREE }; static int sysfs_slab_add(struct kmem_cache *); static int sysfs_slab_alias(struct kmem_cache *, const char *); static void sysfs_slab_remove(struct kmem_cache *); - #else static inline int sysfs_slab_add(struct kmem_cache *s) { return 0; } static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p) @@ -259,16 +251,8 @@ static inline void sysfs_slab_remove(struct kmem_cache *s) { kfree(s); } - #endif -static inline void stat(struct kmem_cache_cpu *c, enum stat_item si) -{ -#ifdef CONFIG_SLUB_STATS - c->stat[si]++; -#endif -} - /******************************************************************** * Core slab cache functions *******************************************************************/ @@ -296,32 +280,15 @@ static inline struct kmem_cache_cpu *get_cpu_slab(struct kmem_cache *s, int cpu) #endif } -/* - * The end pointer in a slab is special. It points to the first object in the - * slab but has bit 0 set to mark it. - * - * Note that SLUB relies on page_mapping returning NULL for pages with bit 0 - * in the mapping set. - */ -static inline int is_end(void *addr) -{ - return (unsigned long)addr & PAGE_MAPPING_ANON; -} - -void *slab_address(struct page *page) -{ - return page->end - PAGE_MAPPING_ANON; -} - static inline int check_valid_pointer(struct kmem_cache *s, struct page *page, const void *object) { void *base; - if (object == page->end) + if (!object) return 1; - base = slab_address(page); + base = page_address(page); if (object < base || object >= base + s->objects * s->size || (object - base) % s->size) { return 0; @@ -354,8 +321,7 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp) /* Scan freelist */ #define for_each_free_object(__p, __s, __free) \ - for (__p = (__free); (__p) != page->end; __p = get_freepointer((__s),\ - __p)) + for (__p = (__free); __p; __p = get_freepointer((__s), __p)) /* Determine object index from a given position */ static inline int slab_index(void *p, struct kmem_cache *s, void *addr) @@ -507,7 +473,7 @@ static void slab_fix(struct kmem_cache *s, char *fmt, ...) static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p) { unsigned int off; /* Offset of last byte */ - u8 *addr = slab_address(page); + u8 *addr = page_address(page); print_tracking(s, p); @@ -685,7 +651,7 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page) if (!(s->flags & SLAB_POISON)) return 1; - start = slab_address(page); + start = page_address(page); end = start + (PAGE_SIZE << s->order); length = s->objects * s->size; remainder = end - (start + length); @@ -719,10 +685,9 @@ static int check_object(struct kmem_cache *s, struct page *page, endobject, red, s->inuse - s->objsize)) return 0; } else { - if ((s->flags & SLAB_POISON) && s->objsize < s->inuse) { - check_bytes_and_report(s, page, p, "Alignment padding", - endobject, POISON_INUSE, s->inuse - s->objsize); - } + if ((s->flags & SLAB_POISON) && s->objsize < s->inuse) + check_bytes_and_report(s, page, p, "Alignment padding", endobject, + POISON_INUSE, s->inuse - s->objsize); } if (s->flags & SLAB_POISON) { @@ -753,7 +718,7 @@ static int check_object(struct kmem_cache *s, struct page *page, * of the free objects in this slab. May cause * another error because the object count is now wrong. */ - set_freepointer(s, p, page->end); + set_freepointer(s, p, NULL); return 0; } return 1; @@ -787,18 +752,18 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search) void *fp = page->freelist; void *object = NULL; - while (fp != page->end && nr <= s->objects) { + while (fp && nr <= s->objects) { if (fp == search) return 1; if (!check_valid_pointer(s, page, fp)) { if (object) { object_err(s, page, object, "Freechain corrupt"); - set_freepointer(s, object, page->end); + set_freepointer(s, object, NULL); break; } else { slab_err(s, page, "Freepointer corrupt"); - page->freelist = page->end; + page->freelist = NULL; page->inuse = s->objects; slab_fix(s, "Freelist cleared"); return 0; @@ -904,7 +869,7 @@ static int alloc_debug_processing(struct kmem_cache *s, struct page *page, */ slab_fix(s, "Marking all objects used"); page->inuse = s->objects; - page->freelist = page->end; + page->freelist = NULL; } return 0; } @@ -929,10 +894,11 @@ static int free_debug_processing(struct kmem_cache *s, struct page *page, return 0; if (unlikely(s != page->slab)) { - if (!PageSlab(page)) { + if (!PageSlab(page)) slab_err(s, page, "Attempt to free object(0x%p) " "outside of slab", object); - } else if (!page->slab) { + else + if (!page->slab) { printk(KERN_ERR "SLUB : no slab for object 0x%p.\n", object); @@ -944,7 +910,7 @@ static int free_debug_processing(struct kmem_cache *s, struct page *page, } /* Special debug activities for freeing objects */ - if (!SlabFrozen(page) && page->freelist == page->end) + if (!SlabFrozen(page) && !page->freelist) remove_full(s, page); if (s->flags & SLAB_STORE_USER) set_track(s, object, TRACK_FREE, addr); @@ -1041,7 +1007,7 @@ static unsigned long kmem_cache_flags(unsigned long objsize, */ if (slub_debug && (!slub_debug_slabs || strncmp(slub_debug_slabs, name, - strlen(slub_debug_slabs)) == 0)) + strlen(slub_debug_slabs)) == 0)) flags |= slub_debug; } @@ -1136,7 +1102,6 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) SetSlabDebug(page); start = page_address(page); - page->end = start + 1; if (unlikely(s->flags & SLAB_POISON)) memset(start, POISON_INUSE, PAGE_SIZE << s->order); @@ -1148,7 +1113,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) last = p; } setup_object(s, page, last); - set_freepointer(s, last, page->end); + set_freepointer(s, last, NULL); page->freelist = start; page->inuse = 0; @@ -1164,7 +1129,7 @@ static void __free_slab(struct kmem_cache *s, struct page *page) void *p; slab_pad_check(s, page); - for_each_object(p, s, slab_address(page)) + for_each_object(p, s, page_address(page)) check_object(s, page, p, 0); ClearSlabDebug(page); } @@ -1174,7 +1139,6 @@ static void __free_slab(struct kmem_cache *s, struct page *page) NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE, -pages); - page->mapping = NULL; __free_pages(page, s->order); } @@ -1219,7 +1183,7 @@ static __always_inline void slab_lock(struct page *page) static __always_inline void slab_unlock(struct page *page) { - __bit_spin_unlock(PG_locked, &page->flags); + bit_spin_unlock(PG_locked, &page->flags); } static __always_inline int slab_trylock(struct page *page) @@ -1330,8 +1294,8 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags) get_cycles() % 1024 > s->remote_node_defrag_ratio) return NULL; - zonelist = &NODE_DATA( - slab_node(current->mempolicy))->node_zonelists[gfp_zone(flags)]; + zonelist = &NODE_DATA(slab_node(current->mempolicy)) + ->node_zonelists[gfp_zone(flags)]; for (z = zonelist->zones; *z; z++) { struct kmem_cache_node *n; @@ -1373,22 +1337,17 @@ static struct page *get_partial(struct kmem_cache *s, gfp_t flags, int node) static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail) { struct kmem_cache_node *n = get_node(s, page_to_nid(page)); - struct kmem_cache_cpu *c = get_cpu_slab(s, smp_processor_id()); ClearSlabFrozen(page); if (page->inuse) { - if (page->freelist != page->end) { + if (page->freelist) add_partial(n, page, tail); - stat(c, tail ? DEACTIVATE_TO_TAIL : DEACTIVATE_TO_HEAD); - } else { - stat(c, DEACTIVATE_FULL); - if (SlabDebug(page) && (s->flags & SLAB_STORE_USER)) - add_full(n, page); - } + else if (SlabDebug(page) && (s->flags & SLAB_STORE_USER)) + add_full(n, page); slab_unlock(page); + } else { - stat(c, DEACTIVATE_EMPTY); if (n->nr_partial < MIN_PARTIAL) { /* * Adding an empty slab to the partial slabs in order @@ -1402,7 +1361,6 @@ static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail) slab_unlock(page); } else { slab_unlock(page); - stat(get_cpu_slab(s, raw_smp_processor_id()), FREE_SLAB); discard_slab(s, page); } } @@ -1415,19 +1373,12 @@ static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c) { struct page *page = c->page; int tail = 1; - - if (c->freelist) - stat(c, DEACTIVATE_REMOTE_FREES); /* * Merge cpu freelist into freelist. Typically we get here * because both freelists are empty. So this is unlikely * to occur. - * - * We need to use _is_end here because deactivate slab may - * be called for a debug slab. Then c->freelist may contain - * a dummy pointer. */ - while (unlikely(!is_end(c->freelist))) { + while (unlikely(c->freelist)) { void **object; tail = 0; /* Hot objects. Put the slab first */ @@ -1447,7 +1398,6 @@ static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c) static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c) { - stat(c, CPUSLAB_FLUSH); slab_lock(c->page); deactivate_slab(s, c); } @@ -1519,21 +1469,16 @@ static void *__slab_alloc(struct kmem_cache *s, { void **object; struct page *new; -#ifdef SLUB_FASTPATH - unsigned long flags; - local_irq_save(flags); -#endif if (!c->page) goto new_slab; slab_lock(c->page); if (unlikely(!node_match(c, node))) goto another_slab; - stat(c, ALLOC_REFILL); load_freelist: object = c->page->freelist; - if (unlikely(object == c->page->end)) + if (unlikely(!object)) goto another_slab; if (unlikely(SlabDebug(c->page))) goto debug; @@ -1541,15 +1486,9 @@ static void *__slab_alloc(struct kmem_cache *s, object = c->page->freelist; c->freelist = object[c->offset]; c->page->inuse = s->objects; - c->page->freelist = c->page->end; + c->page->freelist = NULL; c->node = page_to_nid(c->page); -unlock_out: slab_unlock(c->page); - stat(c, ALLOC_SLOWPATH); -out: -#ifdef SLUB_FASTPATH - local_irq_restore(flags); -#endif return object; another_slab: @@ -1559,7 +1498,6 @@ static void *__slab_alloc(struct kmem_cache *s, new = get_partial(s, gfpflags, node); if (new) { c->page = new; - stat(c, ALLOC_FROM_PARTIAL); goto load_freelist; } @@ -1573,7 +1511,6 @@ static void *__slab_alloc(struct kmem_cache *s, if (new) { c = get_cpu_slab(s, smp_processor_id()); - stat(c, ALLOC_SLAB); if (c->page) flush_slab(s, c); slab_lock(new); @@ -1581,8 +1518,7 @@ static void *__slab_alloc(struct kmem_cache *s, c->page = new; goto load_freelist; } - object = NULL; - goto out; + return NULL; debug: object = c->page->freelist; if (!alloc_debug_processing(s, c->page, object, addr)) @@ -1591,7 +1527,8 @@ static void *__slab_alloc(struct kmem_cache *s, c->page->inuse++; c->page->freelist = object[c->offset]; c->node = -1; - goto unlock_out; + slab_unlock(c->page); + return object; } /* @@ -1608,50 +1545,20 @@ static __always_inline void *slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, void *addr) { void **object; - struct kmem_cache_cpu *c; - -/* - * The SLUB_FASTPATH path is provisional and is currently disabled if the - * kernel is compiled with preemption or if the arch does not support - * fast cmpxchg operations. There are a couple of coming changes that will - * simplify matters and allow preemption. Ultimately we may end up making - * SLUB_FASTPATH the default. - * - * 1. The introduction of the per cpu allocator will avoid array lookups - * through get_cpu_slab(). A special register can be used instead. - * - * 2. The introduction of per cpu atomic operations (cpu_ops) means that - * we can realize the logic here entirely with per cpu atomics. The - * per cpu atomic ops will take care of the preemption issues. - */ - -#ifdef SLUB_FASTPATH - c = get_cpu_slab(s, raw_smp_processor_id()); - do { - object = c->freelist; - if (unlikely(is_end(object) || !node_match(c, node))) { - object = __slab_alloc(s, gfpflags, node, addr, c); - break; - } - stat(c, ALLOC_FASTPATH); - } while (cmpxchg_local(&c->freelist, object, object[c->offset]) - != object); -#else unsigned long flags; + struct kmem_cache_cpu *c; local_irq_save(flags); c = get_cpu_slab(s, smp_processor_id()); - if (unlikely(is_end(c->freelist) || !node_match(c, node))) + if (unlikely(!c->freelist || !node_match(c, node))) object = __slab_alloc(s, gfpflags, node, addr, c); else { object = c->freelist; c->freelist = object[c->offset]; - stat(c, ALLOC_FASTPATH); } local_irq_restore(flags); -#endif if (unlikely((gfpflags & __GFP_ZERO) && object)) memset(object, 0, c->objsize); @@ -1686,15 +1593,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page, { void *prior; void **object = (void *)x; - struct kmem_cache_cpu *c; - -#ifdef SLUB_FASTPATH - unsigned long flags; - local_irq_save(flags); -#endif - c = get_cpu_slab(s, raw_smp_processor_id()); - stat(c, FREE_SLOWPATH); slab_lock(page); if (unlikely(SlabDebug(page))) @@ -1704,10 +1603,8 @@ static void __slab_free(struct kmem_cache *s, struct page *page, page->freelist = object; page->inuse--; - if (unlikely(SlabFrozen(page))) { - stat(c, FREE_FROZEN); + if (unlikely(SlabFrozen(page))) goto out_unlock; - } if (unlikely(!page->inuse)) goto slab_empty; @@ -1717,31 +1614,21 @@ static void __slab_free(struct kmem_cache *s, struct page *page, * was not on the partial list before * then add it. */ - if (unlikely(prior == page->end)) { + if (unlikely(!prior)) add_partial(get_node(s, page_to_nid(page)), page, 1); - stat(c, FREE_ADD_PARTIAL); - } out_unlock: slab_unlock(page); -#ifdef SLUB_FASTPATH - local_irq_restore(flags); -#endif return; slab_empty: - if (prior != page->end) { + if (prior) /* * Slab still on the partial list. */ remove_partial(s, page); - stat(c, FREE_REMOVE_PARTIAL); - } + slab_unlock(page); - stat(c, FREE_SLAB); -#ifdef SLUB_FASTPATH - local_irq_restore(flags); -#endif discard_slab(s, page); return; @@ -1766,36 +1653,8 @@ static __always_inline void slab_free(struct kmem_cache *s, struct page *page, void *x, void *addr) { void **object = (void *)x; - struct kmem_cache_cpu *c; - -#ifdef SLUB_FASTPATH - void **freelist; - - c = get_cpu_slab(s, raw_smp_processor_id()); - debug_check_no_locks_freed(object, s->objsize); - do { - freelist = c->freelist; - barrier(); - /* - * If the compiler would reorder the retrieval of c->page to - * come before c->freelist then an interrupt could - * change the cpu slab before we retrieve c->freelist. We - * could be matching on a page no longer active and put the - * object onto the freelist of the wrong slab. - * - * On the other hand: If we already have the freelist pointer - * then any change of cpu_slab will cause the cmpxchg to fail - * since the freelist pointers are unique per slab. - */ - if (unlikely(page != c->page || c->node < 0)) { - __slab_free(s, page, x, addr, c->offset); - break; - } - object[c->offset] = freelist; - stat(c, FREE_FASTPATH); - } while (cmpxchg_local(&c->freelist, freelist, object) != freelist); -#else unsigned long flags; + struct kmem_cache_cpu *c; local_irq_save(flags); debug_check_no_locks_freed(object, s->objsize); @@ -1803,12 +1662,10 @@ static __always_inline void slab_free(struct kmem_cache *s, if (likely(page == c->page && c->node >= 0)) { object[c->offset] = c->freelist; c->freelist = object; - stat(c, FREE_FASTPATH); } else __slab_free(s, page, x, addr, c->offset); local_irq_restore(flags); -#endif } void kmem_cache_free(struct kmem_cache *s, void *x) @@ -1985,7 +1842,7 @@ static void init_kmem_cache_cpu(struct kmem_cache *s, struct kmem_cache_cpu *c) { c->page = NULL; - c->freelist = (void *)PAGE_MAPPING_ANON; + c->freelist = NULL; c->node = 0; c->offset = s->offset / sizeof(void *); c->objsize = s->objsize; @@ -2589,8 +2446,7 @@ static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags) goto unlock_out; realsize = kmalloc_caches[index].objsize; - text = kasprintf(flags & ~SLUB_DMA, "kmalloc_dma-%d", - (unsigned int)realsize); + text = kasprintf(flags & ~SLUB_DMA, "kmalloc_dma-%d", (unsigned int)realsize), s = kmalloc(kmem_size, flags & ~SLUB_DMA); if (!s || !text || !kmem_cache_open(s, flags, text, @@ -2745,7 +2601,6 @@ EXPORT_SYMBOL(ksize); void kfree(const void *x) { struct page *page; - void *object = (void *)x; if (unlikely(ZERO_OR_NULL_PTR(x))) return; @@ -2755,7 +2610,7 @@ void kfree(const void *x) put_page(page); return; } - slab_free(page->slab, page, object, __builtin_return_address(0)); + slab_free(page->slab, page, (void *)x, __builtin_return_address(0)); } EXPORT_SYMBOL(kfree); @@ -3041,8 +2896,7 @@ void __init kmem_cache_init(void) #endif - printk(KERN_INFO - "SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d," + printk(KERN_INFO "SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d," " CPUs=%d, Nodes=%d\n", caches, cache_line_size(), slub_min_order, slub_max_order, slub_min_objects, @@ -3209,7 +3063,7 @@ static int __cpuinit slab_cpuup_callback(struct notifier_block *nfb, } static struct notifier_block __cpuinitdata slab_notifier = { - .notifier_call = slab_cpuup_callback + &slab_cpuup_callback, NULL, 0 }; #endif @@ -3250,7 +3104,7 @@ static int validate_slab(struct kmem_cache *s, struct page *page, unsigned long *map) { void *p; - void *addr = slab_address(page); + void *addr = page_address(page); if (!check_slab(s, page) || !on_freelist(s, page, NULL)) @@ -3367,9 +3221,8 @@ static void resiliency_test(void) p = kzalloc(32, GFP_KERNEL); p[32 + sizeof(void *)] = 0x34; printk(KERN_ERR "\n2. kmalloc-32: Clobber next pointer/next slab" - " 0x34 -> -0x%p\n", p); - printk(KERN_ERR - "If allocated object is overwritten then not detectable\n\n"); + " 0x34 -> -0x%p\n", p); + printk(KERN_ERR "If allocated object is overwritten then not detectable\n\n"); validate_slab_cache(kmalloc_caches + 5); p = kzalloc(64, GFP_KERNEL); @@ -3377,8 +3230,7 @@ static void resiliency_test(void) *p = 0x56; printk(KERN_ERR "\n3. kmalloc-64: corrupting random byte 0x56->0x%p\n", p); - printk(KERN_ERR - "If allocated object is overwritten then not detectable\n\n"); + printk(KERN_ERR "If allocated object is overwritten then not detectable\n\n"); validate_slab_cache(kmalloc_caches + 6); printk(KERN_ERR "\nB. Corruption after free\n"); @@ -3391,8 +3243,7 @@ static void resiliency_test(void) p = kzalloc(256, GFP_KERNEL); kfree(p); p[50] = 0x9a; - printk(KERN_ERR "\n2. kmalloc-256: Clobber 50th byte 0x9a->0x%p\n\n", - p); + printk(KERN_ERR "\n2. kmalloc-256: Clobber 50th byte 0x9a->0x%p\n\n", p); validate_slab_cache(kmalloc_caches + 8); p = kzalloc(512, GFP_KERNEL); @@ -3533,7 +3384,7 @@ static int add_location(struct loc_track *t, struct kmem_cache *s, static void process_slab(struct loc_track *t, struct kmem_cache *s, struct page *page, enum track_item alloc) { - void *addr = slab_address(page); + void *addr = page_address(page); DECLARE_BITMAP(map, s->objects); void *p; @@ -4021,62 +3872,6 @@ static ssize_t remote_node_defrag_ratio_store(struct kmem_cache *s, SLAB_ATTR(remote_node_defrag_ratio); #endif -#ifdef CONFIG_SLUB_STATS - -static int show_stat(struct kmem_cache *s, char *buf, enum stat_item si) -{ - unsigned long sum = 0; - int cpu; - int len; - int *data = kmalloc(nr_cpu_ids * sizeof(int), GFP_KERNEL); - - if (!data) - return -ENOMEM; - - for_each_online_cpu(cpu) { - unsigned x = get_cpu_slab(s, cpu)->stat[si]; - - data[cpu] = x; - sum += x; - } - - len = sprintf(buf, "%lu", sum); - - for_each_online_cpu(cpu) { - if (data[cpu] && len < PAGE_SIZE - 20) - len += sprintf(buf + len, " c%d=%u", cpu, data[cpu]); - } - kfree(data); - return len + sprintf(buf + len, "\n"); -} - -#define STAT_ATTR(si, text) \ -static ssize_t text##_show(struct kmem_cache *s, char *buf) \ -{ \ - return show_stat(s, buf, si); \ -} \ -SLAB_ATTR_RO(text); \ - -STAT_ATTR(ALLOC_FASTPATH, alloc_fastpath); -STAT_ATTR(ALLOC_SLOWPATH, alloc_slowpath); -STAT_ATTR(FREE_FASTPATH, free_fastpath); -STAT_ATTR(FREE_SLOWPATH, free_slowpath); -STAT_ATTR(FREE_FROZEN, free_frozen); -STAT_ATTR(FREE_ADD_PARTIAL, free_add_partial); -STAT_ATTR(FREE_REMOVE_PARTIAL, free_remove_partial); -STAT_ATTR(ALLOC_FROM_PARTIAL, alloc_from_partial); -STAT_ATTR(ALLOC_SLAB, alloc_slab); -STAT_ATTR(ALLOC_REFILL, alloc_refill); -STAT_ATTR(FREE_SLAB, free_slab); -STAT_ATTR(CPUSLAB_FLUSH, cpuslab_flush); -STAT_ATTR(DEACTIVATE_FULL, deactivate_full); -STAT_ATTR(DEACTIVATE_EMPTY, deactivate_empty); -STAT_ATTR(DEACTIVATE_TO_HEAD, deactivate_to_head); -STAT_ATTR(DEACTIVATE_TO_TAIL, deactivate_to_tail); -STAT_ATTR(DEACTIVATE_REMOTE_FREES, deactivate_remote_frees); - -#endif - static struct attribute *slab_attrs[] = { &slab_size_attr.attr, &object_size_attr.attr, @@ -4106,25 +3901,6 @@ static struct attribute *slab_attrs[] = { #endif #ifdef CONFIG_NUMA &remote_node_defrag_ratio_attr.attr, -#endif -#ifdef CONFIG_SLUB_STATS - &alloc_fastpath_attr.attr, - &alloc_slowpath_attr.attr, - &free_fastpath_attr.attr, - &free_slowpath_attr.attr, - &free_frozen_attr.attr, - &free_add_partial_attr.attr, - &free_remove_partial_attr.attr, - &alloc_from_partial_attr.attr, - &alloc_slab_attr.attr, - &alloc_refill_attr.attr, - &free_slab_attr.attr, - &cpuslab_flush_attr.attr, - &deactivate_full_attr.attr, - &deactivate_empty_attr.attr, - &deactivate_to_head_attr.attr, - &deactivate_to_tail_attr.attr, - &deactivate_remote_frees_attr.attr, #endif NULL };