diff options
232 files changed, 12843 insertions, 15036 deletions
diff --git a/Documentation/DocBook/scsi.tmpl b/Documentation/DocBook/scsi.tmpl index f299ab182bbe..10a150ae2a7e 100644 --- a/Documentation/DocBook/scsi.tmpl +++ b/Documentation/DocBook/scsi.tmpl @@ -12,7 +12,7 @@ <surname>Bottomley</surname> <affiliation> <address> - <email>James.Bottomley@steeleye.com</email> + <email>James.Bottomley@hansenpartnership.com</email> </address> </affiliation> </author> diff --git a/Documentation/hwmon/ads7828 b/Documentation/hwmon/ads7828 new file mode 100644 index 000000000000..75bc4beaf447 --- /dev/null +++ b/Documentation/hwmon/ads7828 @@ -0,0 +1,36 @@ +Kernel driver ads7828 +===================== + +Supported chips: + * Texas Instruments/Burr-Brown ADS7828 + Prefix: 'ads7828' + Addresses scanned: I2C 0x48, 0x49, 0x4a, 0x4b + Datasheet: Publicly available at the Texas Instruments website : + http://focus.ti.com/lit/ds/symlink/ads7828.pdf + +Authors: + Steve Hardy <steve@linuxrealtime.co.uk> + +Module Parameters +----------------- + +* se_input: bool (default Y) + Single ended operation - set to N for differential mode +* int_vref: bool (default Y) + Operate with the internal 2.5V reference - set to N for external reference +* vref_mv: int (default 2500) + If using an external reference, set this to the reference voltage in mV + +Description +----------- + +This driver implements support for the Texas Instruments ADS7828. + +This device is a 12-bit 8-channel A-D converter. + +It can operate in single ended mode (8 +ve inputs) or in differential mode, +where 4 differential pairs can be measured. + +The chip also has the facility to use an external voltage reference. This +may be required if your hardware supplies the ADS7828 from a 5V supply, see +the datasheet for more details. diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index 5b704a40256b..f4ce1fdbeff6 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -30,7 +30,7 @@ Supported chips: Datasheet: No longer be available Authors: - Christophe Gauthron <chrisg@0-in.com> + Christophe Gauthron Jean Delvare <khali@linux-fr.org> diff --git a/Documentation/hwmon/lm78 b/Documentation/hwmon/lm78 index dfc318a60fd4..60932e26abaa 100644 --- a/Documentation/hwmon/lm78 +++ b/Documentation/hwmon/lm78 @@ -4,12 +4,12 @@ Kernel driver lm78 Supported chips: * National Semiconductor LM78 / LM78-J Prefix: 'lm78' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Addresses scanned: I2C 0x28 - 0x2f, ISA 0x290 (8 I/O ports) Datasheet: Publicly available at the National Semiconductor website http://www.national.com/ * National Semiconductor LM79 Prefix: 'lm79' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Addresses scanned: I2C 0x28 - 0x2f, ISA 0x290 (8 I/O ports) Datasheet: Publicly available at the National Semiconductor website http://www.national.com/ diff --git a/Documentation/hwmon/lm87 b/Documentation/hwmon/lm87 index c952c57f0e11..ec27aa1b94cb 100644 --- a/Documentation/hwmon/lm87 +++ b/Documentation/hwmon/lm87 @@ -4,8 +4,12 @@ Kernel driver lm87 Supported chips: * National Semiconductor LM87 Prefix: 'lm87' - Addresses scanned: I2C 0x2c - 0x2f + Addresses scanned: I2C 0x2c - 0x2e Datasheet: http://www.national.com/pf/LM/LM87.html + * Analog Devices ADM1024 + Prefix: 'adm1024' + Addresses scanned: I2C 0x2c - 0x2e + Datasheet: http://www.analog.com/en/prod/0,2877,ADM1024,00.html Authors: Frodo Looijaard <frodol@dds.nl>, @@ -19,11 +23,12 @@ Authors: Description ----------- -This driver implements support for the National Semiconductor LM87. +This driver implements support for the National Semiconductor LM87 +and the Analog Devices ADM1024. The LM87 implements up to three temperature sensors, up to two fan rotation speed sensors, up to seven voltage sensors, alarms, and some -miscellaneous stuff. +miscellaneous stuff. The ADM1024 is fully compatible. Temperatures are measured in degrees Celsius. Each input has a high and low alarm settings. A high limit produces an alarm when the value diff --git a/Documentation/hwmon/userspace-tools b/Documentation/hwmon/userspace-tools index 19900a8fe679..9865aeedc58f 100644 --- a/Documentation/hwmon/userspace-tools +++ b/Documentation/hwmon/userspace-tools @@ -14,7 +14,7 @@ Lm-sensors Core set of utilities that will allow you to obtain health information, setup monitoring limits etc. You can get them on their homepage -http://www.lm-sensors.nu/ or as a package from your Linux distribution. +http://www.lm-sensors.org/ or as a package from your Linux distribution. If from website: Get lm-sensors from project web site. Please note, you need only userspace diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf index ccc2bcb61068..d6e1ae30fa6e 100644 --- a/Documentation/hwmon/w83627ehf +++ b/Documentation/hwmon/w83627ehf @@ -23,8 +23,9 @@ W83627DHG super I/O chips. We will refer to them collectively as Winbond chips. The chips implement three temperature sensors, five fan rotation speed sensors, ten analog voltage sensors (only nine for the 627DHG), one -VID (6 pins), alarms with beep warnings (control unimplemented), and -some automatic fan regulation strategies (plus manual fan control mode). +VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG), alarms with beep +warnings (control unimplemented), and some automatic fan regulation +strategies (plus manual fan control mode). Temperatures are measured in degrees Celsius and measurement resolution is 1 degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when diff --git a/Documentation/hwmon/w83627hf b/Documentation/hwmon/w83627hf index 792231921241..880a59f53da9 100644 --- a/Documentation/hwmon/w83627hf +++ b/Documentation/hwmon/w83627hf @@ -73,5 +73,4 @@ doesn't help, you may just ignore the bogus VID reading with no harm done. For further information on this driver see the w83781d driver documentation. -[1] http://www2.lm-sensors.nu/~lm78/cvs/browse.cgi/lm_sensors2/doc/vid - +[1] http://www.lm-sensors.org/browser/lm-sensors/trunk/doc/vid diff --git a/Documentation/hwmon/w83781d b/Documentation/hwmon/w83781d index b1e9f80098ee..6f800a0283e9 100644 --- a/Documentation/hwmon/w83781d +++ b/Documentation/hwmon/w83781d @@ -4,20 +4,16 @@ Kernel driver w83781d Supported chips: * Winbond W83781D Prefix: 'w83781d' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Addresses scanned: I2C 0x28 - 0x2f, ISA 0x290 (8 I/O ports) Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83781d.pdf * Winbond W83782D Prefix: 'w83782d' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Addresses scanned: I2C 0x28 - 0x2f, ISA 0x290 (8 I/O ports) Datasheet: http://www.winbond.com/PDF/sheet/w83782d.pdf * Winbond W83783S Prefix: 'w83783s' Addresses scanned: I2C 0x2d Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83783s.pdf - * Winbond W83627HF - Prefix: 'w83627hf' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) - Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf * Asus AS99127F Prefix: 'as99127f' Addresses scanned: I2C 0x28 - 0x2f @@ -50,20 +46,18 @@ force_subclients=bus,caddr,saddr,saddr Description ----------- -This driver implements support for the Winbond W83781D, W83782D, W83783S, -W83627HF chips, and the Asus AS99127F chips. We will refer to them -collectively as W8378* chips. +This driver implements support for the Winbond W83781D, W83782D, W83783S +chips, and the Asus AS99127F chips. We will refer to them collectively as +W8378* chips. There is quite some difference between these chips, but they are similar enough that it was sensible to put them together in one driver. -The W83627HF chip is assumed to be identical to the ISA W83782D. The Asus chips are similar to an I2C-only W83782D. Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA as99127f 7 3 0 3 0x31 0x12c3 yes no as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes -w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no @@ -143,9 +137,9 @@ Individual alarm and beep bits: 0x000400: in6 0x000800: fan3 0x001000: chassis -0x002000: temp3 (W83782D and W83627HF only) -0x010000: in7 (W83782D and W83627HF only) -0x020000: in8 (W83782D and W83627HF only) +0x002000: temp3 (W83782D only) +0x010000: in7 (W83782D only) +0x020000: in8 (W83782D only) If an alarm triggers, it will remain triggered until the hardware register is read at least once. This means that the cause for the alarm may diff --git a/Documentation/hwmon/w83l786ng b/Documentation/hwmon/w83l786ng new file mode 100644 index 000000000000..d8f55d7fff10 --- /dev/null +++ b/Documentation/hwmon/w83l786ng @@ -0,0 +1,54 @@ +Kernel driver w83l786ng +===================== + +Supported chips: + * Winbond W83L786NG/W83L786NR + Prefix: 'w83l786ng' + Addresses scanned: I2C 0x2e - 0x2f + Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L786NRNG09.pdf + +Author: Kevin Lo <kevlo@kevlo.org> + + +Module Parameters +----------------- + +* reset boolean + (default 0) + Use 'reset=1' to reset the chip (via index 0x40, bit 7). The default + behavior is no chip reset to preserve BIOS settings + + +Description +----------- + +This driver implements support for Winbond W83L786NG/W83L786NR chips. + +The driver implements two temperature sensors, two fan rotation speed +sensors, and three voltage sensors. + +Temperatures are measured in degrees Celsius and measurement resolution is 1 +degC for temp1 and temp2. + +Fan rotation speeds are reported in RPM (rotations per minute). Fan readings +readings can be divided by a programmable divider (1, 2, 4, 8, 16, 32, 64 +or 128 for fan 1/2) to give the readings more range or accuracy. + +Voltage sensors (also known as IN sensors) report their values in millivolts. +An alarm is triggered if the voltage has crossed a programmable minimum +or maximum limit. + +/sys files +---------- + +pwm[1-2] - this file stores PWM duty cycle or DC value (fan speed) in range: + 0 (stop) to 255 (full) +pwm[1-2]_enable - this file controls mode of fan/temperature control: + * 0 Manual Mode + * 1 Thermal Cruise + * 2 Smart Fan II + * 4 FAN_SET +pwm[1-2]_mode - Select PWM of DC mode + * 0 DC + * 1 PWM +tolerance[1-2] - Value in degrees of Celsius (degC) for +- T diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4 index cf6b6cb02aa1..ef1efa79b1df 100644 --- a/Documentation/i2c/busses/i2c-piix4 +++ b/Documentation/i2c/busses/i2c-piix4 @@ -95,4 +95,4 @@ of all affected systems, so the only safe solution was to prevent access to the SMBus on all IBM systems (detected using DMI data.) For additional information, read: -http://www2.lm-sensors.nu/~lm78/cvs/lm_sensors2/README.thinkpad +http://www.lm-sensors.org/browser/lm-sensors/trunk/README.thinkpad diff --git a/Documentation/scsi/ChangeLog.arcmsr b/Documentation/scsi/ChangeLog.arcmsr index cd8403a33ee6..de2bcacfa870 100644 --- a/Documentation/scsi/ChangeLog.arcmsr +++ b/Documentation/scsi/ChangeLog.arcmsr @@ -68,4 +68,45 @@ ** 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 <mbroz@redhat.com> +** 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/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt index 6f70f2b9327e..a6d5354639b2 100644 --- a/Documentation/scsi/scsi_mid_low_api.txt +++ b/Documentation/scsi/scsi_mid_low_api.txt @@ -1407,7 +1407,7 @@ Credits ======= The following people have contributed to this document: Mike Anderson <andmike at us dot ibm dot com> - James Bottomley <James dot Bottomley at steeleye dot com> + James Bottomley <James dot Bottomley at hansenpartnership dot com> Patrick Mansfield <patmans at us dot ibm dot com> Christoph Hellwig <hch at infradead dot org> Doug Ledford <dledford at redhat dot com> diff --git a/Documentation/vm/slabinfo.c b/Documentation/vm/slabinfo.c index 488c1f31b992..7123fee708ca 100644 --- a/Documentation/vm/slabinfo.c +++ b/Documentation/vm/slabinfo.c @@ -32,6 +32,13 @@ 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]; @@ -64,8 +71,10 @@ 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; @@ -93,8 +102,10 @@ 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<options>|--debug=<options> Set/Clear Debug options\n" - "-e|--empty Show empty slabs\n" + "-D|--display-active Switch line format to activity\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" @@ -281,8 +292,11 @@ int line = 0; void first_line(void) { - printf("Name Objects Objsize Space " - "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n"); + 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"); } /* @@ -309,6 +323,12 @@ 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; @@ -392,6 +412,71 @@ 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) @@ -430,6 +515,7 @@ void report(struct slabinfo *s) ops(s); show_tracking(s); slab_numa(s, 1); + slab_stats(s); } void slabcache(struct slabinfo *s) @@ -479,13 +565,27 @@ void slabcache(struct slabinfo *s) *p++ = 'T'; *p = 0; - 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); + 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); } /* @@ -892,6 +992,8 @@ 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); @@ -1074,6 +1176,23 @@ 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++; @@ -1124,7 +1243,9 @@ 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' }, @@ -1149,7 +1270,7 @@ int main(int argc, char *argv[]) page_size = getpagesize(); - while ((c = getopt_long(argc, argv, "ad::efhil1noprstvzTS", + while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTS", opts, NULL)) != -1) switch (c) { case '1': @@ -1158,11 +1279,17 @@ 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/MAINTAINERS b/MAINTAINERS index aefd23f892ba..2cdb591ac080 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2150,6 +2150,14 @@ 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/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 3ee918695215..f85b928ffac4 100644 --- a/arch/m68k/kernel/process.c +++ b/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 = (struct user_regs_struct *)((int)&dump->regs - (int)dump); + dump->u_ar0 = offsetof(struct user, regs); sw = ((struct switch_stack *)regs) - 1; dump->regs.d1 = regs->d1; dump->regs.d2 = regs->d2; diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index e6e49289f788..4b749c416464 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/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, (KTIME_MONOTONIC_RES).tv64); + DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC); #ifdef CONFIG_BUG DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry)); diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index c95482b6b6dd..9d0acedf5f3f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -52,6 +52,10 @@ 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/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig index f25facd97bb4..00b8a84b0319 100644 --- a/drivers/char/pcmcia/Kconfig +++ b/drivers/char/pcmcia/Kconfig @@ -43,5 +43,14 @@ config CARDMAN_4040 (http://www.omnikey.com/), or a current development version of OpenCT (http://www.opensc.org/). +config IPWIRELESS + tristate "IPWireless 3G UMTS PCMCIA card support" + depends on PCMCIA + select PPP + help + This is a driver for 3G UMTS PCMCIA card from IPWireless company. In + some countries (for example Czech Republic, T-Mobile ISP) this card + is shipped for service called UMTS 4G. + endmenu diff --git a/drivers/char/pcmcia/Makefile b/drivers/char/pcmcia/Makefile index 0aae20985d57..be8f287aa398 100644 --- a/drivers/char/pcmcia/Makefile +++ b/drivers/char/pcmcia/Makefile @@ -4,6 +4,8 @@ # Makefile for the Linux PCMCIA char device drivers. # +obj-y += ipwireless/ + obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o obj-$(CONFIG_CARDMAN_4000) += cm4000_cs.o obj-$(CONFIG_CARDMAN_4040) += cm4040_cs.o diff --git a/drivers/char/pcmcia/ipwireless/Makefile b/drivers/char/pcmcia/ipwireless/Makefile new file mode 100644 index 000000000000..b71eb593643d --- /dev/null +++ b/drivers/char/pcmcia/ipwireless/Makefile @@ -0,0 +1,10 @@ +# +# drivers/char/pcmcia/ipwireless/Makefile +# +# Makefile for the IPWireless driver +# + +obj-$(CONFIG_IPWIRELESS) += ipwireless.o + +ipwireless-objs := hardware.o main.o network.o tty.o + diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c new file mode 100644 index 000000000000..1f978ff87fa8 --- /dev/null +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -0,0 +1,1787 @@ +/* + * IPWireless 3G PCMCIA Network Driver + * + * Original code + * by Stephen Blackheath <stephen@blacksapphire.com>, + * Ben Martel <benm@symmetric.co.nz> + * + * Copyrighted as follows: + * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) + * + * Various driver changes and rewrites, port to new kernels + * Copyright (C) 2006-2007 Jiri Kosina + * + * Misc code cleanups and updates + * Copyright (C) 2007 David Sterba + */ + +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/slab.h> + +#include "hardware.h" +#include "setup_protocol.h" +#include "network.h" +#include "main.h" + +static void ipw_send_setup_packet(struct ipw_hardware *hw); +static void handle_received_SETUP_packet(struct ipw_hardware *ipw, + unsigned int address, + unsigned char *data, int len, + int is_last); +static void ipwireless_setup_timer(unsigned long data); +static void handle_received_CTRL_packet(struct ipw_hardware *hw, + unsigned int channel_idx, unsigned char *data, int len); + +/*#define TIMING_DIAGNOSTICS*/ + +#ifdef TIMING_DIAGNOSTICS + +static struct timing_stats { + unsigned long last_report_time; + unsigned long read_time; + unsigned long write_time; + unsigned long read_bytes; + unsigned long write_bytes; + unsigned long start_time; +}; + +static void start_timing(void) +{ + timing_stats.start_time = jiffies; +} + +static void end_read_timing(unsigned length) +{ + timing_stats.read_time += (jiffies - start_time); + timing_stats.read_bytes += length + 2; + report_timing(); +} + +static void end_write_timing(unsigned length) +{ + timing_stats.write_time += (jiffies - start_time); + timing_stats.write_bytes += length + 2; + report_timing(); +} + +static void report_timing(void) +{ + unsigned long since = jiffies - timing_stats.last_report_time; + + /* If it's been more than one second... */ + if (since >= HZ) { + int first = (timing_stats.last_report_time == 0); + + timing_stats.last_report_time = jiffies; + if (!first) + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": %u us elapsed - read %lu bytes in %u us, " + "wrote %lu bytes in %u us\n", + jiffies_to_usecs(since), + timing_stats.read_bytes, + jiffies_to_usecs(timing_stats.read_time), + timing_stats.write_bytes, + jiffies_to_usecs(timing_stats.write_time)); + + timing_stats.read_time = 0; + timing_stats.write_time = 0; + timing_stats.read_bytes = 0; + timing_stats.write_bytes = 0; + } +} +#else +static void start_timing(void) { } +static void end_read_timing(unsigned length) { } +static void end_write_timing(unsigned length) { } +#endif + +/* Imported IPW definitions */ + +#define LL_MTU_V1 318 +#define LL_MTU_V2 250 +#define LL_MTU_MAX (LL_MTU_V1 > LL_MTU_V2 ? LL_MTU_V1 : LL_MTU_V2) + +#define PRIO_DATA 2 +#define PRIO_CTRL 1 +#define PRIO_SETUP 0 + +/* Addresses */ +#define ADDR_SETUP_PROT 0 + +/* Protocol ids */ +enum { + /* Identifier for the Com Data protocol */ + TL_PROTOCOLID_COM_DATA = 0, + + /* Identifier for the Com Control protocol */ + TL_PROTOCOLID_COM_CTRL = 1, + + /* Identifier for the Setup protocol */ + TL_PROTOCOLID_SETUP = 2 +}; + +/* Number of bytes in NL packet header (cannot do + * sizeof(nl_packet_header) since it's a bitfield) */ +#define NL_FIRST_PACKET_HEADER_SIZE 3 + +/* Number of bytes in NL packet header (cannot do + * sizeof(nl_packet_header) since it's a bitfield) */ +#define NL_FOLLOWING_PACKET_HEADER_SIZE 1 + +struct nl_first_packet_header { +#if defined(__BIG_ENDIAN_BITFIELD) + unsigned char packet_rank:2; + unsigned char address:3; + unsigned char protocol:3; +#else + unsigned char protocol:3; + unsigned char address:3; + unsigned char packet_rank:2; +#endif + unsigned char length_lsb; + unsigned char length_msb; +}; + +struct nl_packet_header { +#if defined(__BIG_ENDIAN_BITFIELD) + unsigned char packet_rank:2; + unsigned char address:3; + unsigned char protocol:3; +#else + unsigned char protocol:3; + unsigned char address:3; + unsigned char packet_rank:2; +#endif +}; + +/* Value of 'packet_rank' above */ +#define NL_INTERMEDIATE_PACKET 0x0 +#define NL_LAST_PACKET 0x1 +#define NL_FIRST_PACKET 0x2 + +union nl_packet { + /* Network packet header of the first packet (a special case) */ + struct nl_first_packet_header hdr_first; + /* Network packet header of the following packets (if any) */ + struct nl_packet_header hdr; + /* Complete network packet (header + data) */ + unsigned char rawpkt[LL_MTU_MAX]; +} __attribute__ ((__packed__)); + +#define HW_VERSION_UNKNOWN -1 +#define HW_VERSION_1 1 +#define HW_VERSION_2 2 + +/* IPW I/O ports */ +#define IOIER 0x00 /* Interrupt Enable Register */ +#define IOIR 0x02 /* Interrupt Source/ACK register */ +#define IODCR 0x04 /* Data Control Register */ +#define IODRR 0x06 /* Data Read Register */ +#define IODWR 0x08 /* Data Write Register */ +#define IOESR 0x0A /* Embedded Driver Status Register */ +#define IORXR 0x0C /* Rx Fifo Register (Host to Embedded) */ +#define IOTXR 0x0E /* Tx Fifo Register (Embedded to Host) */ + +/* I/O ports and bit definitions for version 1 of the hardware */ + +/* IER bits*/ +#define IER_RXENABLED 0x1 +#define IER_TXENABLED 0x2 + +/* ISR bits */ +#define IR_RXINTR 0x1 +#define IR_TXINTR 0x2 + +/* DCR bits */ +#define DCR_RXDONE 0x1 +#define DCR_TXDONE 0x2 +#define DCR_RXRESET 0x4 +#define DCR_TXRESET 0x8 + +/* I/O ports and bit definitions for version 2 of the hardware */ + +struct MEMCCR { + unsigned short reg_config_option; /* PCCOR: Configuration Option Register */ + unsigned short reg_config_and_status; /* PCCSR: Configuration and Status Register */ + unsigned short reg_pin_replacement; /* PCPRR: Pin Replacemant Register */ + unsigned short reg_socket_and_copy; /* PCSCR: Socket and Copy Register */ + unsigned short reg_ext_status; /* PCESR: Extendend Status Register */ + unsigned short reg_io_base; /* PCIOB: I/O Base Register */ +}; + +struct MEMINFREG { + unsigned short memreg_tx_old; /* TX Register (R/W) */ + unsigned short pad1; + unsigned short memreg_rx_done; /* RXDone Register (R/W) */ + unsigned short pad2; + unsigned short memreg_rx; /* RX Register (R/W) */ + unsigned short pad3; + unsigned short memreg_pc_interrupt_ack; /* PC intr Ack Register (W) */ + unsigned short pad4; + unsigned long memreg_card_present;/* Mask for Host to check (R) for + * CARD_PRESENT_VALUE */ + unsigned short memreg_tx_new; /* TX2 (new) Register (R/W) */ +}; + +#define IODMADPR 0x00 /* DMA Data Port Register (R/W) */ + +#define CARD_PRESENT_VALUE (0xBEEFCAFEUL) + +#define MEMTX_TX 0x0001 +#define MEMRX_RX 0x0001 +#define MEMRX_RX_DONE 0x0001 +#define MEMRX_PCINTACKK 0x0001 +#define MEMRX_MEMSPURIOUSINT 0x0001 + +#define NL_NUM_OF_PRIORITIES 3 +#define NL_NUM_OF_PROTOCOLS 3 +#define NL_NUM_OF_ADDRESSES NO_OF_IPW_CHANNELS + +struct ipw_hardware { + unsigned int base_port; + short hw_version; + unsigned short ll_mtu; + spinlock_t spinlock; + + int initializing; + int init_loops; + struct timer_list setup_timer; + + int tx_ready; + struct list_head tx_queue[NL_NUM_OF_PRIORITIES]; + /* True if any packets are queued for transmission */ + int tx_queued; + + int rx_bytes_queued; + struct list_head rx_queue; + /* Pool of rx_packet structures that are not currently used. */ + struct list_head rx_pool; + int rx_pool_size; + /* True if reception of data is blocked while userspace processes it. */ + int blocking_rx; + /* True if there is RX data ready on the hardware. */ + int rx_ready; + unsigned short last_memtx_serial; + /* + * Newer versions of the V2 card firmware send serial numbers in the + * MemTX register. 'serial_number_detected' is set true when we detect + * a non-zero serial number (indicating the new firmware). Thereafter, + * the driver can safely ignore the Timer Recovery re-sends to avoid + * out-of-sync problems. + */ + int serial_number_detected; + struct work_struct work_rx; + + /* True if we are to send the set-up data to the hardware. */ + int to_setup; + + /* Card has been removed */ + int removed; + /* Saved irq value when we disable the interrupt. */ + int irq; + /* True if this driver is shutting down. */ + int shutting_down; + /* Modem control lines */ + unsigned int control_lines[NL_NUM_OF_ADDRESSES]; + struct ipw_rx_packet *packet_assembler[NL_NUM_OF_ADDRESSES]; + + struct tasklet_struct tasklet; + + /* The handle for the network layer, for the sending of events to it. */ + struct ipw_network *network; + struct MEMINFREG __iomem *memory_info_regs; + struct MEMCCR __iomem *memregs_CCR; + void (*reboot_callback) (void *data); + void *reboot_callback_data; + + unsigned short __iomem *memreg_tx; +}; + +/* + * Packet info structure for tx packets. + * Note: not all the fields defined here are required for all protocols + */ +struct ipw_tx_packet { + struct list_head queue; + /* channel idx + 1 */ + unsigned char dest_addr; + /* SETUP, CTRL or DATA */ + unsigned char protocol; + /* Length of data block, which starts at the end of this structure */ + unsigned short length; + /* Sending state */ + /* Offset of where we've sent up to so far */ + unsigned long offset; + /* Count of packet fragments, starting at 0 */ + int fragment_count; + + /* Called after packet is sent and before is freed */ + void (*packet_callback) (void *cb_data, unsigned int packet_length); + void *callback_data; +}; + +/* Signals from DTE */ +#define COMCTRL_RTS 0 +#define COMCTRL_DTR 1 + +/* Signals from DCE */ +#define COMCTRL_CTS 2 +#define COMCTRL_DCD 3 +#define COMCTRL_DSR 4 +#define COMCTRL_RI 5 + +struct ipw_control_packet_body { + /* DTE signal or DCE signal */ + unsigned char sig_no; + /* 0: set signal, 1: clear signal */ + unsigned char value; +} __attribute__ ((__packed__)); + +struct ipw_control_packet { + struct ipw_tx_packet header; + struct ipw_control_packet_body body; +}; + +struct ipw_rx_packet { + struct list_head queue; + unsigned int capacity; + unsigned int length; + unsigned int protocol; + unsigned int channel_idx; +}; + +#ifdef IPWIRELESS_STATE_DEBUG +int ipwireless_dump_hardware_state(char *p, size_t limit, + struct ipw_hardware *hw) +{ + return snprintf(p, limit, + "debug: initializing=%d\n" + "debug: tx_ready=%d\n" + "debug: tx_queued=%d\n" + "debug: rx_ready=%d\n" + "debug: rx_bytes_queued=%d\n" + "debug: blocking_rx=%d\n" + "debug: removed=%d\n" + "debug: hardware.shutting_down=%d\n" + "debug: to_setup=%d\n", + hw->initializing, + hw->tx_ready, + hw->tx_queued, + hw->rx_ready, + hw->rx_bytes_queued, + hw->blocking_rx, + hw->removed, + hw->shutting_down, + hw->to_setup); +} +#endif + +static char *data_type(const unsigned char *buf, unsigned length) +{ + struct nl_packet_header *hdr = (struct nl_packet_header *) buf; + + if (length == 0) + return " "; + + if (hdr->packet_rank & NL_FIRST_PACKET) { + switch (hdr->protocol) { + case TL_PROTOCOLID_COM_DATA: return "DATA "; + case TL_PROTOCOLID_COM_CTRL: return "CTRL "; + case TL_PROTOCOLID_SETUP: return "SETUP"; + default: return "???? "; + } + } else + return " "; +} + +#define DUMP_MAX_BYTES 64 + +static void dump_data_bytes(const char *type, const unsigned char *data, + unsigned length) +{ + char prefix[56]; + + sprintf(prefix, IPWIRELESS_PCCARD_NAME ": %s %s ", + type, data_type(data, length)); + print_hex_dump_bytes(prefix, 0, (void *)data, + length < DUMP_MAX_BYTES ? length : DUMP_MAX_BYTES); +} + +static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data, + unsigned length) +{ + int i; + unsigned long flags; + + start_timing(); + + if (length == 0) + return 0; + + if (length > hw->ll_mtu) + return -1; + + if (ipwireless_debug) + dump_data_bytes("send", data, length); + + spin_lock_irqsave(&hw->spinlock, flags); + + if (hw->hw_version == HW_VERSION_1) { + outw((unsigned short) length, hw->base_port + IODWR); + + for (i = 0; i < length; i += 2) { + unsigned short d = data[i]; + __le16 raw_data; + + if (likely(i + 1 < length)) + d |= data[i + 1] << 8; + raw_data = cpu_to_le16(d); + outw(raw_data, hw->base_port + IODWR); + } + + outw(DCR_TXDONE, hw->base_port + IODCR); + } else if (hw->hw_version == HW_VERSION_2) { + outw((unsigned short) length, hw->base_port + IODMADPR); + + for (i = 0; i < length; i += 2) { + unsigned short d = data[i]; + __le16 raw_data; + + if ((i + 1 < length)) + d |= data[i + 1] << 8; + raw_data = cpu_to_le16(d); + outw(raw_data, hw->base_port + IODMADPR); + } + while ((i & 3) != 2) { + outw((unsigned short) 0xDEAD, hw->base_port + IODMADPR); + i += 2; + } + writew(MEMRX_RX, &hw->memory_info_regs->memreg_rx); + } + + spin_unlock_irqrestore(&hw->spinlock, flags); + + end_write_timing(length); + + return 0; +} + +static int do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet) +{ + unsigned short fragment_data_len; + unsigned short data_left = packet->length - packet->offset; + unsigned short header_size; + union nl_packet pkt; + + header_size = + (packet->fragment_count == 0) + ? NL_FIRST_PACKET_HEADER_SIZE + : NL_FOLLOWING_PACKET_HEADER_SIZE; + fragment_data_len = hw->ll_mtu - header_size; + if (data_left < fragment_data_len) + fragment_data_len = data_left; + + pkt.hdr_first.protocol = packet->protocol; + pkt.hdr_first.address = packet->dest_addr; + pkt.hdr_first.packet_rank = 0; + + /* First packet? */ + if (packet->fragment_count == 0) { + pkt.hdr_first.packet_rank |= NL_FIRST_PACKET; + pkt.hdr_first.length_lsb = (unsigned char) packet->length; + pkt.hdr_first.length_msb = + (unsigned char) (packet->length >> 8); + } + + memcpy(pkt.rawpkt + header_size, + ((unsigned char *) packet) + sizeof(struct ipw_tx_packet) + + packet->offset, fragment_data_len); + packet->offset += fragment_data_len; + packet->fragment_count++; + + /* Last packet? (May also be first packet.) */ + if (packet->offset == packet->length) + pkt.hdr_first.packet_rank |= NL_LAST_PACKET; + do_send_fragment(hw, pkt.rawpkt, header_size + fragment_data_len); + + /* If this packet has unsent data, then re-queue it. */ + if (packet->offset < packet->length) { + /* + * Re-queue it at the head of the highest priority queue so + * it goes before all other packets + */ + unsigned long flags; + + spin_lock_irqsave(&hw->spinlock, flags); + list_add(&packet->queue, &hw->tx_queue[0]); + spin_unlock_irqrestore(&hw->spinlock, flags); + } else { + if (packet->packet_callback) + packet->packet_callback(packet->callback_data, + packet->length); + kfree(packet); + } + + return 0; +} + +static void ipw_setup_hardware(struct ipw_hardware *hw) +{ + unsigned long flags; + + spin_lock_irqsave(&hw->spinlock, flags); + if (hw->hw_version == HW_VERSION_1) { + /* Reset RX FIFO */ + outw(DCR_RXRESET, hw->base_port + IODCR); + /* SB: Reset TX FIFO */ + outw(DCR_TXRESET, hw->base_port + IODCR); + + /* Enable TX and RX interrupts. */ + outw(IER_TXENABLED | IER_RXENABLED, hw->base_port + IOIER); + } else { + /* + * Set INTRACK bit (bit 0), which means we must explicitly + * acknowledge interrupts by clearing bit 2 of reg_config_and_status. + */ + unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status); + + csr |= 1; + writew(csr, &hw->memregs_CCR->reg_config_and_status); + } + spin_unlock_irqrestore(&hw->spinlock, flags); +} + +/* + * If 'packet' is NULL, then this function allocates a new packet, setting its + * length to 0 and ensuring it has the specified minimum amount of free space. + * + * If 'packet' is not NULL, then this function enlarges it if it doesn't + * have the specified minimum amount of free space. + * + */ +static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw, + struct ipw_rx_packet *packet, + int minimum_free_space) +{ + + if (!packet) { + unsigned long flags; + + /* + * If this is the first fragment, then we will need to fetch a + * packet to put it in. + */ + spin_lock_irqsave(&hw->spinlock, flags); + /* If we have one in our pool, then pull it out. */ + if (!list_empty(&hw->rx_pool)) { + packet = list_first_entry(&hw->rx_pool, + struct ipw_rx_packet, queue); + list_del(&packet->queue); + hw->rx_pool_size--; + spin_unlock_irqrestore(&hw->spinlock, flags); + } else { + /* Otherwise allocate a new one. */ + static int min_capacity = 256; + int new_capacity; + + spin_unlock_irqrestore(&hw->spinlock, flags); + new_capacity = + minimum_free_space > min_capacity + ? minimum_free_space + : min_capacity; + packet = kmalloc(sizeof(struct ipw_rx_packet) + + new_capacity, GFP_ATOMIC); + if (!packet) + return NULL; + packet->capacity = new_capacity; + } + packet->length = 0; + } + + /* + * If this packet does not have sufficient capacity for the data we + * want to add, then make it bigger. + */ + if (packet->length + minimum_free_space > packet->capacity) { + struct ipw_rx_packet *old_packet = packet; + + packet = kmalloc(sizeof(struct ipw_rx_packet) + + old_packet->length + minimum_free_space, + GFP_ATOMIC); + if (!packet) + return NULL; + memcpy(packet, old_packet, + sizeof(struct ipw_rx_packet) + + old_packet->length); + packet->capacity = old_packet->length + minimum_free_space; + kfree(old_packet); + } + + return packet; +} + +static void pool_free(struct ipw_hardware *hw, struct ipw_rx_packet *packet) +{ + if (hw->rx_pool_size > 6) + kfree(packet); + else { + hw->rx_pool_size++; + list_add_tail(&packet->queue, &hw->rx_pool); + } +} + +static void queue_received_packet(struct ipw_hardware *hw, + unsigned int protocol, unsigned int address, + unsigned char *data, int length, int is_last) +{ + unsigned int channel_idx = address - 1; + struct ipw_rx_packet *packet = NULL; + unsigned long flags; + + /* Discard packet if channel index is out of range. */ + if (channel_idx >= NL_NUM_OF_ADDRESSES) { + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": data packet has bad address %u\n", address); + return; + } + + /* + * ->packet_assembler is safe to touch unlocked, this is the only place + */ + if (protocol == TL_PROTOCOLID_COM_DATA) { + struct ipw_rx_packet **assem = + &hw->packet_assembler[channel_idx]; + + /* + * Create a new packet, or assembler already contains one + * enlarge it by 'length' bytes. + */ + (*assem) = pool_allocate(hw, *assem, length); + if (!(*assem)) { + printk(KERN_ERR IPWIRELESS_PCCARD_NAME + ": no memory for incomming data packet, dropped!\n"); + return; + } + (*assem)->protocol = protocol; + (*assem)->channel_idx = channel_idx; + + /* Append this packet data onto existing data. */ + memcpy((unsigned char *)(*assem) + + sizeof(struct ipw_rx_packet) + + (*assem)->length, data, length); + (*assem)->length += length; + if (is_last) { + packet = *assem; + *assem = NULL; + /* Count queued DATA bytes only */ + spin_lock_irqsave(&hw->spinlock, flags); + hw->rx_bytes_queued += packet->length; + spin_unlock_irqrestore(&hw->spinlock, flags); + } + } else { + /* If it's a CTRL packet, don't assemble, just queue it. */ + packet = pool_allocate(hw, NULL, length); + if (!packet) { + printk(KERN_ERR IPWIRELESS_PCCARD_NAME + ": no memory for incomming ctrl packet, dropped!\n"); + return; + } + packet->protocol = protocol; + packet->channel_idx = channel_idx; + memcpy((unsigned char *)packet + sizeof(struct ipw_rx_packet), + data, length); + packet->length = length; + } + + /* + * If this is the last packet, then send the assembled packet on to the + * network layer. + */ + if (packet) { + spin_lock_irqsave(&hw->spinlock, flags); + list_add_tail(&packet->queue, &hw->rx_queue); + /* Block reception of incoming packets if queue is full. */ + hw->blocking_rx = + hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE; + + spin_unlock_irqrestore(&hw->spinlock, flags); + schedule_work(&hw->work_rx); + } +} + +/* + * Workqueue callback + */ +static void ipw_receive_data_work(struct work_struct *work_rx) +{ + struct ipw_hardware *hw = + container_of(work_rx, struct ipw_hardware, work_rx); + unsigned long flags; + + spin_lock_irqsave(&hw->spinlock, flags); + while (!list_empty(&hw->rx_queue)) { + struct ipw_rx_packet *packet = + list_first_entry(&hw->rx_queue, + struct ipw_rx_packet, queue); + + if (hw->shutting_down) + break; + list_del(&packet->queue); + + /* + * Note: ipwireless_network_packet_received must be called in a + * process context (i.e. via schedule_work) because the tty + * output code can sleep in the tty_flip_buffer_push call. + */ + if (packet->protocol == TL_PROTOCOLID_COM_DATA) { + if (hw->network != NULL) { + /* If the network hasn't been disconnected. */ + spin_unlock_irqrestore(&hw->spinlock, flags); + /* + * This must run unlocked due to tty processing + * and mutex locking + */ + ipwireless_network_packet_received( + hw->network, + packet->channel_idx, + (unsigned char *)packet + + sizeof(struct ipw_rx_packet), + packet->length); + spin_lock_irqsave(&hw->spinlock, flags); + } + /* Count queued DATA bytes only */ + hw->rx_bytes_queued -= packet->length; + } else { + /* + * This is safe to be called locked, callchain does + * not block + */ + handle_received_CTRL_packet(hw, packet->channel_idx, + (unsigned char *)packet + + sizeof(struct ipw_rx_packet), + packet->length); + } + pool_free(hw, packet); + /* + * Unblock reception of incoming packets if queue is no longer + * full. + */ + hw->blocking_rx = + hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE; + if (hw->shutting_down) + break; + } + spin_unlock_irqrestore(&hw->spinlock, flags); +} + +static void handle_received_CTRL_packet(struct ipw_hardware *hw, + unsigned int channel_idx, + unsigned char *data, int len) +{ + struct ipw_control_packet_body *body = + (struct ipw_control_packet_body *) data; + unsigned int changed_mask; + + if (len != sizeof(struct ipw_control_packet_body)) { + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": control packet was %d bytes - wrong size!\n", + len); + return; + } + + switch (body->sig_no) { + case COMCTRL_CTS: + changed_mask = IPW_CONTROL_LINE_CTS; + break; + case COMCTRL_DCD: + changed_mask = IPW_CONTROL_LINE_DCD; + break; + case COMCTRL_DSR: + changed_mask = IPW_CONTROL_LINE_DSR; + break; + case COMCTRL_RI: + changed_mask = IPW_CONTROL_LINE_RI; + break; + default: + changed_mask = 0; + } + + if (changed_mask != 0) { + if (body->value) + hw->control_lines[channel_idx] |= changed_mask; + else + hw->control_lines[channel_idx] &= ~changed_mask; + if (hw->network) + ipwireless_network_notify_control_line_change( + hw->network, + channel_idx, + hw->control_lines[channel_idx], + changed_mask); + } +} + +static void handle_received_packet(struct ipw_hardware *hw, + union nl_packet *packet, + unsigned short len) +{ + unsigned int protocol = packet->hdr.protocol; + unsigned int address = packet->hdr.address; + unsigned int header_length; + unsigned char *data; + unsigned int data_len; + int is_last = packet->hdr.packet_rank & NL_LAST_PACKET; + + if (packet->hdr.packet_rank & NL_FIRST_PACKET) + header_length = NL_FIRST_PACKET_HEADER_SIZE; + else + header_length = NL_FOLLOWING_PACKET_HEADER_SIZE; + + data = packet->rawpkt + header_length; + data_len = len - header_length; + switch (protocol) { + case TL_PROTOCOLID_COM_DATA: + case TL_PROTOCOLID_COM_CTRL: + queue_received_packet(hw, protocol, address, data, data_len, + is_last); + break; + case TL_PROTOCOLID_SETUP: + handle_received_SETUP_packet(hw, address, data, data_len, + is_last); + break; + } +} + +static void acknowledge_data_read(struct ipw_hardware *hw) +{ + if (hw->hw_version == HW_VERSION_1) + outw(DCR_RXDONE, hw->base_port + IODCR); + else + writew(MEMRX_PCINTACKK, + &hw->memory_info_regs->memreg_pc_interrupt_ack); +} + +/* + * Retrieve a packet from the IPW hardware. + */ +static void do_receive_packet(struct ipw_hardware *hw) +{ + unsigned len; + unsigned int i; + unsigned char pkt[LL_MTU_MAX]; + + start_timing(); + + if (hw->hw_version == HW_VERSION_1) { + len = inw(hw->base_port + IODRR); + if (len > hw->ll_mtu) { + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": received a packet of %u bytes - " + "longer than the MTU!\n", len); + outw(DCR_RXDONE | DCR_RXRESET, hw->base_port + IODCR); + return; + } + + for (i = 0; i < len; i += 2) { + __le16 raw_data = inw(hw->base_port + IODRR); + unsigned short data = le16_to_cpu(raw_data); + + pkt[i] = (unsigned char) data; + pkt[i + 1] = (unsigned char) (data >> 8); + } + } else { + len = inw(hw->base_port + IODMADPR); + if (len > hw->ll_mtu) { + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": received a packet of %u bytes - " + "longer than the MTU!\n", len); + writew(MEMRX_PCINTACKK, + &hw->memory_info_regs->memreg_pc_interrupt_ack); + return; + } + + for (i = 0; i < len; i += 2) { + __le16 raw_data = inw(hw->base_port + IODMADPR); + unsigned short data = le16_to_cpu(raw_data); + + pkt[i] = (unsigned char) data; + pkt[i + 1] = (unsigned char) (data >> 8); + } + + while ((i & 3) != 2) { + inw(hw->base_port + IODMADPR); + i += 2; + } + } + + acknowledge_data_read(hw); + + if (ipwireless_debug) + dump_data_bytes("recv", pkt, len); + + handle_received_packet(hw, (union nl_packet *) pkt, len); + + end_read_timing(len); +} + +static int get_current_packet_priority(struct ipw_hardware *hw) +{ + /* + * If we're initializing, don't send anything of higher priority than + * PRIO_SETUP. The network layer therefore need not care about + * hardware initialization - any of its stuff will simply be queued + * until setup is complete. + */ + return (hw->to_setup || hw->initializing + ? PRIO_SETUP + 1 : + NL_NUM_OF_PRIORITIES); +} + +/* + * return 1 if something has been received from hw + */ +static int get_packets_from_hw(struct ipw_hardware *hw) +{ + int received = 0; + unsigned long flags; + + spin_lock_irqsave(&hw->spinlock, flags); + while (hw->rx_ready && !hw->blocking_rx) { + received = 1; + hw->rx_ready--; + spin_unlock_irqrestore(&hw->spinlock, flags); + + do_receive_packet(hw); + + spin_lock_irqsave(&hw->spinlock, flags); + } + spin_unlock_irqrestore(&hw->spinlock, flags); + + return received; +} + +/* + * Send pending packet up to given priority, prioritize SETUP data until + * hardware is fully setup. + * + * return 1 if more packets can be sent + */ +static int send_pending_packet(struct ipw_hardware *hw, int priority_limit) +{ + int more_to_send = 0; + unsigned long flags; + + spin_lock_irqsave(&hw->spinlock, flags); + if (hw->tx_queued && hw->tx_ready != 0) { + int priority; + struct ipw_tx_packet *packet = NULL; + + hw->tx_ready--; + + /* Pick a packet */ + for (priority = 0; priority < priority_limit; priority++) { + if (!list_empty(&hw->tx_queue[priority])) { + packet = list_first_entry( + &hw->tx_queue[priority], + struct ipw_tx_packet, + queue); + + list_del(&packet->queue); + + break; + } + } + if (!packet) { + hw->tx_queued = 0; + spin_unlock_irqrestore(&hw->spinlock, flags); + return 0; + } + spin_unlock_irqrestore(&hw->spinlock, flags); + + /* Send */ + do_send_packet(hw, packet); + + /* Check if more to send */ + spin_lock_irqsave(&hw->spinlock, flags); + for (priority = 0; priority < priority_limit; priority++) + if (!list_empty(&hw->tx_queue[priority])) { + more_to_send = 1; + break; + } + + if (!more_to_send) + hw->tx_queued = 0; + } + spin_unlock_irqrestore(&hw->spinlock, flags); + + return more_to_send; +} + +/* + * Send and receive all queued packets. + */ +static void ipwireless_do_tasklet(unsigned long hw_) +{ + struct ipw_hardware *hw = (struct ipw_hardware *) hw_; + unsigned long flags; + + spin_lock_irqsave(&hw->spinlock, flags); + if (hw->shutting_down) { + spin_unlock_irqrestore(&hw->spinlock, flags); + return; + } + + if (hw->to_setup == 1) { + /* + * Initial setup data sent to hardware + */ + hw->to_setup = 2; + spin_unlock_irqrestore(&hw->spinlock, flags); + + ipw_setup_hardware(hw); + ipw_send_setup_packet(hw); + + send_pending_packet(hw, PRIO_SETUP + 1); + get_packets_from_hw(hw); + } else { + int priority_limit = get_current_packet_priority(hw); + int again; + + spin_unlock_irqrestore(&hw->spinlock, flags); + + do { + again = send_pending_packet(hw, priority_limit); + again |= get_packets_from_hw(hw); + } while (again); + } +} + +/* + * return true if the card is physically present. + */ +static int is_card_present(struct ipw_hardware *hw) +{ + if (hw->hw_version == HW_VERSION_1) + return inw(hw->base_port + IOIR) != 0xFFFF; + else + return readl(&hw->memory_info_regs->memreg_card_present) == + CARD_PRESENT_VALUE; +} + +static irqreturn_t ipwireless_handle_v1_interrupt(int irq, + struct ipw_hardware *hw) +{ + unsigned short irqn; + + irqn = inw(hw->base_port + IOIR); + + /* Check if card is present */ + if (irqn == 0xFFFF) + return IRQ_NONE; + else if (irqn != 0) { + unsigned short ack = 0; + unsigned long flags; + + /* Transmit complete. */ + if (irqn & IR_TXINTR) { + ack |= IR_TXINTR; + spin_lock_irqsave(&hw->spinlock, flags); + hw->tx_ready++; + spin_unlock_irqrestore(&hw->spinlock, flags); + } + /* Received data */ + if (irqn & IR_RXINTR) { + ack |= IR_RXINTR; + spin_lock_irqsave(&hw->spinlock, flags); + hw->rx_ready++; + spin_unlock_irqrestore(&hw->spinlock, flags); + } + if (ack != 0) { + outw(ack, hw->base_port + IOIR); + tasklet_schedule(&hw->tasklet); + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static void acknowledge_pcmcia_interrupt(struct ipw_hardware *hw) +{ + unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status); + + csr &= 0xfffd; + writew(csr, &hw->memregs_CCR->reg_config_and_status); +} + +static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq, + struct ipw_hardware *hw) +{ + int tx = 0; + int rx = 0; + int rx_repeat = 0; + int try_mem_tx_old; + unsigned long flags; + + do { + + unsigned short memtx = readw(hw->memreg_tx); + unsigned short memtx_serial; + unsigned short memrxdone = + readw(&hw->memory_info_regs->memreg_rx_done); + + try_mem_tx_old = 0; + + /* check whether the interrupt was generated by ipwireless card */ + if (!(memtx & MEMTX_TX) && !(memrxdone & MEMRX_RX_DONE)) { + + /* check if the card uses memreg_tx_old register */ + if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { + memtx = readw(&hw->memory_info_regs->memreg_tx_old); + if (memtx & MEMTX_TX) { + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": Using memreg_tx_old\n"); + hw->memreg_tx = + &hw->memory_info_regs->memreg_tx_old; + } else { + return IRQ_NONE; + } + } else { + return IRQ_NONE; + } + } + + /* + * See if the card is physically present. Note that while it is + * powering up, it appears not to be present. + */ + if (!is_card_present(hw)) { + acknowledge_pcmcia_interrupt(hw); + return IRQ_HANDLED; + } + + memtx_serial = memtx & (unsigned short) 0xff00; + if (memtx & MEMTX_TX) { + writew(memtx_serial, hw->memreg_tx); + + if (hw->serial_number_detected) { + if (memtx_serial != hw->last_memtx_serial) { + hw->last_memtx_serial = memtx_serial; + spin_lock_irqsave(&hw->spinlock, flags); + hw->rx_ready++; + spin_unlock_irqrestore(&hw->spinlock, flags); + rx = 1; + } else + /* Ignore 'Timer Recovery' duplicates. */ + rx_repeat = 1; + } else { + /* + * If a non-zero serial number is seen, then enable + * serial number checking. + */ + if (memtx_serial != 0) { + hw->serial_number_detected = 1; + printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME + ": memreg_tx serial num detected\n"); + + spin_lock_irqsave(&hw->spinlock, flags); + hw->rx_ready++; + spin_unlock_irqrestore(&hw->spinlock, flags); + } + rx = 1; + } + } + if (memrxdone & MEMRX_RX_DONE) { + writew(0, &hw->memory_info_regs->memreg_rx_done); + spin_lock_irqsave(&hw->spinlock, flags); + hw->tx_ready++; + spin_unlock_irqrestore(&hw->spinlock, flags); + tx = 1; + } + if (tx) + writew(MEMRX_PCINTACKK, + &hw->memory_info_regs->memreg_pc_interrupt_ack); + + acknowledge_pcmcia_interrupt(hw); + + if (tx || rx) + tasklet_schedule(&hw->tasklet); + else if (!rx_repeat) { + if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { + if (hw->serial_number_detected) + printk(KERN_WARNING IPWIRELESS_PCCARD_NAME + ": spurious interrupt - new_tx mode\n"); + else { + printk(KERN_WARNING IPWIRELESS_PCCARD_NAME + ": no valid memreg_tx value - " + "switching to the old memreg_tx\n"); + hw->memreg_tx = + &hw->memory_info_regs->memreg_tx_old; + try_mem_tx_old = 1; + } + } else + printk(KERN_WARNING IPWIRELESS_PCCARD_NAME + ": spurious interrupt - old_tx mode\n"); + } + + } while (try_mem_tx_old == 1); + + return IRQ_HANDLED; +} + +irqreturn_t ipwireless_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct ipw_hardware *hw = dev_id; + + if (hw->hw_version == HW_VERSION_1) + return ipwireless_handle_v1_interrupt(irq, hw); + else + return ipwireless_handle_v2_v3_interrupt(irq, hw); +} + +static void flush_packets_to_hw(struct ipw_hardware *hw) +{ + int priority_limit; + unsigned long flags; + + spin_lock_irqsave(&hw->spinlock, flags); + priority_limit = get_current_packet_priority(hw); + spin_unlock_irqrestore(&hw->spinlock, flags); + + while (send_pending_packet(hw, priority_limit)); +} + +static void send_packet(struct ipw_hardware *hw, int priority, + struct ipw_tx_packet *packet) +{ + unsigned long flags; + + spin_lock_irqsave(&hw->spinlock, flags); + list_add_tail(&packet->queue, &hw->tx_queue[priority]); + hw->tx_queued = 1; + spin_unlock_irqrestore(&hw->spinlock, flags); + + flush_packets_to_hw(hw); +} + +/* Create data packet, non-atomic allocation */ +static void *alloc_data_packet(int data_size, + unsigned char dest_addr, + unsigned char protocol) +{ + struct ipw_tx_packet *packet = kzalloc( + sizeof(struct ipw_tx_packet) + data_size, + GFP_ATOMIC); + + if (!packet) + return NULL; + + INIT_LIST_HEAD(&packet->queue); + packet->dest_addr = dest_addr; + packet->protocol = protocol; + packet->length = data_size; + + return packet; +} + +static void *alloc_ctrl_packet(int header_size, + unsigned char dest_addr, + unsigned char protocol, + unsigned char sig_no) +{ + /* + * sig_no is located right after ipw_tx_packet struct in every + * CTRL or SETUP packets, we can use ipw_control_packet as a + * common struct + */ + struct ipw_control_packet *packet = kzalloc(header_size, GFP_ATOMIC); + + if (!packet) + return NULL; + + INIT_LIST_HEAD(&packet->header.queue); + packet->header.dest_addr = dest_addr; + packet->header.protocol = protocol; + packet->header.length = header_size - sizeof(struct ipw_tx_packet); + packet->body.sig_no = sig_no; + + return packet; +} + +int ipwireless_send_packet(struct ipw_hardware *hw, unsigned int channel_idx, + unsigned char *data, unsigned int length, + void (*callback) (void *cb, unsigned int length), + void *callback_data) +{ + struct ipw_tx_packet *packet; + + packet = alloc_data_packet(length, + (unsigned char) (channel_idx + 1), + TL_PROTOCOLID_COM_DATA); + if (!packet) + return -ENOMEM; + packet->packet_callback = callback; + packet->callback_data = callback_data; + memcpy((unsigned char *) packet + + sizeof(struct ipw_tx_packet), data, length); + + send_packet(hw, PRIO_DATA, packet); + return 0; +} + +static int set_control_line(struct ipw_hardware *hw, int prio, + unsigned int channel_idx, int line, int state) +{ + struct ipw_control_packet *packet; + int protocolid = TL_PROTOCOLID_COM_CTRL; + + if (prio == PRIO_SETUP) + protocolid = TL_PROTOCOLID_SETUP; + + packet = alloc_ctrl_packet(sizeof(struct ipw_control_packet), + (unsigned char) (channel_idx + 1), + protocolid, line); + if (!packet) + return -ENOMEM; + packet->header.length = sizeof(struct ipw_control_packet_body); + packet->body.value = (unsigned char) (state == 0 ? 0 : 1); + send_packet(hw, prio, &packet->header); + return 0; +} + + +static int set_DTR(struct ipw_hardware *hw, int priority, + unsigned int channel_idx, int state) +{ + if (state != 0) + hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_DTR; + else + hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_DTR; + + return set_control_line(hw, priority, channel_idx, COMCTRL_DTR, state); +} + +static int set_RTS(struct ipw_hardware *hw, int priority, + unsigned int channel_idx, int state) +{ + if (state != 0) + hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_RTS; + else + hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_RTS; + + return set_control_line(hw, priority, channel_idx, COMCTRL_RTS, state); +} + +int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx, + int state) +{ + return set_DTR(hw, PRIO_CTRL, channel_idx, state); +} + +int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx, + int state) +{ + return set_RTS(hw, PRIO_CTRL, channel_idx, state); +} + +struct ipw_setup_get_version_query_packet { + struct ipw_tx_packet header; + struct tl_setup_get_version_qry body; +}; + +struct ipw_setup_config_packet { + struct ipw_tx_packet header; + struct tl_setup_config_msg body; +}; + +struct ipw_setup_config_done_packet { + struct ipw_tx_packet header; + struct tl_setup_config_done_msg body; +}; + +struct ipw_setup_open_packet { + struct ipw_tx_packet header; + struct tl_setup_open_msg body; +}; + +struct ipw_setup_info_packet { + struct ipw_tx_packet header; + struct tl_setup_info_msg body; +}; + +struct ipw_setup_reboot_msg_ack { + struct ipw_tx_packet header; + struct TlSetupRebootMsgAck body; +}; + +/* This handles the actual initialization of the card */ +static void __handle_setup_get_version_rsp(struct ipw_hardware *hw) +{ + struct ipw_setup_config_packet *config_packet; + struct ipw_setup_config_done_packet *config_done_packet; + struct ipw_setup_open_packet *open_packet; + struct ipw_setup_info_packet *info_packet; + int port; + unsigned int channel_idx; + + /* generate config packet */ + for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) { + config_packet = alloc_ctrl_packet( + sizeof(struct ipw_setup_config_packet), + ADDR_SETUP_PROT, + TL_PROTOCOLID_SETUP, + TL_SETUP_SIGNO_CONFIG_MSG); + if (!config_packet) + goto exit_nomem; + config_packet->header.length = sizeof(struct tl_setup_config_msg); + config_packet->body.port_no = port; + config_packet->body.prio_data = PRIO_DATA; + config_packet->body.prio_ctrl = PRIO_CTRL; + send_packet(hw, PRIO_SETUP, &config_packet->header); + } + config_done_packet = alloc_ctrl_packet( + sizeof(struct ipw_setup_config_done_packet), + ADDR_SETUP_PROT, + TL_PROTOCOLID_SETUP, + TL_SETUP_SIGNO_CONFIG_DONE_MSG); + if (!config_done_packet) + goto exit_nomem; + config_done_packet->header.length = sizeof(struct tl_setup_config_done_msg); + send_packet(hw, PRIO_SETUP, &config_done_packet->header); + + /* generate open packet */ + for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) { + open_packet = alloc_ctrl_packet( + sizeof(struct ipw_setup_open_packet), + ADDR_SETUP_PROT, + TL_PROTOCOLID_SETUP, + TL_SETUP_SIGNO_OPEN_MSG); + if (!open_packet) + goto exit_nomem; + open_packet->header.length = sizeof(struct tl_setup_open_msg); + open_packet->body.port_no = port; + send_packet(hw, PRIO_SETUP, &open_packet->header); + } + for (channel_idx = 0; + channel_idx < NL_NUM_OF_ADDRESSES; channel_idx++) { + int ret; + + ret = set_DTR(hw, PRIO_SETUP, channel_idx, + (hw->control_lines[channel_idx] & + IPW_CONTROL_LINE_DTR) != 0); + if (ret) { + printk(KERN_ERR IPWIRELESS_PCCARD_NAME + ": error setting DTR (%d)\n", ret); + return; + } + + set_RTS(hw, PRIO_SETUP, channel_idx, + (hw->control_lines [channel_idx] & + IPW_CONTROL_LINE_RTS) != 0); + if (ret) { + printk(KERN_ERR IPWIRELESS_PCCARD_NAME + ": error setting RTS (%d)\n", ret); + return; + } + } + /* + * For NDIS we assume that we are using sync PPP frames, for COM async. + * This driver uses NDIS mode too. We don't bother with translation + * from async -> sync PPP. + */ + info_packet = alloc_ctrl_packet(sizeof(struct ipw_setup_info_packet), + ADDR_SETUP_PROT, + TL_PROTOCOLID_SETUP, + TL_SETUP_SIGNO_INFO_MSG); + if (!info_packet) + goto exit_nomem; + info_packet->header.length = sizeof(struct tl_setup_info_msg); + info_packet->body.driver_type = NDISWAN_DRIVER; + info_packet->body.major_version = NDISWAN_DRIVER_MAJOR_VERSION; + info_packet->body.minor_version = NDISWAN_DRIVER_MINOR_VERSION; + send_packet(hw, PRIO_SETUP, &info_packet->header); + + /* Initialization is now complete, so we clear the 'to_setup' flag */ + hw->to_setup = 0; + + return; + +exit_nomem: + printk(KERN_ERR IPWIRELESS_PCCARD_NAME + ": not enough memory to alloc control packet\n"); + hw->to_setup = -1; +} + +static void handle_setup_get_version_rsp(struct ipw_hardware *hw, + unsigned char vers_no) +{ + del_timer(&hw->setup_timer); + hw->initializing = 0; + printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": card is ready.\n"); + + if (vers_no == TL_SETUP_VERSION) + __handle_setup_get_version_rsp(hw); + else + printk(KERN_ERR + IPWIRELESS_PCCARD_NAME + ": invalid hardware version no %u\n", + (unsigned int) vers_no); +} + +static void ipw_send_setup_packet(struct ipw_hardware *hw) +{ + struct ipw_setup_get_version_query_packet *ver_packet; + + ver_packet = alloc_ctrl_packet( + sizeof(struct ipw_setup_get_version_query_packet), + ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, + TL_SETUP_SIGNO_GET_VERSION_QRY); + ver_packet->header.length = sizeof(struct tl_setup_get_version_qry); + + /* + * Response is handled in handle_received_SETUP_packet + */ + send_packet(hw, PRIO_SETUP, &ver_packet->header); +} + +static void handle_received_SETUP_packet(struct ipw_hardware *hw, + unsigned int address, + unsigned char *data, int len, + int is_last) +{ + union ipw_setup_rx_msg *rx_msg = (union ipw_setup_rx_msg *) data; + + if (address != ADDR_SETUP_PROT) { + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": setup packet has bad address %d\n", address); + return; + } + + switch (rx_msg->sig_no) { + case TL_SETUP_SIGNO_GET_VERSION_RSP: + if (hw->to_setup) + handle_setup_get_version_rsp(hw, + rx_msg->version_rsp_msg.version); + break; + + case TL_SETUP_SIGNO_OPEN_MSG: + if (ipwireless_debug) { + unsigned int channel_idx = rx_msg->open_msg.port_no - 1; + + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": OPEN_MSG [channel %u] reply received\n", + channel_idx); + } + break; + + case TL_SETUP_SIGNO_INFO_MSG_ACK: + if (ipwireless_debug) + printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME + ": card successfully configured as NDISWAN\n"); + break; + + case TL_SETUP_SIGNO_REBOOT_MSG: + if (hw->to_setup) + printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME + ": Setup not completed - ignoring reboot msg\n"); + else { + struct ipw_setup_reboot_msg_ack *packet; + + printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME + ": Acknowledging REBOOT message\n"); + packet = alloc_ctrl_packet( + sizeof(struct ipw_setup_reboot_msg_ack), + ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, + TL_SETUP_SIGNO_REBOOT_MSG_ACK); + packet->header.length = + sizeof(struct TlSetupRebootMsgAck); + send_packet(hw, PRIO_SETUP, &packet->header); + if (hw->reboot_callback) + hw->reboot_callback(hw->reboot_callback_data); + } + break; + + default: + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": unknown setup message %u received\n", + (unsigned int) rx_msg->sig_no); + } +} + +static void do_close_hardware(struct ipw_hardware *hw) +{ + unsigned int irqn; + + if (hw->hw_version == HW_VERSION_1) { + /* Disable TX and RX interrupts. */ + outw(0, hw->base_port + IOIER); + + /* Acknowledge any outstanding interrupt requests */ + irqn = inw(hw->base_port + IOIR); + if (irqn & IR_TXINTR) + outw(IR_TXINTR, hw->base_port + IOIR); + if (irqn & IR_RXINTR) + outw(IR_RXINTR, hw->base_port + IOIR); + + synchronize_irq(hw->irq); + } +} + +struct ipw_hardware *ipwireless_hardware_create(void) +{ + int i; + struct ipw_hardware *hw = + kzalloc(sizeof(struct ipw_hardware), GFP_KERNEL); + + if (!hw) + return NULL; + + hw->irq = -1; + hw->initializing = 1; + hw->tx_ready = 1; + hw->rx_bytes_queued = 0; + hw->rx_pool_size = 0; + hw->last_memtx_serial = (unsigned short) 0xffff; + for (i = 0; i < NL_NUM_OF_PRIORITIES; i++) + INIT_LIST_HEAD(&hw->tx_queue[i]); + + INIT_LIST_HEAD(&hw->rx_queue); + INIT_LIST_HEAD(&hw->rx_pool); + spin_lock_init(&hw->spinlock); + tasklet_init(&hw->tasklet, ipwireless_do_tasklet, (unsigned long) hw); + INIT_WORK(&hw->work_rx, ipw_receive_data_work); + setup_timer(&hw->setup_timer, ipwireless_setup_timer, + (unsigned long) hw); + + return hw; +} + +void ipwireless_init_hardware_v1(struct ipw_hardware *hw, + unsigned int base_port, + void __iomem *attr_memory, + void __iomem *common_memory, + int is_v2_card, + void (*reboot_callback) (void *data), + void *reboot_callback_data) +{ + if (hw->removed) { + hw->removed = 0; + enable_irq(hw->irq); + } + hw->base_port = base_port; + hw->hw_version = is_v2_card ? HW_VERSION_2 : HW_VERSION_1; + hw->ll_mtu = hw->hw_version == HW_VERSION_1 ? LL_MTU_V1 : LL_MTU_V2; + hw->memregs_CCR = (struct MEMCCR __iomem *) + ((unsigned short __iomem *) attr_memory + 0x200); + hw->memory_info_regs = (struct MEMINFREG __iomem *) common_memory; + hw->memreg_tx = &hw->memory_info_regs->memreg_tx_new; + hw->reboot_callback = reboot_callback; + hw->reboot_callback_data = reboot_callback_data; +} + +void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw) +{ + hw->initializing = 1; + hw->init_loops = 0; + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": waiting for card to start up...\n"); + ipwireless_setup_timer((unsigned long) hw); +} + +static void ipwireless_setup_timer(unsigned long data) +{ + struct ipw_hardware *hw = (struct ipw_hardware *) data; + + hw->init_loops++; + + if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY && + hw->hw_version == HW_VERSION_2 && + hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": failed to startup using TX2, trying TX\n"); + + hw->memreg_tx = &hw->memory_info_regs->memreg_tx_old; + hw->init_loops = 0; + } + /* Give up after a certain number of retries */ + if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY) { + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": card failed to start up!\n"); + hw->initializing = 0; + } else { + /* Do not attempt to write to the board if it is not present. */ + if (is_card_present(hw)) { + unsigned long flags; + + spin_lock_irqsave(&hw->spinlock, flags); + hw->to_setup = 1; + hw->tx_ready = 1; + spin_unlock_irqrestore(&hw->spinlock, flags); + tasklet_schedule(&hw->tasklet); + } + + mod_timer(&hw->setup_timer, + jiffies + msecs_to_jiffies(TL_SETUP_VERSION_QRY_TMO)); + } +} + +/* + * Stop any interrupts from executing so that, once this function returns, + * other layers of the driver can be sure they won't get any more callbacks. + * Thus must be called on a proper process context. + */ +void ipwireless_stop_interrupts(struct ipw_hardware *hw) +{ + if (!hw->shutting_down) { + /* Tell everyone we are going down. */ + hw->shutting_down = 1; + del_timer(&hw->setup_timer); + + /* Prevent the hardware from sending any more interrupts */ + do_close_hardware(hw); + } +} + +void ipwireless_hardware_free(struct ipw_hardware *hw) +{ + int i; + struct ipw_rx_packet *rp, *rq; + struct ipw_tx_packet *tp, *tq; + + ipwireless_stop_interrupts(hw); + + flush_scheduled_work(); + + for (i = 0; i < NL_NUM_OF_ADDRESSES; i++) + if (hw->packet_assembler[i] != NULL) + kfree(hw->packet_assembler[i]); + + for (i = 0; i < NL_NUM_OF_PRIORITIES; i++) + list_for_each_entry_safe(tp, tq, &hw->tx_queue[i], queue) { + list_del(&tp->queue); + kfree(tp); + } + + list_for_each_entry_safe(rp, rq, &hw->rx_queue, queue) { + list_del(&rp->queue); + kfree(rp); + } + + list_for_each_entry_safe(rp, rq, &hw->rx_pool, queue) { + list_del(&rp->queue); + kfree(rp); + } + kfree(hw); +} + +/* + * Associate the specified network with this hardware, so it will receive events + * from it. + */ +void ipwireless_associate_network(struct ipw_hardware *hw, + struct ipw_network *network) +{ + hw->network = network; +} diff --git a/drivers/char/pcmcia/ipwireless/hardware.h b/drivers/char/pcmcia/ipwireless/hardware.h new file mode 100644 index 000000000000..c83190ffb0e7 --- /dev/null +++ b/drivers/char/pcmcia/ipwireless/hardware.h @@ -0,0 +1,64 @@ +/* + * IPWireless 3G PCMCIA Network Driver + * + * Original code + * by Stephen Blackheath <stephen@blacksapphire.com>, + * Ben Martel <benm@symmetric.co.nz> + * + * Copyrighted as follows: + * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) + * + * Various driver changes and rewrites, port to new kernels + * Copyright (C) 2006-2007 Jiri Kosina + * + * Misc code cleanups and updates + * Copyright (C) 2007 David Sterba + */ + +#ifndef _IPWIRELESS_CS_HARDWARE_H_ +#define _IPWIRELESS_CS_HARDWARE_H_ + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#define IPW_CONTROL_LINE_CTS 0x0001 +#define IPW_CONTROL_LINE_DCD 0x0002 +#define IPW_CONTROL_LINE_DSR 0x0004 +#define IPW_CONTROL_LINE_RI 0x0008 +#define IPW_CONTROL_LINE_DTR 0x0010 +#define IPW_CONTROL_LINE_RTS 0x0020 + +struct ipw_hardware; +struct ipw_network; + +struct ipw_hardware *ipwireless_hardware_create(void); +void ipwireless_hardware_free(struct ipw_hardware *hw); +irqreturn_t ipwireless_interrupt(int irq, void *dev_id, struct pt_regs *regs); +int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx, + int state); +int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx, + int state); +int ipwireless_send_packet(struct ipw_hardware *hw, + unsigned int channel_idx, + unsigned char *data, + unsigned int length, + void (*packet_sent_callback) (void *cb, + unsigned int length), + void *sent_cb_data); +void ipwireless_associate_network(struct ipw_hardware *hw, + struct ipw_network *net); +void ipwireless_stop_interrupts(struct ipw_hardware *hw); +void ipwireless_init_hardware_v1(struct ipw_hardware *hw, + unsigned int base_port, + void __iomem *attr_memory, + void __iomem *common_memory, + int is_v2_card, + void (*reboot_cb) (void *data), + void *reboot_cb_data); +void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw); +void ipwireless_sleep(unsigned int tenths); +int ipwireless_dump_hardware_state(char *p, size_t limit, + struct ipw_hardware *hw); + +#endif diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c new file mode 100644 index 000000000000..00c7f8407e3e --- /dev/null +++ b/drivers/char/pcmcia/ipwireless/main.c @@ -0,0 +1,501 @@ +/* + * IPWireless 3G PCMCIA Network Driver + * + * Original code + * by Stephen Blackheath <stephen@blacksapphire.com>, + * Ben Martel <benm@symmetric.co.nz> + * + * Copyrighted as follows: + * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) + * + * Various driver changes and rewrites, port to new kernels + * Copyright (C) 2006-2007 Jiri Kosina + * + * Misc code cleanups and updates + * Copyright (C) 2007 David Sterba + */ + +#include "hardware.h" +#include "network.h" +#include "main.h" +#include "tty.h" + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/slab.h> + +#include <pcmcia/version.h> +#include <pcmcia/cisreg.h> +#include <pcmcia/device_id.h> +#include <pcmcia/ss.h> +#include <pcmcia/ds.h> +#include <pcmcia/cs.h> + +static struct pcmcia_device_id ipw_ids[] = { + PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100), + PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200), + PCMCIA_DEVICE_NULL +}; +MODULE_DEVICE_TABLE(pcmcia, ipw_ids); + +static void ipwireless_detach(struct pcmcia_device *link); + +/* + * Module params + */ +/* Debug mode: more verbose, print sent/recv bytes */ +int ipwireless_debug; +int ipwireless_loopback; +int ipwireless_out_queue = 1; + +module_param_named(debug, ipwireless_debug, int, 0); +module_param_named(loopback, ipwireless_loopback, int, 0); +module_param_named(out_queue, ipwireless_out_queue, int, 0); +MODULE_PARM_DESC(debug, "switch on debug messages [0]"); +MODULE_PARM_DESC(loopback, + "debug: enable ras_raw channel [0]"); +MODULE_PARM_DESC(out_queue, "debug: set size of outgoing queue [1]"); + +/* Executes in process context. */ +static void signalled_reboot_work(struct work_struct *work_reboot) +{ + struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev, + work_reboot); + struct pcmcia_device *link = ipw->link; + int ret = pccard_reset_card(link->socket); + + if (ret != CS_SUCCESS) + cs_error(link, ResetCard, ret); +} + +static void signalled_reboot_callback(void *callback_data) +{ + struct ipw_dev *ipw = (struct ipw_dev *) callback_data; + + /* Delegate to process context. */ + schedule_work(&ipw->work_reboot); +} + +static int config_ipwireless(struct ipw_dev *ipw) +{ + struct pcmcia_device *link = ipw->link; + int ret; + config_info_t conf; + tuple_t tuple; + unsigned short buf[64]; + cisparse_t parse; + unsigned short cor_value; + win_req_t request_attr_memory; + win_req_t request_common_memory; + memreq_t memreq_attr_memory; + memreq_t memreq_common_memory; + + ipw->is_v2_card = 0; + + tuple.Attributes = 0; + tuple.TupleData = (cisdata_t *) buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + + tuple.DesiredTuple = RETURN_FIRST_TUPLE; + + ret = pcmcia_get_first_tuple(link, &tuple); + + while (ret == 0) { + ret = pcmcia_get_tuple_data(link, &tuple); + + if (ret != CS_SUCCESS) { + cs_error(link, GetTupleData, ret); + goto exit0; + } + ret = pcmcia_get_next_tuple(link, &tuple); + } + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + + ret = pcmcia_get_first_tuple(link, &tuple); + + if (ret != CS_SUCCESS) { + cs_error(link, GetFirstTuple, ret); + goto exit0; + } + + ret = pcmcia_get_tuple_data(link, &tuple); + + if (ret != CS_SUCCESS) { + cs_error(link, GetTupleData, ret); + goto exit0; + } + + ret = pcmcia_parse_tuple(link, &tuple, &parse); + + if (ret != CS_SUCCESS) { + cs_error(link, ParseTuple, ret); + goto exit0; + } + + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.BasePort1 = parse.cftable_entry.io.win[0].base; + link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; + link->io.IOAddrLines = 16; + + link->irq.IRQInfo1 = parse.cftable_entry.irq.IRQInfo1; + + /* 0x40 causes it to generate level mode interrupts. */ + /* 0x04 enables IREQ pin. */ + cor_value = parse.cftable_entry.index | 0x44; + link->conf.ConfigIndex = cor_value; + + /* IRQ and I/O settings */ + tuple.DesiredTuple = CISTPL_CONFIG; + + ret = pcmcia_get_first_tuple(link, &tuple); + + if (ret != CS_SUCCESS) { + cs_error(link, GetFirstTuple, ret); + goto exit0; + } + + ret = pcmcia_get_tuple_data(link, &tuple); + + if (ret != CS_SUCCESS) { + cs_error(link, GetTupleData, ret); + goto exit0; + } + + ret = pcmcia_parse_tuple(link, &tuple, &parse); + + if (ret != CS_SUCCESS) { + cs_error(link, GetTupleData, ret); + goto exit0; + } + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + link->conf.IntType = INT_MEMORY_AND_IO; + + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; + link->irq.Handler = ipwireless_interrupt; + link->irq.Instance = ipw->hardware; + + ret = pcmcia_request_io(link, &link->io); + + if (ret != CS_SUCCESS) { + cs_error(link, RequestIO, ret); + goto exit0; + } + + /* memory settings */ + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + + ret = pcmcia_get_first_tuple(link, &tuple); + + if (ret != CS_SUCCESS) { + cs_error(link, GetFirstTuple, ret); + goto exit1; + } + + ret = pcmcia_get_tuple_data(link, &tuple); + + if (ret != CS_SUCCESS) { + cs_error(link, GetTupleData, ret); + goto exit1; + } + + ret = pcmcia_parse_tuple(link, &tuple, &parse); + + if (ret != CS_SUCCESS) { + cs_error(link, ParseTuple, ret); + goto exit1; + } + + if (parse.cftable_entry.mem.nwin > 0) { + request_common_memory.Attributes = + WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; + request_common_memory.Base = + parse.cftable_entry.mem.win[0].host_addr; + request_common_memory.Size = parse.cftable_entry.mem.win[0].len; + if (request_common_memory.Size < 0x1000) + request_common_memory.Size = 0x1000; + request_common_memory.AccessSpeed = 0; + + ret = pcmcia_request_window(&link, &request_common_memory, + &ipw->handle_common_memory); + + if (ret != CS_SUCCESS) { + cs_error(link, RequestWindow, ret); + goto exit1; + } + + memreq_common_memory.CardOffset = + parse.cftable_entry.mem.win[0].card_addr; + memreq_common_memory.Page = 0; + + ret = pcmcia_map_mem_page(ipw->handle_common_memory, + &memreq_common_memory); + + if (ret != CS_SUCCESS) { + cs_error(link, MapMemPage, ret); + goto exit1; + } + + ipw->is_v2_card = + parse.cftable_entry.mem.win[0].len == 0x100; + + ipw->common_memory = ioremap(request_common_memory.Base, + request_common_memory.Size); + + request_attr_memory.Attributes = + WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE; + request_attr_memory.Base = 0; + request_attr_memory.Size = 0; /* this used to be 0x1000 */ + request_attr_memory.AccessSpeed = 0; + + ret = pcmcia_request_window(&link, &request_attr_memory, + &ipw->handle_attr_memory); + + if (ret != CS_SUCCESS) { + cs_error(link, RequestWindow, ret); + goto exit2; + } + + memreq_attr_memory.CardOffset = 0; + memreq_attr_memory.Page = 0; + + ret = pcmcia_map_mem_page(ipw->handle_attr_memory, + &memreq_attr_memory); + + if (ret != CS_SUCCESS) { + cs_error(link, MapMemPage, ret); + goto exit2; + } + + ipw->attr_memory = ioremap(request_attr_memory.Base, + request_attr_memory.Size); + } + + INIT_WORK(&ipw->work_reboot, signalled_reboot_work); + + ipwireless_init_hardware_v1(ipw->hardware, link->io.BasePort1, + ipw->attr_memory, ipw->common_memory, + ipw->is_v2_card, signalled_reboot_callback, + ipw); + + ret = pcmcia_request_irq(link, &link->irq); + + if (ret != CS_SUCCESS) { + cs_error(link, RequestIRQ, ret); + goto exit3; + } + + /* Look up current Vcc */ + + ret = pcmcia_get_configuration_info(link, &conf); + + if (ret != CS_SUCCESS) { + cs_error(link, GetConfigurationInfo, ret); + goto exit4; + } + + printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n", + ipw->is_v2_card ? "V2/V3" : "V1"); + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": I/O ports 0x%04x-0x%04x, irq %d\n", + (unsigned int) link->io.BasePort1, + (unsigned int) (link->io.BasePort1 + + link->io.NumPorts1 - 1), + (unsigned int) link->irq.AssignedIRQ); + if (ipw->attr_memory && ipw->common_memory) + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": attr memory 0x%08lx-0x%08lx, " + "common memory 0x%08lx-0x%08lx\n", + request_attr_memory.Base, + request_attr_memory.Base + + request_attr_memory.Size - 1, + request_common_memory.Base, + request_common_memory.Base + + request_common_memory.Size - 1); + + ipw->network = ipwireless_network_create(ipw->hardware); + if (!ipw->network) + goto exit3; + + ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network, + ipw->nodes); + if (!ipw->tty) + goto exit3; + + ipwireless_init_hardware_v2_v3(ipw->hardware); + + /* + * Do the RequestConfiguration last, because it enables interrupts. + * Then we don't get any interrupts before we're ready for them. + */ + ret = pcmcia_request_configuration(link, &link->conf); + + if (ret != CS_SUCCESS) { + cs_error(link, RequestConfiguration, ret); + goto exit4; + } + + link->dev_node = &ipw->nodes[0]; + + return 0; + +exit4: + pcmcia_disable_device(link); +exit3: + if (ipw->attr_memory) { + iounmap(ipw->attr_memory); + pcmcia_release_window(ipw->handle_attr_memory); + pcmcia_disable_device(link); + } +exit2: + if (ipw->common_memory) { + iounmap(ipw->common_memory); + pcmcia_release_window(ipw->handle_common_memory); + } +exit1: + pcmcia_disable_device(link); +exit0: + return -1; +} + +static void release_ipwireless(struct ipw_dev *ipw) +{ + struct pcmcia_device *link = ipw->link; + + pcmcia_disable_device(link); + + if (ipw->common_memory) + iounmap(ipw->common_memory); + if (ipw->attr_memory) + iounmap(ipw->attr_memory); + if (ipw->common_memory) + pcmcia_release_window(ipw->handle_common_memory); + if (ipw->attr_memory) + pcmcia_release_window(ipw->handle_attr_memory); + pcmcia_disable_device(link); +} + +/* + * ipwireless_attach() creates an "instance" of the driver, allocating + * local data structures for one device (one interface). The device + * is registered with Card Services. + * + * The pcmcia_device structure is initialized, but we don't actually + * configure the card at this point -- we wait until we receive a + * card insertion event. + */ +static int ipwireless_attach(struct pcmcia_device *link) +{ + struct ipw_dev *ipw; + int ret; + + ipw = kzalloc(sizeof(struct ipw_dev), GFP_KERNEL); + if (!ipw) + return -ENOMEM; + + ipw->link = link; + link->priv = ipw; + link->irq.Instance = ipw; + + /* Link this device into our device list. */ + link->dev_node = &ipw->nodes[0]; + + ipw->hardware = ipwireless_hardware_create(); + if (!ipw->hardware) { + kfree(ipw); + return -ENOMEM; + } + /* RegisterClient will call config_ipwireless */ + + ret = config_ipwireless(ipw); + + if (ret != 0) { + cs_error(link, RegisterClient, ret); + ipwireless_detach(link); + return ret; + } + + return 0; +} + +/* + * This deletes a driver "instance". The device is de-registered with + * Card Services. If it has been released, all local data structures + * are freed. Otherwise, the structures will be freed when the device + * is released. + */ +static void ipwireless_detach(struct pcmcia_device *link) +{ + struct ipw_dev *ipw = link->priv; + + release_ipwireless(ipw); + + /* Break the link with Card Services */ + if (link) + pcmcia_disable_device(link); + + if (ipw->tty != NULL) + ipwireless_tty_free(ipw->tty); + if (ipw->network != NULL) + ipwireless_network_free(ipw->network); + if (ipw->hardware != NULL) + ipwireless_hardware_free(ipw->hardware); + kfree(ipw); +} + +static struct pcmcia_driver me = { + .owner = THIS_MODULE, + .probe = ipwireless_attach, + .remove = ipwireless_detach, + .drv = { .name = IPWIRELESS_PCCARD_NAME }, + .id_table = ipw_ids +}; + +/* + * Module insertion : initialisation of the module. + * Register the card with cardmgr... + */ +static int __init init_ipwireless(void) +{ + int ret; + + printk(KERN_INFO IPWIRELESS_PCCARD_NAME " " + IPWIRELESS_PCMCIA_VERSION " by " IPWIRELESS_PCMCIA_AUTHOR "\n"); + + ret = ipwireless_tty_init(); + if (ret != 0) + return ret; + + ret = pcmcia_register_driver(&me); + if (ret != 0) + ipwireless_tty_release(); + + return ret; +} + +/* + * Module removal + */ +static void __exit exit_ipwireless(void) +{ + printk(KERN_INFO IPWIRELESS_PCCARD_NAME " " + IPWIRELESS_PCMCIA_VERSION " removed\n"); + + pcmcia_unregister_driver(&me); + ipwireless_tty_release(); +} + +module_init(init_ipwireless); +module_exit(exit_ipwireless); + +MODULE_AUTHOR(IPWIRELESS_PCMCIA_AUTHOR); +MODULE_DESCRIPTION(IPWIRELESS_PCCARD_NAME " " IPWIRELESS_PCMCIA_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/pcmcia/ipwireless/main.h b/drivers/char/pcmcia/ipwireless/main.h new file mode 100644 index 000000000000..1bfdcc8d47d6 --- /dev/null +++ b/drivers/char/pcmcia/ipwireless/main.h @@ -0,0 +1,70 @@ +/* + * IPWireless 3G PCMCIA Network Driver + * + * Original code + * by Stephen Blackheath <stephen@blacksapphire.com>, + * Ben Martel <benm@symmetric.co.nz> + * + * Copyrighted as follows: + * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) + * + * Various driver changes and rewrites, port to new kernels + * Copyright (C) 2006-2007 Jiri Kosina + * + * Misc code cleanups and updates + * Copyright (C) 2007 David Sterba + */ + +#ifndef _IPWIRELESS_CS_H_ +#define _IPWIRELESS_CS_H_ + +#include <linux/sched.h> +#include <linux/types.h> + +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/ds.h> + +#include "hardware.h" + +#define IPWIRELESS_PCCARD_NAME "ipwireless" +#define IPWIRELESS_PCMCIA_VERSION "1.1" +#define IPWIRELESS_PCMCIA_AUTHOR \ + "Stephen Blackheath, Ben Martel, Jiri Kosina and David Sterba" + +#define IPWIRELESS_TX_QUEUE_SIZE 262144 +#define IPWIRELESS_RX_QUEUE_SIZE 262144 + +#define IPWIRELESS_STATE_DEBUG + +struct ipw_hardware; +struct ipw_network; +struct ipw_tty; + +struct ipw_dev { + struct pcmcia_device *link; + int is_v2_card; + window_handle_t handle_attr_memory; + void __iomem *attr_memory; + window_handle_t handle_common_memory; + void __iomem *common_memory; + dev_node_t nodes[2]; + /* Reference to attribute memory, containing CIS data */ + void *attribute_memory; + + /* Hardware context */ + struct ipw_hardware *hardware; + /* Network layer context */ + struct ipw_network *network; + /* TTY device context */ + struct ipw_tty *tty; + struct work_struct work_reboot; +}; + +/* Module parametres */ +extern int ipwireless_debug; +extern int ipwireless_loopback; +extern int ipwireless_out_queue; + +#endif diff --git a/drivers/char/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c new file mode 100644 index 000000000000..ff35230058d3 --- /dev/null +++ b/drivers/char/pcmcia/ipwireless/network.c @@ -0,0 +1,512 @@ +/* + * IPWireless 3G PCMCIA Network Driver + * + * Original code + * by Stephen Blackheath <stephen@blacksapphire.com>, + * Ben Martel <benm@symmetric.co.nz> + * + * Copyrighted as follows: + * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) + * + * Various driver changes and rewrites, port to new kernels + * Copyright (C) 2006-2007 Jiri Kosina + * + * Misc code cleanups and updates + * Copyright (C) 2007 David Sterba + */ + +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mutex.h> +#include <linux/netdevice.h> +#include <linux/ppp_channel.h> +#include <linux/ppp_defs.h> +#include <linux/if_ppp.h> +#include <linux/skbuff.h> + +#include "network.h" +#include "hardware.h" +#include "main.h" +#include "tty.h" + +#define MAX_OUTGOING_PACKETS_QUEUED ipwireless_out_queue +#define MAX_ASSOCIATED_TTYS 2 + +#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) + +struct ipw_network { + /* Hardware context, used for calls to hardware layer. */ + struct ipw_hardware *hardware; + /* Context for kernel 'generic_ppp' functionality */ + struct ppp_channel *ppp_channel; + /* tty context connected with IPW console */ + struct ipw_tty *associated_ttys[NO_OF_IPW_CHANNELS][MAX_ASSOCIATED_TTYS]; + /* True if ppp needs waking up once we're ready to xmit */ + int ppp_blocked; + /* Number of packets queued up in hardware module. */ + int outgoing_packets_queued; + /* Spinlock to avoid interrupts during shutdown */ + spinlock_t spinlock; + struct mutex close_lock; + + /* PPP ioctl data, not actually used anywere */ + unsigned int flags; + unsigned int rbits; + u32 xaccm[8]; + u32 raccm; + int mru; + + int shutting_down; + unsigned int ras_control_lines; + + struct work_struct work_go_online; + struct work_struct work_go_offline; +}; + + +#ifdef IPWIRELESS_STATE_DEBUG +int ipwireless_dump_network_state(char *p, size_t limit, + struct ipw_network *network) +{ + return snprintf(p, limit, + "debug: ppp_blocked=%d\n" + "debug: outgoing_packets_queued=%d\n" + "debug: network.shutting_down=%d\n", + network->ppp_blocked, + network->outgoing_packets_queued, + network->shutting_down); +} +#endif + +static void notify_packet_sent(void *callback_data, unsigned int packet_length) +{ + struct ipw_network *network = callback_data; + unsigned long flags; + + spin_lock_irqsave(&network->spinlock, flags); + network->outgoing_packets_queued--; + if (network->ppp_channel != NULL) { + if (network->ppp_blocked) { + network->ppp_blocked = 0; + spin_unlock_irqrestore(&network->spinlock, flags); + ppp_output_wakeup(network->ppp_channel); + if (ipwireless_debug) + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": ppp unblocked\n"); + } else + spin_unlock_irqrestore(&network->spinlock, flags); + } else + spin_unlock_irqrestore(&network->spinlock, flags); +} + +/* + * Called by the ppp system when it has a packet to send to the hardware. + */ +static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel, + struct sk_buff *skb) +{ + struct ipw_network *network = ppp_channel->private; + unsigned long flags; + + spin_lock_irqsave(&network->spinlock, flags); + if (network->outgoing_packets_queued < MAX_OUTGOING_PACKETS_QUEUED) { + unsigned char *buf; + static unsigned char header[] = { + PPP_ALLSTATIONS, /* 0xff */ + PPP_UI, /* 0x03 */ + }; + int ret; + + network->outgoing_packets_queued++; + spin_unlock_irqrestore(&network->spinlock, flags); + + /* + * If we have the requested amount of headroom in the skb we + * were handed, then we can add the header efficiently. + */ + if (skb_headroom(skb) >= 2) { + memcpy(skb_push(skb, 2), header, 2); + ret = ipwireless_send_packet(network->hardware, + IPW_CHANNEL_RAS, skb->data, + skb->len, + notify_packet_sent, + network); + if (ret == -1) { + skb_pull(skb, 2); + return 0; + } + } else { + /* Otherwise (rarely) we do it inefficiently. */ + buf = kmalloc(skb->len + 2, GFP_ATOMIC); + if (!buf) + return 0; + memcpy(buf + 2, skb->data, skb->len); + memcpy(buf, header, 2); + ret = ipwireless_send_packet(network->hardware, + IPW_CHANNEL_RAS, buf, + skb->len + 2, + notify_packet_sent, + network); + kfree(buf); + if (ret == -1) + return 0; + } + kfree_skb(skb); + return 1; + } else { + /* + * Otherwise reject the packet, and flag that the ppp system + * needs to be unblocked once we are ready to send. + */ + network->ppp_blocked = 1; + spin_unlock_irqrestore(&network->spinlock, flags); + return 0; + } +} + +/* Handle an ioctl call that has come in via ppp. (copy of ppp_async_ioctl() */ +static int ipwireless_ppp_ioctl(struct ppp_channel *ppp_channel, + unsigned int cmd, unsigned long arg) +{ + struct ipw_network *network = ppp_channel->private; + int err, val; + u32 accm[8]; + int __user *user_arg = (int __user *) arg; + + err = -EFAULT; + switch (cmd) { + case PPPIOCGFLAGS: + val = network->flags | network->rbits; + if (put_user(val, user_arg)) + break; + err = 0; + break; + + case PPPIOCSFLAGS: + if (get_user(val, user_arg)) + break; + network->flags = val & ~SC_RCV_BITS; + network->rbits = val & SC_RCV_BITS; + err = 0; + break; + + case PPPIOCGASYNCMAP: + if (put_user(network->xaccm[0], user_arg)) + break; + err = 0; + break; + + case PPPIOCSASYNCMAP: + if (get_user(network->xaccm[0], user_arg)) + break; + err = 0; + break; + + case PPPIOCGRASYNCMAP: + if (put_user(network->raccm, user_arg)) + break; + err = 0; + break; + + case PPPIOCSRASYNCMAP: + if (get_user(network->raccm, user_arg)) + break; + err = 0; + break; + + case PPPIOCGXASYNCMAP: + if (copy_to_user((void __user *) arg, network->xaccm, + sizeof(network->xaccm))) + break; + err = 0; + break; + + case PPPIOCSXASYNCMAP: + if (copy_from_user(accm, (void __user *) arg, sizeof(accm))) + break; + accm[2] &= ~0x40000000U; /* can't escape 0x5e */ + accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */ + memcpy(network->xaccm, accm, sizeof(network->xaccm)); + err = 0; + break; + + case PPPIOCGMRU: + if (put_user(network->mru, user_arg)) + break; + err = 0; + break; + + case PPPIOCSMRU: + if (get_user(val, user_arg)) + break; + if (val < PPP_MRU) + val = PPP_MRU; + network->mru = val; + err = 0; + break; + + default: + err = -ENOTTY; + } + + return err; +} + +static struct ppp_channel_ops ipwireless_ppp_channel_ops = { + .start_xmit = ipwireless_ppp_start_xmit, + .ioctl = ipwireless_ppp_ioctl +}; + +static void do_go_online(struct work_struct *work_go_online) +{ + struct ipw_network *network = + container_of(work_go_online, struct ipw_network, + work_go_online); + unsigned long flags; + + spin_lock_irqsave(&network->spinlock, flags); + if (!network->ppp_channel) { + struct ppp_channel *channel; + + spin_unlock_irqrestore(&network->spinlock, flags); + channel = kzalloc(sizeof(struct ppp_channel), GFP_KERNEL); + if (!channel) { + printk(KERN_ERR IPWIRELESS_PCCARD_NAME + ": unable to allocate PPP channel\n"); + return; + } + channel->private = network; + channel->mtu = 16384; /* Wild guess */ + channel->hdrlen = 2; + channel->ops = &ipwireless_ppp_channel_ops; + + network->flags = 0; + network->rbits = 0; + network->mru = PPP_MRU; + memset(network->xaccm, 0, sizeof(network->xaccm)); + network->xaccm[0] = ~0U; + network->xaccm[3] = 0x60000000U; + network->raccm = ~0U; + ppp_register_channel(channel); + spin_lock_irqsave(&network->spinlock, flags); + network->ppp_channel = channel; + } + spin_unlock_irqrestore(&network->spinlock, flags); +} + +static void do_go_offline(struct work_struct *work_go_offline) +{ + struct ipw_network *network = + container_of(work_go_offline, struct ipw_network, + work_go_offline); + unsigned long flags; + + mutex_lock(&network->close_lock); + spin_lock_irqsave(&network->spinlock, flags); + if (network->ppp_channel != NULL) { + struct ppp_channel *channel = network->ppp_channel; + + network->ppp_channel = NULL; + spin_unlock_irqrestore(&network->spinlock, flags); + mutex_unlock(&network->close_lock); + ppp_unregister_channel(channel); + } else { + spin_unlock_irqrestore(&network->spinlock, flags); + mutex_unlock(&network->close_lock); + } +} + +void ipwireless_network_notify_control_line_change(struct ipw_network *network, + unsigned int channel_idx, + unsigned int control_lines, + unsigned int changed_mask) +{ + int i; + + if (channel_idx == IPW_CHANNEL_RAS) + network->ras_control_lines = control_lines; + + for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) { + struct ipw_tty *tty = + network->associated_ttys[channel_idx][i]; + + /* + * If it's associated with a tty (other than the RAS channel + * when we're online), then send the data to that tty. The RAS + * channel's data is handled above - it always goes through + * ppp_generic. + */ + if (tty) + ipwireless_tty_notify_control_line_change(tty, + channel_idx, + control_lines, + changed_mask); + } +} + +/* + * Some versions of firmware stuff packets with 0xff 0x03 (PPP: ALLSTATIONS, UI) + * bytes, which are required on sent packet, but not always present on received + * packets + */ +static struct sk_buff *ipw_packet_received_skb(unsigned char *data, + unsigned int length) +{ + struct sk_buff *skb; + + if (length > 2 && data[0] == PPP_ALLSTATIONS && data[1] == PPP_UI) { + length -= 2; + data += 2; + } + + skb = dev_alloc_skb(length + 4); + skb_reserve(skb, 2); + memcpy(skb_put(skb, length), data, length); + + return skb; +} + +void ipwireless_network_packet_received(struct ipw_network *network, + unsigned int channel_idx, + unsigned char *data, + unsigned int length) +{ + int i; + unsigned long flags; + + for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) { + struct ipw_tty *tty = network->associated_ttys[channel_idx][i]; + + /* + * If it's associated with a tty (other than the RAS channel + * when we're online), then send the data to that tty. The RAS + * channel's data is handled above - it always goes through + * ppp_generic. + */ + if (tty && channel_idx == IPW_CHANNEL_RAS + && (network->ras_control_lines & + IPW_CONTROL_LINE_DCD) != 0 + && ipwireless_tty_is_modem(tty)) { + /* + * If data came in on the RAS channel and this tty is + * the modem tty, and we are online, then we send it to + * the PPP layer. + */ + mutex_lock(&network->close_lock); + spin_lock_irqsave(&network->spinlock, flags); + if (network->ppp_channel != NULL) { + struct sk_buff *skb; + + spin_unlock_irqrestore(&network->spinlock, + flags); + + /* Send the data to the ppp_generic module. */ + skb = ipw_packet_received_skb(data, length); + ppp_input(network->ppp_channel, skb); + } else + spin_unlock_irqrestore(&network->spinlock, + flags); + mutex_unlock(&network->close_lock); + } + /* Otherwise we send it out the tty. */ + else + ipwireless_tty_received(tty, data, length); + } +} + +struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw) +{ + struct ipw_network *network = + kzalloc(sizeof(struct ipw_network), GFP_ATOMIC); + + if (!network) + return NULL; + + spin_lock_init(&network->spinlock); + mutex_init(&network->close_lock); + + network->hardware = hw; + + INIT_WORK(&network->work_go_online, do_go_online); + INIT_WORK(&network->work_go_offline, do_go_offline); + + ipwireless_associate_network(hw, network); + + return network; +} + +void ipwireless_network_free(struct ipw_network *network) +{ + network->shutting_down = 1; + + ipwireless_ppp_close(network); + flush_scheduled_work(); + + ipwireless_stop_interrupts(network->hardware); + ipwireless_associate_network(network->hardware, NULL); + + kfree(network); +} + +void ipwireless_associate_network_tty(struct ipw_network *network, + unsigned int channel_idx, + struct ipw_tty *tty) +{ + int i; + + for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) + if (network->associated_ttys[channel_idx][i] == NULL) { + network->associated_ttys[channel_idx][i] = tty; + break; + } +} + +void ipwireless_disassociate_network_ttys(struct ipw_network *network, + unsigned int channel_idx) +{ + int i; + + for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) + network->associated_ttys[channel_idx][i] = NULL; +} + +void ipwireless_ppp_open(struct ipw_network *network) +{ + if (ipwireless_debug) + printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": online\n"); + schedule_work(&network->work_go_online); +} + +void ipwireless_ppp_close(struct ipw_network *network) +{ + /* Disconnect from the wireless network. */ + if (ipwireless_debug) + printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": offline\n"); + schedule_work(&network->work_go_offline); +} + +int ipwireless_ppp_channel_index(struct ipw_network *network) +{ + int ret = -1; + unsigned long flags; + + spin_lock_irqsave(&network->spinlock, flags); + if (network->ppp_channel != NULL) + ret = ppp_channel_index(network->ppp_channel); + spin_unlock_irqrestore(&network->spinlock, flags); + + return ret; +} + +int ipwireless_ppp_unit_number(struct ipw_network *network) +{ + int ret = -1; + unsigned long flags; + + spin_lock_irqsave(&network->spinlock, flags); + if (network->ppp_channel != NULL) + ret = ppp_unit_number(network->ppp_channel); + spin_unlock_irqrestore(&network->spinlock, flags); + + return ret; +} diff --git a/drivers/char/pcmcia/ipwireless/network.h b/drivers/char/pcmcia/ipwireless/network.h new file mode 100644 index 000000000000..b0e1e952fd14 --- /dev/null +++ b/drivers/char/pcmcia/ipwireless/network.h @@ -0,0 +1,55 @@ +/* + * IPWireless 3G PCMCIA Network Driver + * + * Original code + * by Stephen Blackheath <stephen@blacksapphire.com>, + * Ben Martel <benm@symmetric.co.nz> + * + * Copyrighted as follows: + * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) + * + * Various driver changes and rewrites, port to new kernels + * Copyright (C) 2006-2007 Jiri Kosina + * + * Misc code cleanups and updates + * Copyright (C) 2007 David Sterba + */ + +#ifndef _IPWIRELESS_CS_NETWORK_H_ +#define _IPWIRELESS_CS_NETWORK_H_ + +#include <linux/types.h> + +struct ipw_network; +struct ipw_tty; +struct ipw_hardware; + +/* Definitions of the different channels on the PCMCIA UE */ +#define IPW_CHANNEL_RAS 0 +#define IPW_CHANNEL_DIALLER 1 +#define IPW_CHANNEL_CONSOLE 2 +#define NO_OF_IPW_CHANNELS 5 + +void ipwireless_network_notify_control_line_change(struct ipw_network *net, + unsigned int channel_idx, unsigned int control_lines, + unsigned int control_mask); +void ipwireless_network_packet_received(struct ipw_network *net, + unsigned int channel_idx, unsigned char *data, + unsigned int length); +struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw); +void ipwireless_network_free(struct ipw_network *net); +void ipwireless_associate_network_tty(struct ipw_network *net, + unsigned int channel_idx, struct ipw_tty *tty); +void ipwireless_disassociate_network_ttys(struct ipw_network *net, + unsigned int channel_idx); + +void ipwireless_ppp_open(struct ipw_network *net); + +void ipwireless_ppp_close(struct ipw_network *net); +int ipwireless_ppp_channel_index(struct ipw_network *net); +int ipwireless_ppp_unit_number(struct ipw_network *net); + +int ipwireless_dump_network_state(char *p, size_t limit, + struct ipw_network *net); + +#endif diff --git a/drivers/char/pcmcia/ipwireless/setup_protocol.h b/drivers/char/pcmcia/ipwireless/setup_protocol.h new file mode 100644 index 000000000000..9d6bcc77c73c --- /dev/null +++ b/drivers/char/pcmcia/ipwireless/setup_protocol.h @@ -0,0 +1,108 @@ +/* + * IPWireless 3G PCMCIA Network Driver + * + * Original code + * by Stephen Blackheath <stephen@blacksapphire.com>, + * Ben Martel <benm@symmetric.co.nz> + * + * Copyrighted as follows: + * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) + * + * Various driver changes and rewrites, port to new kernels + * Copyright (C) 2006-2007 Jiri Kosina + * + * Misc code cleanups and updates + * Copyright (C) 2007 David Sterba + */ + +#ifndef _IPWIRELESS_CS_SETUP_PROTOCOL_H_ +#define _IPWIRELESS_CS_SETUP_PROTOCOL_H_ + +/* Version of the setup protocol and transport protocols */ +#define TL_SETUP_VERSION 1 + +#define TL_SETUP_VERSION_QRY_TMO 1000 +#define TL_SETUP_MAX_VERSION_QRY 30 + +/* Message numbers 0-9 are obsoleted and must not be reused! */ +#define TL_SETUP_SIGNO_GET_VERSION_QRY 10 +#define TL_SETUP_SIGNO_GET_VERSION_RSP 11 +#define TL_SETUP_SIGNO_CONFIG_MSG 12 +#define TL_SETUP_SIGNO_CONFIG_DONE_MSG 13 +#define TL_SETUP_SIGNO_OPEN_MSG 14 +#define TL_SETUP_SIGNO_CLOSE_MSG 15 + +#define TL_SETUP_SIGNO_INFO_MSG 20 +#define TL_SETUP_SIGNO_INFO_MSG_ACK 21 + +#define TL_SETUP_SIGNO_REBOOT_MSG 22 +#define TL_SETUP_SIGNO_REBOOT_MSG_ACK 23 + +/* Synchronous start-messages */ +struct tl_setup_get_version_qry { + unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_QRY */ +} __attribute__ ((__packed__)); + +struct tl_setup_get_version_rsp { + unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_RSP */ + unsigned char version; /* TL_SETUP_VERSION */ +} __attribute__ ((__packed__)); + +struct tl_setup_config_msg { + unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_MSG */ + unsigned char port_no; + unsigned char prio_data; + unsigned char prio_ctrl; +} __attribute__ ((__packed__)); + +struct tl_setup_config_done_msg { + unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_DONE_MSG */ +} __attribute__ ((__packed__)); + +/* Asyncronous messages */ +struct tl_setup_open_msg { + unsigned char sig_no; /* TL_SETUP_SIGNO_OPEN_MSG */ + unsigned char port_no; +} __attribute__ ((__packed__)); + +struct tl_setup_close_msg { + unsigned char sig_no; /* TL_SETUP_SIGNO_CLOSE_MSG */ + unsigned char port_no; +} __attribute__ ((__packed__)); + +/* Driver type - for use in tl_setup_info_msg.driver_type */ +#define COMM_DRIVER 0 +#define NDISWAN_DRIVER 1 +#define NDISWAN_DRIVER_MAJOR_VERSION 2 +#define NDISWAN_DRIVER_MINOR_VERSION 0 + +/* + * It should not matter when this message comes over as we just store the + * results and send the ACK. + */ +struct tl_setup_info_msg { + unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG */ + unsigned char driver_type; + unsigned char major_version; + unsigned char minor_version; +} __attribute__ ((__packed__)); + +struct tl_setup_info_msgAck { + unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG_ACK */ +} __attribute__ ((__packed__)); + +struct TlSetupRebootMsgAck { + unsigned char sig_no; /* TL_SETUP_SIGNO_REBOOT_MSG_ACK */ +} __attribute__ ((__packed__)); + +/* Define a union of all the msgs that the driver can receive from the card.*/ +union ipw_setup_rx_msg { + unsigned char sig_no; + struct tl_setup_get_version_rsp version_rsp_msg; + struct tl_setup_open_msg open_msg; + struct tl_setup_close_msg close_msg; + struct tl_setup_info_msg InfoMsg; + struct tl_setup_info_msgAck info_msg_ack; +} __attribute__ ((__packed__)); + +#endif /* _IPWIRELESS_CS_SETUP_PROTOCOL_H_ */ diff --git a/drivers/char/pcmcia/ipwireless/tty.c b/drivers/char/pcmcia/ipwireless/tty.c new file mode 100644 index 000000000000..42f3815c5ce3 --- /dev/null +++ b/drivers/char/pcmcia/ipwireless/tty.c @@ -0,0 +1,688 @@ +/* + * IPWireless 3G PCMCIA Network Driver + * + * Original code + * by Stephen Blackheath <stephen@blacksapphire.com>, + * Ben Martel <benm@symmetric.co.nz> + * + * Copyrighted as follows: + * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) + * + * Various driver changes and rewrites, port to new kernels + * Copyright (C) 2006-2007 Jiri Kosina + * + * Misc code cleanups and updates + * Copyright (C) 2007 David Sterba + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/ppp_defs.h> +#include <linux/if.h> +#include <linux/if_ppp.h> +#include <linux/sched.h> +#include <linux/serial.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/uaccess.h> +#include <linux/version.h> + +#include "tty.h" +#include "network.h" +#include "hardware.h" +#include "main.h" + +#define IPWIRELESS_PCMCIA_START (0) +#define IPWIRELESS_PCMCIA_MINORS (24) +#define IPWIRELESS_PCMCIA_MINOR_RANGE (8) + +#define TTYTYPE_MODEM (0) +#define TTYTYPE_MONITOR (1) +#define TTYTYPE_RAS_RAW (2) + +struct ipw_tty { + int index; + struct ipw_hardware *hardware; + unsigned int channel_idx; + unsigned int secondary_channel_idx; + int tty_type; + struct ipw_network *network; + struct tty_struct *linux_tty; + int open_count; + unsigned int control_lines; + struct mutex ipw_tty_mutex; + int tx_bytes_queued; + int closing; +}; + +static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS]; + +static struct tty_driver *ipw_tty_driver; + +static char *tty_type_name(int tty_type) +{ + static char *channel_names[] = { + "modem", + "monitor", + "RAS-raw" + }; + + return channel_names[tty_type]; +} + +static void report_registering(struct ipw_tty *tty) +{ + char *iftype = tty_type_name(tty->tty_type); + + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": registering %s device ttyIPWp%d\n", iftype, tty->index); +} + +static void report_deregistering(struct ipw_tty *tty) +{ + char *iftype = tty_type_name(tty->tty_type); + + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": deregistering %s device ttyIPWp%d\n", iftype, + tty->index); +} + +static struct ipw_tty *get_tty(int minor) +{ + if (minor < ipw_tty_driver->minor_start + || minor >= ipw_tty_driver->minor_start + + IPWIRELESS_PCMCIA_MINORS) + return NULL; + else { + int minor_offset = minor - ipw_tty_driver->minor_start; + + /* + * The 'ras_raw' channel is only available when 'loopback' mode + * is enabled. + * Number of minor starts with 16 (_RANGE * _RAS_RAW). + */ + if (!ipwireless_loopback && + minor_offset >= + IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW) + return NULL; + + return ttys[minor_offset]; + } +} + +static int ipw_open(struct tty_struct *linux_tty, struct file *filp) +{ + int minor = linux_tty->index; + struct ipw_tty *tty = get_tty(minor); + + if (!tty) + return -ENODEV; + + mutex_lock(&tty->ipw_tty_mutex); + + if (tty->closing) { + mutex_unlock(&tty->ipw_tty_mutex); + return -ENODEV; + } + if (tty->open_count == 0) + tty->tx_bytes_queued = 0; + + tty->open_count++; + + tty->linux_tty = linux_tty; + linux_tty->driver_data = tty; + linux_tty->low_latency = 1; + + if (tty->tty_type == TTYTYPE_MODEM) + ipwireless_ppp_open(tty->network); + + mutex_unlock(&tty->ipw_tty_mutex); + + return 0; +} + +static void do_ipw_close(struct ipw_tty *tty) +{ + tty->open_count--; + + if (tty->open_count == 0) { + struct tty_struct *linux_tty = tty->linux_tty; + + if (linux_tty != NULL) { + tty->linux_tty = NULL; + linux_tty->driver_data = NULL; + + if (tty->tty_type == TTYTYPE_MODEM) + ipwireless_ppp_close(tty->network); + } + } +} + +static void ipw_hangup(struct tty_struct *linux_tty) +{ + struct ipw_tty *tty = linux_tty->driver_data; + + if (!tty) + return; + + mutex_lock(&tty->ipw_tty_mutex); + if (tty->open_count == 0) { + mutex_unlock(&tty->ipw_tty_mutex); + return; + } + + do_ipw_close(tty); + + mutex_unlock(&tty->ipw_tty_mutex); +} + +static void ipw_close(struct tty_struct *linux_tty, struct file *filp) +{ + ipw_hangup(linux_tty); +} + +/* Take data received from hardware, and send it out the tty */ +void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, + unsigned int length) +{ + struct tty_struct *linux_tty; + int work = 0; + + mutex_lock(&tty->ipw_tty_mutex); + linux_tty = tty->linux_tty; + if (linux_tty == NULL) { + mutex_unlock(&tty->ipw_tty_mutex); + return; + } + + if (!tty->open_count) { + mutex_unlock(&tty->ipw_tty_mutex); + return; + } + mutex_unlock(&tty->ipw_tty_mutex); + + work = tty_insert_flip_string(linux_tty, data, length); + + if (work != length) + printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME + ": %d chars not inserted to flip buffer!\n", + length - work); + + /* + * This may sleep if ->low_latency is set + */ + if (work) + tty_flip_buffer_push(linux_tty); +} + +static void ipw_write_packet_sent_callback(void *callback_data, + unsigned int packet_length) +{ + struct ipw_tty *tty = callback_data; + + /* + * Packet has been sent, so we subtract the number of bytes from our + * tally of outstanding TX bytes. + */ + tty->tx_bytes_queued -= packet_length; +} + +static int ipw_write(struct tty_struct *linux_tty, + const unsigned char *buf, int count) +{ + struct ipw_tty *tty = linux_tty->driver_data; + int room, ret; + + if (!tty) + return -ENODEV; + + mutex_lock(&tty->ipw_tty_mutex); + if (!tty->open_count) { + mutex_unlock(&tty->ipw_tty_mutex); + return -EINVAL; + } + + room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; + if (room < 0) + room = 0; + /* Don't allow caller to write any more than we have room for */ + if (count > room) + count = room; + + if (count == 0) { + mutex_unlock(&tty->ipw_tty_mutex); + return 0; + } + + ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS, + (unsigned char *) buf, count, + ipw_write_packet_sent_callback, tty); + if (ret == -1) { + mutex_unlock(&tty->ipw_tty_mutex); + return 0; + } + + tty->tx_bytes_queued += count; + mutex_unlock(&tty->ipw_tty_mutex); + + return count; +} + +static int ipw_write_room(struct tty_struct *linux_tty) +{ + struct ipw_tty *tty = linux_tty->driver_data; + int room; + + if (!tty) + return -ENODEV; + + if (!tty->open_count) + return -EINVAL; + + room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; + if (room < 0) + room = 0; + + return room; +} + +static int ipwireless_get_serial_info(struct ipw_tty *tty, + struct serial_struct __user *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return (-EFAULT); + + memset(&tmp, 0, sizeof(tmp)); + tmp.type = PORT_UNKNOWN; + tmp.line = tty->index; + tmp.port = 0; + tmp.irq = 0; + tmp.flags = 0; + tmp.baud_base = 115200; + tmp.close_delay = 0; + tmp.closing_wait = 0; + tmp.custom_divisor = 0; + tmp.hub6 = 0; + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + + return 0; +} + +static int ipw_chars_in_buffer(struct tty_struct *linux_tty) +{ + struct ipw_tty *tty = linux_tty->driver_data; + + if (!tty) + return -ENODEV; + + if (!tty->open_count) + return -EINVAL; + + return tty->tx_bytes_queued; +} + +static int get_control_lines(struct ipw_tty *tty) +{ + unsigned int my = tty->control_lines; + unsigned int out = 0; + + if (my & IPW_CONTROL_LINE_RTS) + out |= TIOCM_RTS; + if (my & IPW_CONTROL_LINE_DTR) + out |= TIOCM_DTR; + if (my & IPW_CONTROL_LINE_CTS) + out |= TIOCM_CTS; + if (my & IPW_CONTROL_LINE_DSR) + out |= TIOCM_DSR; + if (my & IPW_CONTROL_LINE_DCD) + out |= TIOCM_CD; + + return out; +} + +static int set_control_lines(struct ipw_tty *tty, unsigned int set, + unsigned int clear) +{ + int ret; + + if (set & TIOCM_RTS) { + ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 1); + if (ret) + return ret; + if (tty->secondary_channel_idx != -1) { + ret = ipwireless_set_RTS(tty->hardware, + tty->secondary_channel_idx, 1); + if (ret) + return ret; + } + } + if (set & TIOCM_DTR) { + ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 1); + if (ret) + return ret; + if (tty->secondary_channel_idx != -1) { + ret = ipwireless_set_DTR(tty->hardware, + tty->secondary_channel_idx, 1); + if (ret) + return ret; + } + } + if (clear & TIOCM_RTS) { + ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 0); + if (tty->secondary_channel_idx != -1) { + ret = ipwireless_set_RTS(tty->hardware, + tty->secondary_channel_idx, 0); + if (ret) + return ret; + } + } + if (clear & TIOCM_DTR) { + ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 0); + if (tty->secondary_channel_idx != -1) { + ret = ipwireless_set_DTR(tty->hardware, + tty->secondary_channel_idx, 0); + if (ret) + return ret; + } + } + return 0; +} + +static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file) +{ + struct ipw_tty *tty = linux_tty->driver_data; + + if (!tty) + return -ENODEV; + + if (!tty->open_count) + return -EINVAL; + + return get_control_lines(tty); +} + +static int +ipw_tiocmset(struct tty_struct *linux_tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct ipw_tty *tty = linux_tty->driver_data; + + if (!tty) + return -ENODEV; + + if (!tty->open_count) + return -EINVAL; + + return set_control_lines(tty, set, clear); +} + +static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct ipw_tty *tty = linux_tty->driver_data; + + if (!tty) + return -ENODEV; + + if (!tty->open_count) + return -EINVAL; + + switch (cmd) { + case TIOCGSERIAL: + return ipwireless_get_serial_info(tty, (void __user *) arg); + + case TIOCSSERIAL: + return 0; /* Keeps the PCMCIA scripts happy. */ + } + + if (tty->tty_type == TTYTYPE_MODEM) { + switch (cmd) { + case PPPIOCGCHAN: + { + int chan = ipwireless_ppp_channel_index( + tty->network); + + if (chan < 0) + return -ENODEV; + if (put_user(chan, (int __user *) arg)) + return -EFAULT; + } + return 0; + + case PPPIOCGUNIT: + { + int unit = ipwireless_ppp_unit_number( + tty->network); + + if (unit < 0) + return -ENODEV; + if (put_user(unit, (int __user *) arg)) + return -EFAULT; + } + return 0; + + case TCGETS: + case TCGETA: + return n_tty_ioctl(linux_tty, file, cmd, arg); + + case TCFLSH: + return n_tty_ioctl(linux_tty, file, cmd, arg); + + case FIONREAD: + { + int val = 0; + + if (put_user(val, (int __user *) arg)) + return -EFAULT; + } + return 0; + } + } + + return -ENOIOCTLCMD; +} + +static int add_tty(dev_node_t *nodesp, int j, + struct ipw_hardware *hardware, + struct ipw_network *network, int channel_idx, + int secondary_channel_idx, int tty_type) +{ + ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL); + if (!ttys[j]) + return -ENOMEM; + ttys[j]->index = j; + ttys[j]->hardware = hardware; + ttys[j]->channel_idx = channel_idx; + ttys[j]->secondary_channel_idx = secondary_channel_idx; + ttys[j]->network = network; + ttys[j]->tty_type = tty_type; + mutex_init(&ttys[j]->ipw_tty_mutex); + + tty_register_device(ipw_tty_driver, j, NULL); + ipwireless_associate_network_tty(network, channel_idx, ttys[j]); + + if (secondary_channel_idx != -1) + ipwireless_associate_network_tty(network, + secondary_channel_idx, + ttys[j]); + if (nodesp != NULL) { + sprintf(nodesp->dev_name, "ttyIPWp%d", j); + nodesp->major = ipw_tty_driver->major; + nodesp->minor = j + ipw_tty_driver->minor_start; + } + if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j]) + report_registering(ttys[j]); + return 0; +} + +struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hardware, + struct ipw_network *network, + dev_node_t *nodes) +{ + int i, j; + + for (i = 0; i < IPWIRELESS_PCMCIA_MINOR_RANGE; i++) { + int allfree = 1; + + for (j = i; j < IPWIRELESS_PCMCIA_MINORS; + j += IPWIRELESS_PCMCIA_MINOR_RANGE) + if (ttys[j] != NULL) { + allfree = 0; + break; + } + + if (allfree) { + j = i; + + if (add_tty(&nodes[0], j, hardware, network, + IPW_CHANNEL_DIALLER, IPW_CHANNEL_RAS, + TTYTYPE_MODEM)) + return NULL; + + j += IPWIRELESS_PCMCIA_MINOR_RANGE; + if (add_tty(&nodes[1], j, hardware, network, + IPW_CHANNEL_DIALLER, -1, + TTYTYPE_MONITOR)) + return NULL; + + j += IPWIRELESS_PCMCIA_MINOR_RANGE; + if (add_tty(NULL, j, hardware, network, + IPW_CHANNEL_RAS, -1, + TTYTYPE_RAS_RAW)) + return NULL; + + nodes[0].next = &nodes[1]; + nodes[1].next = NULL; + + return ttys[i]; + } + } + return NULL; +} + +/* + * Must be called before ipwireless_network_free(). + */ +void ipwireless_tty_free(struct ipw_tty *tty) +{ + int j; + struct ipw_network *network = ttys[tty->index]->network; + + for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS; + j += IPWIRELESS_PCMCIA_MINOR_RANGE) { + struct ipw_tty *ttyj = ttys[j]; + + if (ttyj) { + mutex_lock(&ttyj->ipw_tty_mutex); + if (get_tty(j + ipw_tty_driver->minor_start) == ttyj) + report_deregistering(ttyj); + ttyj->closing = 1; + if (ttyj->linux_tty != NULL) { + mutex_unlock(&ttyj->ipw_tty_mutex); + tty_hangup(ttyj->linux_tty); + /* Wait till the tty_hangup has completed */ + flush_scheduled_work(); + mutex_lock(&ttyj->ipw_tty_mutex); + } + while (ttyj->open_count) + do_ipw_close(ttyj); + ipwireless_disassociate_network_ttys(network, + ttyj->channel_idx); + tty_unregister_device(ipw_tty_driver, j); + ttys[j] = NULL; + mutex_unlock(&ttyj->ipw_tty_mutex); + kfree(ttyj); + } + } +} + +static struct tty_operations tty_ops = { + .open = ipw_open, + .close = ipw_close, + .hangup = ipw_hangup, + .write = ipw_write, + .write_room = ipw_write_room, + .ioctl = ipw_ioctl, + .chars_in_buffer = ipw_chars_in_buffer, + .tiocmget = ipw_tiocmget, + .tiocmset = ipw_tiocmset, +}; + +int ipwireless_tty_init(void) +{ + int result; + + ipw_tty_driver = alloc_tty_driver(IPWIRELESS_PCMCIA_MINORS); + if (!ipw_tty_driver) + return -ENOMEM; + + ipw_tty_driver->owner = THIS_MODULE; + ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME; + ipw_tty_driver->name = "ttyIPWp"; + ipw_tty_driver->major = 0; + ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START; + ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; + ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL; + ipw_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + ipw_tty_driver->init_termios = tty_std_termios; + ipw_tty_driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + ipw_tty_driver->init_termios.c_ispeed = 9600; + ipw_tty_driver->init_termios.c_ospeed = 9600; + tty_set_operations(ipw_tty_driver, &tty_ops); + result = tty_register_driver(ipw_tty_driver); + if (result) { + printk(KERN_ERR IPWIRELESS_PCCARD_NAME + ": failed to register tty driver\n"); + put_tty_driver(ipw_tty_driver); + return result; + } + + return 0; +} + +void ipwireless_tty_release(void) +{ + int ret; + + ret = tty_unregister_driver(ipw_tty_driver); + put_tty_driver(ipw_tty_driver); + if (ret != 0) + printk(KERN_ERR IPWIRELESS_PCCARD_NAME + ": tty_unregister_driver failed with code %d\n", ret); +} + +int ipwireless_tty_is_modem(struct ipw_tty *tty) +{ + return tty->tty_type == TTYTYPE_MODEM; +} + +void +ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, + unsigned int channel_idx, + unsigned int control_lines, + unsigned int changed_mask) +{ + unsigned int old_control_lines = tty->control_lines; + + tty->control_lines = (tty->control_lines & ~changed_mask) + | (control_lines & changed_mask); + + /* + * If DCD is de-asserted, we close the tty so pppd can tell that we + * have gone offline. + */ + if ((old_control_lines & IPW_CONTROL_LINE_DCD) + && !(tty->control_lines & IPW_CONTROL_LINE_DCD) + && tty->linux_tty) { + tty_hangup(tty->linux_tty); + } +} + diff --git a/drivers/char/pcmcia/ipwireless/tty.h b/drivers/char/pcmcia/ipwireless/tty.h new file mode 100644 index 000000000000..b0deb9168b6b --- /dev/null +++ b/drivers/char/pcmcia/ipwireless/tty.h @@ -0,0 +1,48 @@ +/* + * IPWireless 3G PCMCIA Network Driver + * + * Original code + * by Stephen Blackheath <stephen@blacksapphire.com>, + * Ben Martel <benm@symmetric.co.nz> + * + * Copyrighted as follows: + * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) + * + * Various driver changes and rewrites, port to new kernels + * Copyright (C) 2006-2007 Jiri Kosina + * + * Misc code cleanups and updates + * Copyright (C) 2007 David Sterba + */ + +#ifndef _IPWIRELESS_CS_TTY_H_ +#define _IPWIRELESS_CS_TTY_H_ + +#include <linux/types.h> +#include <linux/sched.h> + +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/ds.h> + +struct ipw_tty; +struct ipw_network; +struct ipw_hardware; + +int ipwireless_tty_init(void); +void ipwireless_tty_release(void); + +struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hw, + struct ipw_network *net, + dev_node_t *nodes); +void ipwireless_tty_free(struct ipw_tty *tty); +void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, + unsigned int length); +int ipwireless_tty_is_modem(struct ipw_tty *tty); +void ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, + unsigned int channel_idx, + unsigned int control_lines, + unsigned int changed_mask); + +#endif diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index e0bade732376..1412d7bcdbd1 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -43,18 +43,12 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s) * We have to be cautious here. We have seen BIOSes with DMI pointers * pointing to completely the wrong place for example */ -static int __init dmi_table(u32 base, int len, int num, - void (*decode)(const struct dmi_header *)) +static void dmi_table(u8 *buf, int len, int num, + void (*decode)(const struct dmi_header *)) { - u8 *buf, *data; + u8 *data = buf; int i = 0; - buf = dmi_ioremap(base, len); - if (buf == NULL) - return -1; - - data = buf; - /* * Stop when we see all the items the table claimed to have * OR we run off the end of the table (also happens) @@ -75,7 +69,23 @@ static int __init dmi_table(u32 base, int len, int num, data += 2; i++; } - dmi_iounmap(buf, len); +} + +static u32 dmi_base; +static u16 dmi_len; +static u16 dmi_num; + +static int __init dmi_walk_early(void (*decode)(const struct dmi_header *)) +{ + u8 *buf; + + buf = dmi_ioremap(dmi_base, dmi_len); + if (buf == NULL) + return -1; + + dmi_table(buf, dmi_len, dmi_num, decode); + + dmi_iounmap(buf, dmi_len); return 0; } @@ -291,9 +301,9 @@ static int __init dmi_present(const char __iomem *p) memcpy_fromio(buf, p, 15); if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) { - u16 num = (buf[13] << 8) | buf[12]; - u16 len = (buf[7] << 8) | buf[6]; - u32 base = (buf[11] << 24) | (buf[10] << 16) | + dmi_num = (buf[13] << 8) | buf[12]; + dmi_len = (buf[7] << 8) | buf[6]; + dmi_base = (buf[11] << 24) | (buf[10] << 16) | (buf[9] << 8) | buf[8]; /* @@ -305,7 +315,7 @@ static int __init dmi_present(const char __iomem *p) buf[14] >> 4, buf[14] & 0xF); else printk(KERN_INFO "DMI present.\n"); - if (dmi_table(base,len, num, dmi_decode) == 0) + if (dmi_walk_early(dmi_decode) == 0) return 0; } return 1; @@ -489,3 +499,27 @@ int dmi_get_year(int field) return year; } + +/** + * dmi_walk - Walk the DMI table and get called back for every record + * @decode: Callback function + * + * Returns -1 when the DMI table can't be reached, 0 on success. + */ +int dmi_walk(void (*decode)(const struct dmi_header *)) +{ + u8 *buf; + + if (!dmi_available) + return -1; + + buf = ioremap(dmi_base, dmi_len); + if (buf == NULL) + return -1; + + dmi_table(buf, dmi_len, dmi_num, decode); + + iounmap(buf); + return 0; +} +EXPORT_SYMBOL_GPL(dmi_walk); diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index a0445bea9f75..410ffe4e9d80 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -433,12 +433,12 @@ config SENSORS_LM85 will be called lm85. config SENSORS_LM87 - tristate "National Semiconductor LM87" + tristate "National Semiconductor LM87 and compatibles" depends on I2C select HWMON_VID help If you say yes here you get support for National Semiconductor LM87 - sensor chips. + and Analog Devices ADM1024 sensor chips. This driver can also be built as a module. If so, the module will be called lm87. @@ -588,6 +588,16 @@ config SENSORS_SMSC47B397 This driver can also be built as a module. If so, the module will be called smsc47b397. +config SENSORS_ADS7828 + tristate "Texas Instruments ADS7828" + depends on I2C + help + If you say yes here you get support for Texas Instruments ADS7828 + 12-bit 8-channel ADC device. + + This driver can also be built as a module. If so, the module + will be called ads7828. + config SENSORS_THMC50 tristate "Texas Instruments THMC50 / Analog Devices ADM1022" depends on I2C && EXPERIMENTAL @@ -631,13 +641,13 @@ config SENSORS_VT8231 will be called vt8231. config SENSORS_W83781D - tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F" + tristate "Winbond W83781D, W83782D, W83783S, Asus AS99127F" depends on I2C select HWMON_VID help If you say yes here you get support for the Winbond W8378x series - of sensor chips: the W83781D, W83782D, W83783S and W83627HF, - and the similar Asus AS99127F. + of sensor chips: the W83781D, W83782D and W83783S, and the similar + Asus AS99127F. This driver can also be built as a module. If so, the module will be called w83781d. @@ -683,6 +693,16 @@ config SENSORS_W83L785TS This driver can also be built as a module. If so, the module will be called w83l785ts. +config SENSORS_W83L786NG + tristate "Winbond W83L786NG, W83L786NR" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the Winbond W83L786NG + and W83L786NR sensor chips. + + This driver can also be built as a module. If so, the module + will be called w83l786ng. + config SENSORS_W83627HF tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF" select HWMON_VID diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 55595f6e1aa6..824161337f1c 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o +obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o obj-$(CONFIG_SENSORS_AMS) += ams/ @@ -68,6 +69,7 @@ obj-$(CONFIG_SENSORS_VT1211) += vt1211.o obj-$(CONFIG_SENSORS_VT8231) += vt8231.o obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o +obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index d9f04ce90327..ed33fddc4dee 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -528,6 +528,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX1 Fan", 33, 2, 60, 1, 0 }, { "AUX2 Fan", 35, 2, 60, 1, 0 }, { "AUX3 Fan", 36, 2, 60, 1, 0 }, + { "AUX4 Fan", 37, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, { 0x001B, "unknown", { diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index ebdc6d7db231..b96be772e498 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -115,7 +115,6 @@ static struct i2c_driver adm1021_driver = { .driver = { .name = "adm1021", }, - .id = I2C_DRIVERID_ADM1021, .attach_adapter = adm1021_attach_adapter, .detach_client = adm1021_detach_client, }; diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index 041ecb0bdf48..e96c3725203d 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -51,6 +51,7 @@ #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/hwmon-vid.h> #include <linux/err.h> #include <linux/mutex.h> @@ -74,7 +75,7 @@ I2C_CLIENT_INSMOD_2(adm1025, ne1619); */ #define ADM1025_REG_MAN_ID 0x3E -#define ADM1025_REG_CHIP_ID 0x3F +#define ADM1025_REG_CHIP_ID 0x3F #define ADM1025_REG_CONFIG 0x40 #define ADM1025_REG_STATUS1 0x41 #define ADM1025_REG_STATUS2 0x42 @@ -92,7 +93,7 @@ I2C_CLIENT_INSMOD_2(adm1025, ne1619); * The ADM1025 uses signed 8-bit values for temperatures. */ -static int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 }; +static const int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 }; #define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192) #define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \ @@ -122,7 +123,6 @@ static struct i2c_driver adm1025_driver = { .driver = { .name = "adm1025", }, - .id = I2C_DRIVERID_ADM1025, .attach_adapter = adm1025_attach_adapter, .detach_client = adm1025_detach_client, }; @@ -153,86 +153,96 @@ struct adm1025_data { * Sysfs stuff */ -#define show_in(offset) \ -static ssize_t show_in##offset(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ - in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ - in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ - in_scale[offset])); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); -show_in(0); -show_in(1); -show_in(2); -show_in(3); -show_in(4); -show_in(5); - -#define show_temp(offset) \ -static ssize_t show_temp##offset(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ -} \ -static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \ -} \ -static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \ -}\ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp##offset, NULL); -show_temp(1); -show_temp(2); +static ssize_t +show_in(struct device *dev, struct device_attribute *attr, char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%u\n", IN_FROM_REG(data->in[index], + in_scale[index])); +} + +static ssize_t +show_in_min(struct device *dev, struct device_attribute *attr, char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[index], + in_scale[index])); +} + +static ssize_t +show_in_max(struct device *dev, struct device_attribute *attr, char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[index], + in_scale[index])); +} + +static ssize_t +show_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[index])); +} + +static ssize_t +show_temp_min(struct device *dev, struct device_attribute *attr, char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[index])); +} + +static ssize_t +show_temp_max(struct device *dev, struct device_attribute *attr, char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index])); +} + +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1025_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->in_min[index] = IN_TO_REG(val, in_scale[index]); + i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(index), + data->in_min[index]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1025_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->in_max[index] = IN_TO_REG(val, in_scale[index]); + i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(index), + data->in_max[index]); + mutex_unlock(&data->update_lock); + return count; +} #define set_in(offset) \ -static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->in_min[offset] = IN_TO_REG(val, in_scale[offset]); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(offset), \ - data->in_min[offset]); \ - mutex_unlock(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->in_max[offset] = IN_TO_REG(val, in_scale[offset]); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(offset), \ - data->in_max[offset]); \ - mutex_unlock(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \ - show_in##offset##_max, set_in##offset##_max); +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in, NULL, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \ + show_in_max, set_in_max, offset) set_in(0); set_in(1); set_in(2); @@ -240,65 +250,91 @@ set_in(3); set_in(4); set_in(5); +static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1025_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->temp_min[index] = TEMP_TO_REG(val); + i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(index), + data->temp_min[index]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1025_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->temp_max[index] = TEMP_TO_REG(val); + i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(index), + data->temp_max[index]); + mutex_unlock(&data->update_lock); + return count; +} + #define set_temp(offset) \ -static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->temp_min[offset-1] = TEMP_TO_REG(val); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(offset-1), \ - data->temp_min[offset-1]); \ - mutex_unlock(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->temp_max[offset-1] = TEMP_TO_REG(val); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(offset-1), \ - data->temp_max[offset-1]); \ - mutex_unlock(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ - show_temp##offset##_min, set_temp##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ - show_temp##offset##_max, set_temp##offset##_max); +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ + show_temp_min, set_temp_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ + show_temp_max, set_temp_max, offset - 1) set_temp(1); set_temp(2); -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t +show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1025_data *data = adm1025_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t +show_alarm(struct device *dev, struct device_attribute *attr, char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_alarm, NULL, 14); + +static ssize_t +show_vid(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1025_data *data = adm1025_update_device(dev); return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); } static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t +show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1025_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct adm1025_data *data = i2c_get_clientdata(client); + struct adm1025_data *data = dev_get_drvdata(dev); data->vrm = simple_strtoul(buf, NULL, 10); return count; } @@ -316,27 +352,35 @@ static int adm1025_attach_adapter(struct i2c_adapter *adapter) } static struct attribute *adm1025_attributes[] = { - &dev_attr_in0_input.attr, - &dev_attr_in1_input.attr, - &dev_attr_in2_input.attr, - &dev_attr_in3_input.attr, - &dev_attr_in5_input.attr, - &dev_attr_in0_min.attr, - &dev_attr_in1_min.attr, - &dev_attr_in2_min.attr, - &dev_attr_in3_min.attr, - &dev_attr_in5_min.attr, - &dev_attr_in0_max.attr, - &dev_attr_in1_max.attr, - &dev_attr_in2_max.attr, - &dev_attr_in3_max.attr, - &dev_attr_in5_max.attr, - &dev_attr_temp1_input.attr, - &dev_attr_temp2_input.attr, - &dev_attr_temp1_min.attr, - &dev_attr_temp2_min.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp2_max.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_fault.dev_attr.attr, &dev_attr_alarms.attr, &dev_attr_cpu0_vid.attr, &dev_attr_vrm.attr, @@ -347,15 +391,16 @@ static const struct attribute_group adm1025_group = { .attrs = adm1025_attributes, }; -static struct attribute *adm1025_attributes_opt[] = { - &dev_attr_in4_input.attr, - &dev_attr_in4_min.attr, - &dev_attr_in4_max.attr, +static struct attribute *adm1025_attributes_in4[] = { + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, NULL }; -static const struct attribute_group adm1025_group_opt = { - .attrs = adm1025_attributes_opt, +static const struct attribute_group adm1025_group_in4 = { + .attrs = adm1025_attributes_in4, }; /* @@ -364,7 +409,7 @@ static const struct attribute_group adm1025_group_opt = { */ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) { - struct i2c_client *new_client; + struct i2c_client *client; struct adm1025_data *data; int err = 0; const char *name = ""; @@ -378,14 +423,11 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) goto exit; } - /* The common I2C client data is placed right before the - ADM1025-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1025_driver; - new_client->flags = 0; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &adm1025_driver; /* * Now we do the remaining detection. A negative kind means that @@ -397,12 +439,12 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) * requested, so both the detection and the identification steps * are skipped. */ - config = i2c_smbus_read_byte_data(new_client, ADM1025_REG_CONFIG); + config = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG); if (kind < 0) { /* detection */ if ((config & 0x80) != 0x00 - || (i2c_smbus_read_byte_data(new_client, + || (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS1) & 0xC0) != 0x00 - || (i2c_smbus_read_byte_data(new_client, + || (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS2) & 0xBC) != 0x00) { dev_dbg(&adapter->dev, "ADM1025 detection failed at 0x%02x.\n", @@ -414,11 +456,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) if (kind <= 0) { /* identification */ u8 man_id, chip_id; - man_id = i2c_smbus_read_byte_data(new_client, - ADM1025_REG_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - ADM1025_REG_CHIP_ID); - + man_id = i2c_smbus_read_byte_data(client, ADM1025_REG_MAN_ID); + chip_id = i2c_smbus_read_byte_data(client, ADM1025_REG_CHIP_ID); + if (man_id == 0x41) { /* Analog Devices */ if ((chip_id & 0xF0) == 0x20) { /* ADM1025/ADM1025A */ kind = adm1025; @@ -446,33 +486,28 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) } /* We can fill in the remaining client fields */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; + strlcpy(client->name, name, I2C_NAME_SIZE); mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto exit_free; /* Initialize the ADM1025 chip */ - adm1025_init_client(new_client); + adm1025_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1025_group))) + if ((err = sysfs_create_group(&client->dev.kobj, &adm1025_group))) goto exit_detach; /* Pin 11 is either in4 (+12V) or VID4 */ if (!(config & 0x20)) { - if ((err = device_create_file(&new_client->dev, - &dev_attr_in4_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in4_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in4_max))) + if ((err = sysfs_create_group(&client->dev.kobj, + &adm1025_group_in4))) goto exit_remove; } - data->hwmon_dev = hwmon_device_register(&new_client->dev); + data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exit_remove; @@ -481,10 +516,10 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_remove: - sysfs_remove_group(&new_client->dev.kobj, &adm1025_group); - sysfs_remove_group(&new_client->dev.kobj, &adm1025_group_opt); + sysfs_remove_group(&client->dev.kobj, &adm1025_group); + sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4); exit_detach: - i2c_detach_client(new_client); + i2c_detach_client(client); exit_free: kfree(data); exit: @@ -540,7 +575,7 @@ static int adm1025_detach_client(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1025_group); - sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt); + sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 3e63c1486770..8002f68240c4 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -40,8 +40,8 @@ static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; /* Insmod parameters */ I2C_CLIENT_INSMOD_1(adm1026); -static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; +static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; static int gpio_output[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -49,46 +49,49 @@ static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, static int gpio_normal[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; -module_param_array(gpio_input,int,NULL,0); -MODULE_PARM_DESC(gpio_input,"List of GPIO pins (0-16) to program as inputs"); -module_param_array(gpio_output,int,NULL,0); -MODULE_PARM_DESC(gpio_output,"List of GPIO pins (0-16) to program as " +module_param_array(gpio_input, int, NULL, 0); +MODULE_PARM_DESC(gpio_input, "List of GPIO pins (0-16) to program as inputs"); +module_param_array(gpio_output, int, NULL, 0); +MODULE_PARM_DESC(gpio_output, "List of GPIO pins (0-16) to program as " "outputs"); -module_param_array(gpio_inverted,int,NULL,0); -MODULE_PARM_DESC(gpio_inverted,"List of GPIO pins (0-16) to program as " +module_param_array(gpio_inverted, int, NULL, 0); +MODULE_PARM_DESC(gpio_inverted, "List of GPIO pins (0-16) to program as " "inverted"); -module_param_array(gpio_normal,int,NULL,0); -MODULE_PARM_DESC(gpio_normal,"List of GPIO pins (0-16) to program as " +module_param_array(gpio_normal, int, NULL, 0); +MODULE_PARM_DESC(gpio_normal, "List of GPIO pins (0-16) to program as " "normal/non-inverted"); -module_param_array(gpio_fan,int,NULL,0); -MODULE_PARM_DESC(gpio_fan,"List of GPIO pins (0-7) to program as fan tachs"); +module_param_array(gpio_fan, int, NULL, 0); +MODULE_PARM_DESC(gpio_fan, "List of GPIO pins (0-7) to program as fan tachs"); /* Many ADM1026 constants specified below */ /* The ADM1026 registers */ -#define ADM1026_REG_CONFIG1 0x00 -#define CFG1_MONITOR 0x01 -#define CFG1_INT_ENABLE 0x02 -#define CFG1_INT_CLEAR 0x04 -#define CFG1_AIN8_9 0x08 -#define CFG1_THERM_HOT 0x10 -#define CFG1_DAC_AFC 0x20 -#define CFG1_PWM_AFC 0x40 -#define CFG1_RESET 0x80 -#define ADM1026_REG_CONFIG2 0x01 +#define ADM1026_REG_CONFIG1 0x00 +#define CFG1_MONITOR 0x01 +#define CFG1_INT_ENABLE 0x02 +#define CFG1_INT_CLEAR 0x04 +#define CFG1_AIN8_9 0x08 +#define CFG1_THERM_HOT 0x10 +#define CFG1_DAC_AFC 0x20 +#define CFG1_PWM_AFC 0x40 +#define CFG1_RESET 0x80 + +#define ADM1026_REG_CONFIG2 0x01 /* CONFIG2 controls FAN0/GPIO0 through FAN7/GPIO7 */ -#define ADM1026_REG_CONFIG3 0x07 -#define CFG3_GPIO16_ENABLE 0x01 -#define CFG3_CI_CLEAR 0x02 -#define CFG3_VREF_250 0x04 -#define CFG3_GPIO16_DIR 0x40 -#define CFG3_GPIO16_POL 0x80 -#define ADM1026_REG_E2CONFIG 0x13 -#define E2CFG_READ 0x01 -#define E2CFG_WRITE 0x02 -#define E2CFG_ERASE 0x04 -#define E2CFG_ROM 0x08 -#define E2CFG_CLK_EXT 0x80 + +#define ADM1026_REG_CONFIG3 0x07 +#define CFG3_GPIO16_ENABLE 0x01 +#define CFG3_CI_CLEAR 0x02 +#define CFG3_VREF_250 0x04 +#define CFG3_GPIO16_DIR 0x40 +#define CFG3_GPIO16_POL 0x80 + +#define ADM1026_REG_E2CONFIG 0x13 +#define E2CFG_READ 0x01 +#define E2CFG_WRITE 0x02 +#define E2CFG_ERASE 0x04 +#define E2CFG_ROM 0x08 +#define E2CFG_CLK_EXT 0x80 /* There are 10 general analog inputs and 7 dedicated inputs * They are: @@ -129,48 +132,48 @@ static u16 ADM1026_REG_TEMP_TMIN[] = { 0x10, 0x11, 0x12 }; static u16 ADM1026_REG_TEMP_THERM[] = { 0x0d, 0x0e, 0x0f }; static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f }; -#define ADM1026_REG_FAN(nr) (0x38 + (nr)) -#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr)) -#define ADM1026_REG_FAN_DIV_0_3 0x02 -#define ADM1026_REG_FAN_DIV_4_7 0x03 +#define ADM1026_REG_FAN(nr) (0x38 + (nr)) +#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr)) +#define ADM1026_REG_FAN_DIV_0_3 0x02 +#define ADM1026_REG_FAN_DIV_4_7 0x03 -#define ADM1026_REG_DAC 0x04 -#define ADM1026_REG_PWM 0x05 +#define ADM1026_REG_DAC 0x04 +#define ADM1026_REG_PWM 0x05 -#define ADM1026_REG_GPIO_CFG_0_3 0x08 -#define ADM1026_REG_GPIO_CFG_4_7 0x09 -#define ADM1026_REG_GPIO_CFG_8_11 0x0a -#define ADM1026_REG_GPIO_CFG_12_15 0x0b +#define ADM1026_REG_GPIO_CFG_0_3 0x08 +#define ADM1026_REG_GPIO_CFG_4_7 0x09 +#define ADM1026_REG_GPIO_CFG_8_11 0x0a +#define ADM1026_REG_GPIO_CFG_12_15 0x0b /* CFG_16 in REG_CFG3 */ -#define ADM1026_REG_GPIO_STATUS_0_7 0x24 -#define ADM1026_REG_GPIO_STATUS_8_15 0x25 +#define ADM1026_REG_GPIO_STATUS_0_7 0x24 +#define ADM1026_REG_GPIO_STATUS_8_15 0x25 /* STATUS_16 in REG_STATUS4 */ -#define ADM1026_REG_GPIO_MASK_0_7 0x1c -#define ADM1026_REG_GPIO_MASK_8_15 0x1d +#define ADM1026_REG_GPIO_MASK_0_7 0x1c +#define ADM1026_REG_GPIO_MASK_8_15 0x1d /* MASK_16 in REG_MASK4 */ -#define ADM1026_REG_COMPANY 0x16 -#define ADM1026_REG_VERSTEP 0x17 +#define ADM1026_REG_COMPANY 0x16 +#define ADM1026_REG_VERSTEP 0x17 /* These are the recognized values for the above regs */ -#define ADM1026_COMPANY_ANALOG_DEV 0x41 -#define ADM1026_VERSTEP_GENERIC 0x40 -#define ADM1026_VERSTEP_ADM1026 0x44 +#define ADM1026_COMPANY_ANALOG_DEV 0x41 +#define ADM1026_VERSTEP_GENERIC 0x40 +#define ADM1026_VERSTEP_ADM1026 0x44 -#define ADM1026_REG_MASK1 0x18 -#define ADM1026_REG_MASK2 0x19 -#define ADM1026_REG_MASK3 0x1a -#define ADM1026_REG_MASK4 0x1b +#define ADM1026_REG_MASK1 0x18 +#define ADM1026_REG_MASK2 0x19 +#define ADM1026_REG_MASK3 0x1a +#define ADM1026_REG_MASK4 0x1b -#define ADM1026_REG_STATUS1 0x20 -#define ADM1026_REG_STATUS2 0x21 -#define ADM1026_REG_STATUS3 0x22 -#define ADM1026_REG_STATUS4 0x23 +#define ADM1026_REG_STATUS1 0x20 +#define ADM1026_REG_STATUS2 0x21 +#define ADM1026_REG_STATUS3 0x22 +#define ADM1026_REG_STATUS4 0x23 #define ADM1026_FAN_ACTIVATION_TEMP_HYST -6 -#define ADM1026_FAN_CONTROL_TEMP_RANGE 20 -#define ADM1026_PWM_MAX 255 +#define ADM1026_FAN_CONTROL_TEMP_RANGE 20 +#define ADM1026_PWM_MAX 255 -/* Conversions. Rounding and limit checking is only done on the TO_REG +/* Conversions. Rounding and limit checking is only done on the TO_REG * variants. Note that you should be a bit careful with which arguments * these macros are called: arguments may be evaluated more than once. */ @@ -186,52 +189,49 @@ static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f }; * The values in this table are based on Table II, page 15 of the * datasheet. */ -static int adm1026_scaling[] = { /* .001 Volts */ - 2250, 2250, 2250, 2250, 2250, 2250, - 1875, 1875, 1875, 1875, 3000, 3330, +static int adm1026_scaling[] = { /* .001 Volts */ + 2250, 2250, 2250, 2250, 2250, 2250, + 1875, 1875, 1875, 1875, 3000, 3330, 3330, 4995, 2250, 12000, 13875 }; #define NEG12_OFFSET 16000 -#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) -#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,adm1026_scaling[n],192),\ - 0,255)) -#define INS_FROM_REG(n,val) (SCALE(val,192,adm1026_scaling[n])) +#define SCALE(val, from, to) (((val)*(to) + ((from)/2))/(from)) +#define INS_TO_REG(n, val) (SENSORS_LIMIT(SCALE(val, adm1026_scaling[n], 192),\ + 0, 255)) +#define INS_FROM_REG(n, val) (SCALE(val, 192, adm1026_scaling[n])) /* FAN speed is measured using 22.5kHz clock and counts for 2 pulses * and we assume a 2 pulse-per-rev fan tach signal * 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000 */ -#define FAN_TO_REG(val,div) ((val)<=0 ? 0xff : SENSORS_LIMIT(1350000/((val)*\ - (div)),1,254)) -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==0xff ? 0 : 1350000/((val)*\ - (div))) +#define FAN_TO_REG(val, div) ((val) <= 0 ? 0xff : \ + SENSORS_LIMIT(1350000/((val)*(div)), 1, 254)) +#define FAN_FROM_REG(val, div) ((val) == 0 ? -1:(val) == 0xff ? 0 : \ + 1350000/((val)*(div))) #define DIV_FROM_REG(val) (1<<(val)) -#define DIV_TO_REG(val) ((val)>=8 ? 3 : (val)>=4 ? 2 : (val)>=2 ? 1 : 0) +#define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0) /* Temperature is reported in 1 degC increments */ #define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ - -127,127)) + -127, 127)) #define TEMP_FROM_REG(val) ((val) * 1000) #define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ - -127,127)) + -127, 127)) #define OFFSET_FROM_REG(val) ((val) * 1000) -#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) +#define PWM_TO_REG(val) (SENSORS_LIMIT(val, 0, 255)) #define PWM_FROM_REG(val) (val) #define PWM_MIN_TO_REG(val) ((val) & 0xf0) #define PWM_MIN_FROM_REG(val) (((val) & 0xf0) + ((val) >> 4)) -/* Analog output is a voltage, and scaled to millivolts. The datasheet - * indicates that the DAC could be used to drive the fans, but in our +/* Analog output is a voltage, and scaled to millivolts. The datasheet + * indicates that the DAC could be used to drive the fans, but in our * example board (Arima HDAMA) it isn't connected to the fans at all. */ -#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val)*255)+500)/2500),0,255)) +#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val)*255)+500)/2500), 0, 255)) #define DAC_FROM_REG(val) (((val)*2500)/255) -/* Typically used with systems using a v9.1 VRM spec ? */ -#define ADM1026_INIT_VRM 91 - /* Chip sampling rates * * Some sensors are not updated more frequently than once per second @@ -243,8 +243,8 @@ static int adm1026_scaling[] = { /* .001 Volts */ * So, we keep the config data up to date in the cache * when it is written and only sample it once every 5 *minutes* */ -#define ADM1026_DATA_INTERVAL (1 * HZ) -#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ) +#define ADM1026_DATA_INTERVAL (1 * HZ) +#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ) /* We allow for multiple chips in a single system. * @@ -261,37 +261,36 @@ struct pwm_data { struct adm1026_data { struct i2c_client client; struct device *hwmon_dev; - enum chips type; struct mutex update_lock; int valid; /* !=0 if following fields are valid */ unsigned long last_reading; /* In jiffies */ unsigned long last_config; /* In jiffies */ - u8 in[17]; /* Register value */ - u8 in_max[17]; /* Register value */ - u8 in_min[17]; /* Register value */ - s8 temp[3]; /* Register value */ - s8 temp_min[3]; /* Register value */ - s8 temp_max[3]; /* Register value */ - s8 temp_tmin[3]; /* Register value */ - s8 temp_crit[3]; /* Register value */ - s8 temp_offset[3]; /* Register value */ - u8 fan[8]; /* Register value */ - u8 fan_min[8]; /* Register value */ - u8 fan_div[8]; /* Decoded value */ - struct pwm_data pwm1; /* Pwm control values */ - int vid; /* Decoded value */ - u8 vrm; /* VRM version */ + u8 in[17]; /* Register value */ + u8 in_max[17]; /* Register value */ + u8 in_min[17]; /* Register value */ + s8 temp[3]; /* Register value */ + s8 temp_min[3]; /* Register value */ + s8 temp_max[3]; /* Register value */ + s8 temp_tmin[3]; /* Register value */ + s8 temp_crit[3]; /* Register value */ + s8 temp_offset[3]; /* Register value */ + u8 fan[8]; /* Register value */ + u8 fan_min[8]; /* Register value */ + u8 fan_div[8]; /* Decoded value */ + struct pwm_data pwm1; /* Pwm control values */ + int vid; /* Decoded value */ + u8 vrm; /* VRM version */ u8 analog_out; /* Register value (DAC) */ - long alarms; /* Register encoding, combined */ - long alarm_mask; /* Register encoding, combined */ - long gpio; /* Register encoding, combined */ - long gpio_mask; /* Register encoding, combined */ - u8 gpio_config[17]; /* Decoded value */ - u8 config1; /* Register value */ - u8 config2; /* Register value */ - u8 config3; /* Register value */ + long alarms; /* Register encoding, combined */ + long alarm_mask; /* Register encoding, combined */ + long gpio; /* Register encoding, combined */ + long gpio_mask; /* Register encoding, combined */ + u8 gpio_config[17]; /* Decoded value */ + u8 config1; /* Register value */ + u8 config2; /* Register value */ + u8 config3; /* Register value */ }; static int adm1026_attach_adapter(struct i2c_adapter *adapter); @@ -301,7 +300,7 @@ static int adm1026_detach_client(struct i2c_client *client); static int adm1026_read_value(struct i2c_client *client, u8 reg); static int adm1026_write_value(struct i2c_client *client, u8 reg, int value); static void adm1026_print_gpio(struct i2c_client *client); -static void adm1026_fixup_gpio(struct i2c_client *client); +static void adm1026_fixup_gpio(struct i2c_client *client); static struct adm1026_data *adm1026_update_device(struct device *dev); static void adm1026_init_client(struct i2c_client *client); @@ -311,7 +310,7 @@ static struct i2c_driver adm1026_driver = { .name = "adm1026", }, .attach_adapter = adm1026_attach_adapter, - .detach_client = adm1026_detach_client, + .detach_client = adm1026_detach_client, }; static int adm1026_attach_adapter(struct i2c_adapter *adapter) @@ -355,7 +354,7 @@ static void adm1026_init_client(struct i2c_client *client) int value, i; struct adm1026_data *data = i2c_get_clientdata(client); - dev_dbg(&client->dev, "Initializing device\n"); + dev_dbg(&client->dev, "Initializing device\n"); /* Read chip config */ data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1); data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2); @@ -384,7 +383,6 @@ static void adm1026_init_client(struct i2c_client *client) "and temp limits enabled.\n"); } - value = data->config3; if (data->config3 & CFG3_GPIO16_ENABLE) { dev_dbg(&client->dev, "GPIO16 enabled. THERM " "pin disabled.\n"); @@ -426,10 +424,10 @@ static void adm1026_init_client(struct i2c_client *client) * configured, we don't want to mess with them. * If they weren't, the default is 100% PWM, no * control and will suffice until 'sensors -s' - * can be run by the user. We DO set the default + * can be run by the user. We DO set the default * value for pwm1.auto_pwm_min to its maximum * so that enabling automatic pwm fan control - * without first setting a value for pwm1.auto_pwm_min + * without first setting a value for pwm1.auto_pwm_min * will not result in potentially dangerous fan speed decrease. */ data->pwm1.auto_pwm_min=255; @@ -453,7 +451,7 @@ static void adm1026_init_client(struct i2c_client *client) static void adm1026_print_gpio(struct i2c_client *client) { struct adm1026_data *data = i2c_get_clientdata(client); - int i; + int i; dev_dbg(&client->dev, "GPIO config is:"); for (i = 0;i <= 7;++i) { @@ -477,7 +475,7 @@ static void adm1026_print_gpio(struct i2c_client *client) data->gpio_config[16] & 0x02 ? "" : "!", data->gpio_config[16] & 0x01 ? "OUT" : "IN"); } else { - /* GPIO16 is THERM */ + /* GPIO16 is THERM */ dev_dbg(&client->dev, "\tTHERM\n"); } } @@ -485,8 +483,8 @@ static void adm1026_print_gpio(struct i2c_client *client) static void adm1026_fixup_gpio(struct i2c_client *client) { struct adm1026_data *data = i2c_get_clientdata(client); - int i; - int value; + int i; + int value; /* Make the changes requested. */ /* We may need to unlock/stop monitoring or soft-reset the @@ -516,14 +514,14 @@ static void adm1026_fixup_gpio(struct i2c_client *client) } } - /* Inverted */ + /* Inverted */ for (i = 0;i <= 16;++i) { if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16) { data->gpio_config[gpio_inverted[i]] &= ~ 0x02; } } - /* Normal overrides inverted */ + /* Normal overrides inverted */ for (i = 0;i <= 16;++i) { if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16) { data->gpio_config[gpio_normal[i]] |= 0x02; @@ -569,7 +567,7 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) if (!data->valid || time_after(jiffies, data->last_reading + ADM1026_DATA_INTERVAL)) { /* Things that change quickly */ - dev_dbg(&client->dev,"Reading sensor values\n"); + dev_dbg(&client->dev, "Reading sensor values\n"); for (i = 0;i <= 16;++i) { data->in[i] = adm1026_read_value(client, ADM1026_REG_IN[i]); @@ -582,18 +580,18 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) for (i = 0;i <= 2;++i) { /* NOTE: temp[] is s8 and we assume 2's complement - * "conversion" in the assignment */ + * "conversion" in the assignment */ data->temp[i] = adm1026_read_value(client, ADM1026_REG_TEMP[i]); } - data->pwm1.pwm = adm1026_read_value(client, + data->pwm1.pwm = adm1026_read_value(client, ADM1026_REG_PWM); - data->analog_out = adm1026_read_value(client, + data->analog_out = adm1026_read_value(client, ADM1026_REG_DAC); /* GPIO16 is MSbit of alarms, move it to gpio */ alarms = adm1026_read_value(client, ADM1026_REG_STATUS4); - gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */ + gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */ alarms &= 0x7f; alarms <<= 8; alarms |= adm1026_read_value(client, ADM1026_REG_STATUS3); @@ -604,24 +602,24 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) data->alarms = alarms; /* Read the GPIO values */ - gpio |= adm1026_read_value(client, + gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_STATUS_8_15); gpio <<= 8; - gpio |= adm1026_read_value(client, + gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_STATUS_0_7); data->gpio = gpio; data->last_reading = jiffies; - }; /* last_reading */ + }; /* last_reading */ if (!data->valid || time_after(jiffies, data->last_config + ADM1026_CONFIG_INTERVAL)) { /* Things that don't change often */ dev_dbg(&client->dev, "Reading config values\n"); for (i = 0;i <= 16;++i) { - data->in_min[i] = adm1026_read_value(client, + data->in_min[i] = adm1026_read_value(client, ADM1026_REG_IN_MIN[i]); - data->in_max[i] = adm1026_read_value(client, + data->in_max[i] = adm1026_read_value(client, ADM1026_REG_IN_MAX[i]); } @@ -629,32 +627,32 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) | (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8); for (i = 0;i <= 7;++i) { - data->fan_min[i] = adm1026_read_value(client, + data->fan_min[i] = adm1026_read_value(client, ADM1026_REG_FAN_MIN(i)); data->fan_div[i] = DIV_FROM_REG(value & 0x03); value >>= 2; } for (i = 0; i <= 2; ++i) { - /* NOTE: temp_xxx[] are s8 and we assume 2's + /* NOTE: temp_xxx[] are s8 and we assume 2's * complement "conversion" in the assignment */ - data->temp_min[i] = adm1026_read_value(client, + data->temp_min[i] = adm1026_read_value(client, ADM1026_REG_TEMP_MIN[i]); - data->temp_max[i] = adm1026_read_value(client, + data->temp_max[i] = adm1026_read_value(client, ADM1026_REG_TEMP_MAX[i]); - data->temp_tmin[i] = adm1026_read_value(client, + data->temp_tmin[i] = adm1026_read_value(client, ADM1026_REG_TEMP_TMIN[i]); - data->temp_crit[i] = adm1026_read_value(client, + data->temp_crit[i] = adm1026_read_value(client, ADM1026_REG_TEMP_THERM[i]); - data->temp_offset[i] = adm1026_read_value(client, + data->temp_offset[i] = adm1026_read_value(client, ADM1026_REG_TEMP_OFFSET[i]); } /* Read the STATUS/alarm masks */ - alarms = adm1026_read_value(client, ADM1026_REG_MASK4); - gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */ - alarms = (alarms & 0x7f) << 8; + alarms = adm1026_read_value(client, ADM1026_REG_MASK4); + gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */ + alarms = (alarms & 0x7f) << 8; alarms |= adm1026_read_value(client, ADM1026_REG_MASK3); alarms <<= 8; alarms |= adm1026_read_value(client, ADM1026_REG_MASK2); @@ -663,24 +661,24 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) data->alarm_mask = alarms; /* Read the GPIO values */ - gpio |= adm1026_read_value(client, + gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_8_15); gpio <<= 8; gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_0_7); data->gpio_mask = gpio; /* Read various values from CONFIG1 */ - data->config1 = adm1026_read_value(client, + data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1); if (data->config1 & CFG1_PWM_AFC) { data->pwm1.enable = 2; - data->pwm1.auto_pwm_min = + data->pwm1.auto_pwm_min = PWM_MIN_FROM_REG(data->pwm1.pwm); } /* Read the GPIO config */ - data->config2 = adm1026_read_value(client, + data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2); - data->config3 = adm1026_read_value(client, + data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3); data->gpio_config[16] = (data->config3 >> 6) & 0x03; @@ -695,7 +693,7 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) } data->last_config = jiffies; - }; /* last_config */ + }; /* last_config */ dev_dbg(&client->dev, "Setting VID from GPIO11-15.\n"); data->vid = (data->gpio >> 11) & 0x1f; @@ -710,15 +708,15 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in[nr])); + return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in[nr])); } static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, char *buf) { struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr])); + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in_min[nr])); } static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -733,7 +731,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, data->in_min[nr] = INS_TO_REG(nr, val); adm1026_write_value(client, ADM1026_REG_IN_MIN[nr], data->in_min[nr]); mutex_unlock(&data->update_lock); - return count; + return count; } static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, char *buf) @@ -741,7 +739,7 @@ static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr])); + return sprintf(buf, "%d\n", INS_FROM_REG(nr, data->in_max[nr])); } static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -788,13 +786,13 @@ in_reg(15); static ssize_t show_in16(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in[16]) - + return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in[16]) - NEG12_OFFSET); } static ssize_t show_in16_min(struct device *dev, struct device_attribute *attr, char *buf) { - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_min[16]) + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in_min[16]) - NEG12_OFFSET); } static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -807,12 +805,12 @@ static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, c data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET); adm1026_write_value(client, ADM1026_REG_IN_MIN[16], data->in_min[16]); mutex_unlock(&data->update_lock); - return count; + return count; } static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_max[16]) + return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in_max[16]) - NEG12_OFFSET); } static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -843,7 +841,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], data->fan_div[nr])); } static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, @@ -852,7 +850,7 @@ static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], data->fan_div[nr])); } static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, @@ -872,10 +870,10 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, return count; } -#define fan_offset(offset) \ -static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \ - offset - 1); \ -static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ +#define fan_offset(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \ + offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ show_fan_min, set_fan_min, offset - 1); fan_offset(1); @@ -892,8 +890,8 @@ static void fixup_fan_min(struct device *dev, int fan, int old_div) { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int new_min; - int new_div = data->fan_div[fan]; + int new_min; + int new_div = data->fan_div[fan]; /* 0 and 0xff are special. Don't adjust them */ if (data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff) { @@ -913,7 +911,7 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", data->fan_div[nr]); + return sprintf(buf, "%d\n", data->fan_div[nr]); } static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -922,10 +920,10 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val,orig_div,new_div,shift; + int val, orig_div, new_div, shift; val = simple_strtol(buf, NULL, 10); - new_div = DIV_TO_REG(val); + new_div = DIV_TO_REG(val); if (new_div == 0) { return -EINVAL; } @@ -946,14 +944,14 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, } if (data->fan_div[nr] != orig_div) { - fixup_fan_min(dev,nr,orig_div); + fixup_fan_min(dev, nr, orig_div); } mutex_unlock(&data->update_lock); return count; } -#define fan_offset_div(offset) \ -static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ +#define fan_offset_div(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ show_fan_div, set_fan_div, offset - 1); fan_offset_div(1); @@ -972,7 +970,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp[nr])); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); } static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, char *buf) @@ -980,7 +978,7 @@ static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr])); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr])); } static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1004,7 +1002,7 @@ static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr])); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr])); } static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1024,7 +1022,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, } #define temp_reg(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \ +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \ NULL, offset - 1); \ static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ show_temp_min, set_temp_min, offset - 1); \ @@ -1042,7 +1040,7 @@ static ssize_t show_temp_offset(struct device *dev, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_offset[nr])); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_offset[nr])); } static ssize_t set_temp_offset(struct device *dev, struct device_attribute *attr, const char *buf, @@ -1076,7 +1074,7 @@ static ssize_t show_temp_auto_point1_temp_hyst(struct device *dev, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG( + return sprintf(buf, "%d\n", TEMP_FROM_REG( ADM1026_FAN_ACTIVATION_TEMP_HYST + data->temp_tmin[nr])); } static ssize_t show_temp_auto_point2_temp(struct device *dev, @@ -1085,7 +1083,7 @@ static ssize_t show_temp_auto_point2_temp(struct device *dev, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr] + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_tmin[nr] + ADM1026_FAN_CONTROL_TEMP_RANGE)); } static ssize_t show_temp_auto_point1_temp(struct device *dev, @@ -1094,7 +1092,7 @@ static ssize_t show_temp_auto_point1_temp(struct device *dev, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr])); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_tmin[nr])); } static ssize_t set_temp_auto_point1_temp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1113,13 +1111,13 @@ static ssize_t set_temp_auto_point1_temp(struct device *dev, return count; } -#define temp_auto_point(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp, S_IRUGO | S_IWUSR, \ - show_temp_auto_point1_temp, set_temp_auto_point1_temp, \ - offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp_hyst, S_IRUGO, \ - show_temp_auto_point1_temp_hyst, NULL, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_auto_point2_temp, S_IRUGO, \ +#define temp_auto_point(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp, \ + S_IRUGO | S_IWUSR, show_temp_auto_point1_temp, \ + set_temp_auto_point1_temp, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp_hyst, S_IRUGO,\ + show_temp_auto_point1_temp_hyst, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_point2_temp, S_IRUGO, \ show_temp_auto_point2_temp, NULL, offset - 1); temp_auto_point(1); @@ -1130,7 +1128,7 @@ static ssize_t show_temp_crit_enable(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", (data->config1 & CFG1_THERM_HOT) >> 4); + return sprintf(buf, "%d\n", (data->config1 & CFG1_THERM_HOT) >> 4); } static ssize_t set_temp_crit_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1142,7 +1140,7 @@ static ssize_t set_temp_crit_enable(struct device *dev, if ((val == 1) || (val==0)) { mutex_lock(&data->update_lock); data->config1 = (data->config1 & ~CFG1_THERM_HOT) | (val << 4); - adm1026_write_value(client, ADM1026_REG_CONFIG1, + adm1026_write_value(client, ADM1026_REG_CONFIG1, data->config1); mutex_unlock(&data->update_lock); } @@ -1163,7 +1161,7 @@ static ssize_t show_temp_crit(struct device *dev, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_crit[nr])); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr])); } static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1193,7 +1191,7 @@ temp_crit_reg(3); static ssize_t show_analog_out_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", DAC_FROM_REG(data->analog_out)); + return sprintf(buf, "%d\n", DAC_FROM_REG(data->analog_out)); } static ssize_t set_analog_out_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1209,26 +1207,25 @@ static ssize_t set_analog_out_reg(struct device *dev, struct device_attribute *a return count; } -static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg, +static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg, set_analog_out_reg); static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm)); + return sprintf(buf, "%d\n", vid_from_reg(data->vid & 0x3f, data->vrm)); } static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = dev_get_drvdata(dev); - return sprintf(buf,"%d\n", data->vrm); + return sprintf(buf, "%d\n", data->vrm); } static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); + struct adm1026_data *data = dev_get_drvdata(dev); data->vrm = simple_strtol(buf, NULL, 10); return count; @@ -1239,15 +1236,52 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf, "%ld\n", (long) (data->alarms)); + return sprintf(buf, "%ld\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + int bitnr = to_sensor_dev_attr(attr)->index; + return sprintf(buf, "%ld\n", (data->alarms >> bitnr) & 1); +} + +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in11_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(in14_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(in15_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(in16_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 12); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 13); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 14); +static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 15); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 16); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 17); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 18); +static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 19); +static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 20); +static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 21); +static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_alarm, NULL, 22); +static SENSOR_DEVICE_ATTR(fan8_alarm, S_IRUGO, show_alarm, NULL, 23); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 24); +static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 25); +static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 26); + static ssize_t show_alarm_mask(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%ld\n", data->alarm_mask); + return sprintf(buf, "%ld\n", data->alarm_mask); } static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1283,7 +1317,7 @@ static DEVICE_ATTR(alarm_mask, S_IRUGO | S_IWUSR, show_alarm_mask, static ssize_t show_gpio(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%ld\n", data->gpio); + return sprintf(buf, "%ld\n", data->gpio); } static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1291,16 +1325,16 @@ static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, const struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); - long gpio; + long gpio; mutex_lock(&data->update_lock); data->gpio = val & 0x1ffff; gpio = data->gpio; - adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_0_7,gpio & 0xff); + adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_0_7, gpio & 0xff); gpio >>= 8; - adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_8_15,gpio & 0xff); + adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_8_15, gpio & 0xff); gpio = ((gpio >> 1) & 0x80) | (data->alarms >> 24 & 0x7f); - adm1026_write_value(client, ADM1026_REG_STATUS4,gpio & 0xff); + adm1026_write_value(client, ADM1026_REG_STATUS4, gpio & 0xff); mutex_unlock(&data->update_lock); return count; } @@ -1311,7 +1345,7 @@ static DEVICE_ATTR(gpio, S_IRUGO | S_IWUSR, show_gpio, set_gpio); static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%ld\n", data->gpio_mask); + return sprintf(buf, "%ld\n", data->gpio_mask); } static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1319,16 +1353,16 @@ static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); - long mask; + long mask; mutex_lock(&data->update_lock); data->gpio_mask = val & 0x1ffff; mask = data->gpio_mask; - adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7,mask & 0xff); + adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7, mask & 0xff); mask >>= 8; - adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15,mask & 0xff); + adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15, mask & 0xff); mask = ((mask >> 1) & 0x80) | (data->alarm_mask >> 24 & 0x7f); - adm1026_write_value(client, ADM1026_REG_MASK1,mask & 0xff); + adm1026_write_value(client, ADM1026_REG_MASK1, mask & 0xff); mutex_unlock(&data->update_lock); return count; } @@ -1338,7 +1372,7 @@ static DEVICE_ATTR(gpio_mask, S_IRUGO | S_IWUSR, show_gpio_mask, set_gpio_mask); static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm1.pwm)); + return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm1.pwm)); } static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1359,7 +1393,7 @@ static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, co static ssize_t show_auto_pwm_min(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", data->pwm1.auto_pwm_min); + return sprintf(buf, "%d\n", data->pwm1.auto_pwm_min); } static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1369,10 +1403,10 @@ static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *att int val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); - data->pwm1.auto_pwm_min = SENSORS_LIMIT(val,0,255); + data->pwm1.auto_pwm_min = SENSORS_LIMIT(val, 0, 255); if (data->pwm1.enable == 2) { /* apply immediately */ data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) | - PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); + PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); } mutex_unlock(&data->update_lock); @@ -1380,12 +1414,12 @@ static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *att } static ssize_t show_auto_pwm_max(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf,"%d\n", ADM1026_PWM_MAX); + return sprintf(buf, "%d\n", ADM1026_PWM_MAX); } static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", data->pwm1.enable); + return sprintf(buf, "%d\n", data->pwm1.enable); } static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1393,7 +1427,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); - int old_enable; + int old_enable; if ((val >= 0) && (val < 3)) { mutex_lock(&data->update_lock); @@ -1403,15 +1437,15 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, | ((val == 2) ? CFG1_PWM_AFC : 0); adm1026_write_value(client, ADM1026_REG_CONFIG1, data->config1); - if (val == 2) { /* apply pwm1_auto_pwm_min to pwm1 */ + if (val == 2) { /* apply pwm1_auto_pwm_min to pwm1 */ data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) | - PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); - adm1026_write_value(client, ADM1026_REG_PWM, + PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); + adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); } else if (!((old_enable == 1) && (val == 1))) { /* set pwm to safe value */ data->pwm1.pwm = 255; - adm1026_write_value(client, ADM1026_REG_PWM, + adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); } mutex_unlock(&data->update_lock); @@ -1420,20 +1454,20 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, } /* enable PWM fan control */ -static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); -static DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); -static DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); -static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, +static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); +static DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); +static DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); +static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, set_pwm_enable); -static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable, +static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable, set_pwm_enable); -static DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable, +static DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable, set_pwm_enable); -static DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO | S_IWUSR, show_auto_pwm_min, set_auto_pwm_min); -static DEVICE_ATTR(temp2_auto_point1_pwm, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(temp2_auto_point1_pwm, S_IRUGO | S_IWUSR, show_auto_pwm_min, set_auto_pwm_min); -static DEVICE_ATTR(temp3_auto_point1_pwm, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(temp3_auto_point1_pwm, S_IRUGO | S_IWUSR, show_auto_pwm_min, set_auto_pwm_min); static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); @@ -1444,105 +1478,115 @@ static struct attribute *adm1026_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in0_max.dev_attr.attr, &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in1_max.dev_attr.attr, &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, &sensor_dev_attr_in2_max.dev_attr.attr, &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, &sensor_dev_attr_in3_input.dev_attr.attr, &sensor_dev_attr_in3_max.dev_attr.attr, &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, &sensor_dev_attr_in4_input.dev_attr.attr, &sensor_dev_attr_in4_max.dev_attr.attr, &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, &sensor_dev_attr_in5_input.dev_attr.attr, &sensor_dev_attr_in5_max.dev_attr.attr, &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, &sensor_dev_attr_in6_input.dev_attr.attr, &sensor_dev_attr_in6_max.dev_attr.attr, &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, &sensor_dev_attr_in7_input.dev_attr.attr, &sensor_dev_attr_in7_max.dev_attr.attr, &sensor_dev_attr_in7_min.dev_attr.attr, - &sensor_dev_attr_in8_input.dev_attr.attr, - &sensor_dev_attr_in8_max.dev_attr.attr, - &sensor_dev_attr_in8_min.dev_attr.attr, - &sensor_dev_attr_in9_input.dev_attr.attr, - &sensor_dev_attr_in9_max.dev_attr.attr, - &sensor_dev_attr_in9_min.dev_attr.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, &sensor_dev_attr_in10_input.dev_attr.attr, &sensor_dev_attr_in10_max.dev_attr.attr, &sensor_dev_attr_in10_min.dev_attr.attr, + &sensor_dev_attr_in10_alarm.dev_attr.attr, &sensor_dev_attr_in11_input.dev_attr.attr, &sensor_dev_attr_in11_max.dev_attr.attr, &sensor_dev_attr_in11_min.dev_attr.attr, + &sensor_dev_attr_in11_alarm.dev_attr.attr, &sensor_dev_attr_in12_input.dev_attr.attr, &sensor_dev_attr_in12_max.dev_attr.attr, &sensor_dev_attr_in12_min.dev_attr.attr, + &sensor_dev_attr_in12_alarm.dev_attr.attr, &sensor_dev_attr_in13_input.dev_attr.attr, &sensor_dev_attr_in13_max.dev_attr.attr, &sensor_dev_attr_in13_min.dev_attr.attr, + &sensor_dev_attr_in13_alarm.dev_attr.attr, &sensor_dev_attr_in14_input.dev_attr.attr, &sensor_dev_attr_in14_max.dev_attr.attr, &sensor_dev_attr_in14_min.dev_attr.attr, + &sensor_dev_attr_in14_alarm.dev_attr.attr, &sensor_dev_attr_in15_input.dev_attr.attr, &sensor_dev_attr_in15_max.dev_attr.attr, &sensor_dev_attr_in15_min.dev_attr.attr, + &sensor_dev_attr_in15_alarm.dev_attr.attr, &sensor_dev_attr_in16_input.dev_attr.attr, &sensor_dev_attr_in16_max.dev_attr.attr, &sensor_dev_attr_in16_min.dev_attr.attr, + &sensor_dev_attr_in16_alarm.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, &sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, &sensor_dev_attr_fan3_input.dev_attr.attr, &sensor_dev_attr_fan3_div.dev_attr.attr, &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, &sensor_dev_attr_fan4_input.dev_attr.attr, &sensor_dev_attr_fan4_div.dev_attr.attr, &sensor_dev_attr_fan4_min.dev_attr.attr, + &sensor_dev_attr_fan4_alarm.dev_attr.attr, &sensor_dev_attr_fan5_input.dev_attr.attr, &sensor_dev_attr_fan5_div.dev_attr.attr, &sensor_dev_attr_fan5_min.dev_attr.attr, + &sensor_dev_attr_fan5_alarm.dev_attr.attr, &sensor_dev_attr_fan6_input.dev_attr.attr, &sensor_dev_attr_fan6_div.dev_attr.attr, &sensor_dev_attr_fan6_min.dev_attr.attr, + &sensor_dev_attr_fan6_alarm.dev_attr.attr, &sensor_dev_attr_fan7_input.dev_attr.attr, &sensor_dev_attr_fan7_div.dev_attr.attr, &sensor_dev_attr_fan7_min.dev_attr.attr, + &sensor_dev_attr_fan7_alarm.dev_attr.attr, &sensor_dev_attr_fan8_input.dev_attr.attr, &sensor_dev_attr_fan8_div.dev_attr.attr, &sensor_dev_attr_fan8_min.dev_attr.attr, + &sensor_dev_attr_fan8_alarm.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr, - &sensor_dev_attr_temp3_input.dev_attr.attr, - &sensor_dev_attr_temp3_max.dev_attr.attr, - &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, &sensor_dev_attr_temp1_offset.dev_attr.attr, &sensor_dev_attr_temp2_offset.dev_attr.attr, - &sensor_dev_attr_temp3_offset.dev_attr.attr, &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr, &sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr, - &sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr, &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr, &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr.attr, - &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr.attr, &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr, &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr, - &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr, - &sensor_dev_attr_temp3_crit.dev_attr.attr, &dev_attr_temp1_crit_enable.attr, &dev_attr_temp2_crit_enable.attr, - &dev_attr_temp3_crit_enable.attr, &dev_attr_cpu0_vid.attr, &dev_attr_vrm.attr, &dev_attr_alarms.attr, @@ -1557,10 +1601,8 @@ static struct attribute *adm1026_attributes[] = { &dev_attr_pwm3_enable.attr, &dev_attr_temp1_auto_point1_pwm.attr, &dev_attr_temp2_auto_point1_pwm.attr, - &dev_attr_temp3_auto_point1_pwm.attr, &dev_attr_temp1_auto_point2_pwm.attr, &dev_attr_temp2_auto_point2_pwm.attr, - &dev_attr_temp3_auto_point2_pwm.attr, &dev_attr_analog_out.attr, NULL }; @@ -1569,11 +1611,45 @@ static const struct attribute_group adm1026_group = { .attrs = adm1026_attributes, }; +static struct attribute *adm1026_attributes_temp3[] = { + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_offset.dev_attr.attr, + &sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr.attr, + &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_temp3_crit.dev_attr.attr, + &dev_attr_temp3_crit_enable.attr, + &dev_attr_temp3_auto_point1_pwm.attr, + &dev_attr_temp3_auto_point2_pwm.attr, +}; + +static const struct attribute_group adm1026_group_temp3 = { + .attrs = adm1026_attributes_temp3, +}; + +static struct attribute *adm1026_attributes_in8_9[] = { + &sensor_dev_attr_in8_input.dev_attr.attr, + &sensor_dev_attr_in8_max.dev_attr.attr, + &sensor_dev_attr_in8_min.dev_attr.attr, + &sensor_dev_attr_in8_alarm.dev_attr.attr, + &sensor_dev_attr_in9_input.dev_attr.attr, + &sensor_dev_attr_in9_max.dev_attr.attr, + &sensor_dev_attr_in9_min.dev_attr.attr, + &sensor_dev_attr_in9_alarm.dev_attr.attr, +}; + +static const struct attribute_group adm1026_group_in8_9 = { + .attrs = adm1026_attributes_in8_9, +}; + static int adm1026_detect(struct i2c_adapter *adapter, int address, int kind) { int company, verstep; - struct i2c_client *new_client; + struct i2c_client *client; struct adm1026_data *data; int err = 0; const char *type_name = ""; @@ -1592,26 +1668,25 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address, goto exit; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1026_driver; - new_client->flags = 0; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &adm1026_driver; /* Now, we do the remaining detection. */ - company = adm1026_read_value(new_client, ADM1026_REG_COMPANY); - verstep = adm1026_read_value(new_client, ADM1026_REG_VERSTEP); + company = adm1026_read_value(client, ADM1026_REG_COMPANY); + verstep = adm1026_read_value(client, ADM1026_REG_VERSTEP); - dev_dbg(&new_client->dev, "Detecting device at %d,0x%02x with" + dev_dbg(&client->dev, "Detecting device at %d,0x%02x with" " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", - i2c_adapter_id(new_client->adapter), new_client->addr, + i2c_adapter_id(client->adapter), client->addr, company, verstep); /* If auto-detecting, Determine the chip type. */ if (kind <= 0) { - dev_dbg(&new_client->dev, "Autodetecting device at %d,0x%02x " + dev_dbg(&client->dev, "Autodetecting device at %d,0x%02x " "...\n", i2c_adapter_id(adapter), address); if (company == ADM1026_COMPANY_ANALOG_DEV && verstep == ADM1026_VERSTEP_ADM1026) { @@ -1627,16 +1702,15 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address, verstep); kind = any_chip; } else { - dev_dbg(&new_client->dev, ": Autodetection " + dev_dbg(&client->dev, ": Autodetection " "failed\n"); /* Not an ADM1026 ... */ - if (kind == 0) { /* User used force=x,y */ + if (kind == 0) { /* User used force=x,y */ dev_err(&adapter->dev, "Generic ADM1026 not " "found at %d,0x%02x. Try " "force_adm1026.\n", i2c_adapter_id(adapter), address); } - err = 0; goto exitfree; } } @@ -1655,28 +1729,34 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address, err = -EFAULT; goto exitfree; } - strlcpy(new_client->name, type_name, I2C_NAME_SIZE); + strlcpy(client->name, type_name, I2C_NAME_SIZE); /* Fill in the remaining client fields */ - data->type = kind; - data->valid = 0; mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto exitfree; /* Set the VRM version */ data->vrm = vid_which_vrm(); /* Initialize the ADM1026 chip */ - adm1026_init_client(new_client); + adm1026_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1026_group))) + if ((err = sysfs_create_group(&client->dev.kobj, &adm1026_group))) goto exitdetach; + if (data->config1 & CFG1_AIN8_9) + err = sysfs_create_group(&client->dev.kobj, + &adm1026_group_in8_9); + else + err = sysfs_create_group(&client->dev.kobj, + &adm1026_group_temp3); + if (err) + goto exitremove; - data->hwmon_dev = hwmon_device_register(&new_client->dev); + data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exitremove; @@ -1686,9 +1766,13 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address, /* Error out and cleanup code */ exitremove: - sysfs_remove_group(&new_client->dev.kobj, &adm1026_group); + sysfs_remove_group(&client->dev.kobj, &adm1026_group); + if (data->config1 & CFG1_AIN8_9) + sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9); + else + sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3); exitdetach: - i2c_detach_client(new_client); + i2c_detach_client(client); exitfree: kfree(data); exit: @@ -1700,6 +1784,10 @@ static int adm1026_detach_client(struct i2c_client *client) struct adm1026_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1026_group); + if (data->config1 & CFG1_AIN8_9) + sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9); + else + sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3); i2c_detach_client(client); kfree(data); return 0; @@ -1710,14 +1798,14 @@ static int __init sm_adm1026_init(void) return i2c_add_driver(&adm1026_driver); } -static void __exit sm_adm1026_exit(void) +static void __exit sm_adm1026_exit(void) { i2c_del_driver(&adm1026_driver); } MODULE_LICENSE("GPL"); MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com>, " - "Justin Thiessen <jthiessen@penguincomputing.com>"); + "Justin Thiessen <jthiessen@penguincomputing.com>"); MODULE_DESCRIPTION("ADM1026 driver"); module_init(sm_adm1026_init); diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 37cfc101da5e..5aaad3636c98 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -5,7 +5,7 @@ Supports adm1030 / adm1031 Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org> Reworked by Jean Delvare <khali@linux-fr.org> - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -27,27 +27,28 @@ #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> /* Following macros takes channel parameter starting from 0 to 2 */ #define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr)) -#define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr)) +#define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr)) #define ADM1031_REG_PWM (0x22) #define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr)) -#define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4*(nr)) -#define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4*(nr)) -#define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4*(nr)) +#define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4 * (nr)) +#define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4 * (nr)) +#define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4 * (nr)) -#define ADM1031_REG_TEMP(nr) (0xa + (nr)) +#define ADM1031_REG_TEMP(nr) (0x0a + (nr)) #define ADM1031_REG_AUTO_TEMP(nr) (0x24 + (nr)) #define ADM1031_REG_STATUS(nr) (0x2 + (nr)) -#define ADM1031_REG_CONF1 0x0 -#define ADM1031_REG_CONF2 0x1 -#define ADM1031_REG_EXT_TEMP 0x6 +#define ADM1031_REG_CONF1 0x00 +#define ADM1031_REG_CONF2 0x01 +#define ADM1031_REG_EXT_TEMP 0x06 #define ADM1031_CONF1_MONITOR_ENABLE 0x01 /* Monitoring enable */ #define ADM1031_CONF1_PWM_INVERT 0x08 /* PWM Invert */ @@ -78,7 +79,7 @@ struct adm1031_data { /* The chan_select_table contains the possible configurations for * auto fan control. */ - auto_chan_table_t *chan_select_table; + const auto_chan_table_t *chan_select_table; u16 alarm; u8 conf1; u8 conf2; @@ -181,25 +182,25 @@ static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm) #define GET_FAN_AUTO_BITFIELD(data, idx) \ (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx%2] -/* The tables below contains the possible values for the auto fan +/* The tables below contains the possible values for the auto fan * control bitfields. the index in the table is the register value. * MSb is the auto fan control enable bit, so the four first entries * in the table disables auto fan control when both bitfields are zero. */ -static auto_chan_table_t auto_channel_select_table_adm1031 = { - {0, 0}, {0, 0}, {0, 0}, {0, 0}, - {2 /*0b010 */ , 4 /*0b100 */ }, - {2 /*0b010 */ , 2 /*0b010 */ }, - {4 /*0b100 */ , 4 /*0b100 */ }, - {7 /*0b111 */ , 7 /*0b111 */ }, +static const auto_chan_table_t auto_channel_select_table_adm1031 = { + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 2 /* 0b010 */ , 4 /* 0b100 */ }, + { 2 /* 0b010 */ , 2 /* 0b010 */ }, + { 4 /* 0b100 */ , 4 /* 0b100 */ }, + { 7 /* 0b111 */ , 7 /* 0b111 */ }, }; -static auto_chan_table_t auto_channel_select_table_adm1030 = { - {0, 0}, {0, 0}, {0, 0}, {0, 0}, - {2 /*0b10 */ , 0}, - {0xff /*invalid */ , 0}, - {0xff /*invalid */ , 0}, - {3 /*0b11 */ , 0}, +static const auto_chan_table_t auto_channel_select_table_adm1030 = { + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 2 /* 0b10 */ , 0 }, + { 0xff /* invalid */ , 0 }, + { 0xff /* invalid */ , 0 }, + { 3 /* 0b11 */ , 0 }, }; /* That function checks if a bitfield is valid and returns the other bitfield @@ -228,8 +229,8 @@ get_fan_auto_nearest(struct adm1031_data *data, break; } else if (val == (*data->chan_select_table)[i][chan] && first_match == -1) { - /* Save the first match in case of an exact match has not been - * found + /* Save the first match in case of an exact match has + * not been found */ first_match = i; } @@ -245,17 +246,21 @@ get_fan_auto_nearest(struct adm1031_data *data, return 0; } -static ssize_t show_fan_auto_channel(struct device *dev, char *buf, int nr) +static ssize_t show_fan_auto_channel(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct adm1031_data *data = adm1031_update_device(dev); return sprintf(buf, "%d\n", GET_FAN_AUTO_BITFIELD(data, nr)); } static ssize_t -set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr) +set_fan_auto_channel(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; int val = simple_strtol(buf, NULL, 10); u8 reg; int ret; @@ -264,16 +269,17 @@ set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr) old_fan_mode = data->conf1; mutex_lock(&data->update_lock); - + if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®))) { mutex_unlock(&data->update_lock); return ret; } - if (((data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1)) & ADM1031_CONF1_AUTO_MODE) ^ + data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1); + if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^ (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) { if (data->conf1 & ADM1031_CONF1_AUTO_MODE){ - /* Switch to Auto Fan Mode - * Save PWM registers + /* Switch to Auto Fan Mode + * Save PWM registers * Set PWM registers to 33% Both */ data->old_pwm[0] = data->pwm[0]; data->old_pwm[1] = data->pwm[1]; @@ -283,7 +289,7 @@ set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr) data->pwm[0] = data->old_pwm[0]; data->pwm[1] = data->old_pwm[1]; /* Restore PWM registers */ - adm1031_write_value(client, ADM1031_REG_PWM, + adm1031_write_value(client, ADM1031_REG_PWM, data->pwm[0] | (data->pwm[1] << 4)); } } @@ -293,41 +299,35 @@ set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr) return count; } -#define fan_auto_channel_offset(offset) \ -static ssize_t show_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_auto_channel(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_auto_channel(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(auto_fan##offset##_channel, S_IRUGO | S_IWUSR, \ - show_fan_auto_channel_##offset, \ - set_fan_auto_channel_##offset) - -fan_auto_channel_offset(1); -fan_auto_channel_offset(2); +static SENSOR_DEVICE_ATTR(auto_fan1_channel, S_IRUGO | S_IWUSR, + show_fan_auto_channel, set_fan_auto_channel, 0); +static SENSOR_DEVICE_ATTR(auto_fan2_channel, S_IRUGO | S_IWUSR, + show_fan_auto_channel, set_fan_auto_channel, 1); /* Auto Temps */ -static ssize_t show_auto_temp_off(struct device *dev, char *buf, int nr) +static ssize_t show_auto_temp_off(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", + return sprintf(buf, "%d\n", AUTO_TEMP_OFF_FROM_REG(data->auto_temp[nr])); } -static ssize_t show_auto_temp_min(struct device *dev, char *buf, int nr) +static ssize_t show_auto_temp_min(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct adm1031_data *data = adm1031_update_device(dev); return sprintf(buf, "%d\n", AUTO_TEMP_MIN_FROM_REG(data->auto_temp[nr])); } static ssize_t -set_auto_temp_min(struct device *dev, const char *buf, size_t count, int nr) +set_auto_temp_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; int val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); @@ -337,17 +337,21 @@ set_auto_temp_min(struct device *dev, const char *buf, size_t count, int nr) mutex_unlock(&data->update_lock); return count; } -static ssize_t show_auto_temp_max(struct device *dev, char *buf, int nr) +static ssize_t show_auto_temp_max(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct adm1031_data *data = adm1031_update_device(dev); return sprintf(buf, "%d\n", AUTO_TEMP_MAX_FROM_REG(data->auto_temp[nr])); } static ssize_t -set_auto_temp_max(struct device *dev, const char *buf, size_t count, int nr) +set_auto_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; int val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); @@ -358,56 +362,37 @@ set_auto_temp_max(struct device *dev, const char *buf, size_t count, int nr) return count; } -#define auto_temp_reg(offset) \ -static ssize_t show_auto_temp_##offset##_off (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_auto_temp_off(dev, buf, offset - 1); \ -} \ -static ssize_t show_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_auto_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_auto_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t set_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_auto_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_auto_temp_max(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(auto_temp##offset##_off, S_IRUGO, \ - show_auto_temp_##offset##_off, NULL); \ -static DEVICE_ATTR(auto_temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_auto_temp_##offset##_min, set_auto_temp_##offset##_min);\ -static DEVICE_ATTR(auto_temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_auto_temp_##offset##_max, set_auto_temp_##offset##_max) +#define auto_temp_reg(offset) \ +static SENSOR_DEVICE_ATTR(auto_temp##offset##_off, S_IRUGO, \ + show_auto_temp_off, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(auto_temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_auto_temp_min, set_auto_temp_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(auto_temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_auto_temp_max, set_auto_temp_max, offset - 1) auto_temp_reg(1); auto_temp_reg(2); auto_temp_reg(3); /* pwm */ -static ssize_t show_pwm(struct device *dev, char *buf, int nr) +static ssize_t show_pwm(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct adm1031_data *data = adm1031_update_device(dev); return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); } -static ssize_t -set_pwm(struct device *dev, const char *buf, size_t count, int nr) +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; int val = simple_strtol(buf, NULL, 10); int reg; mutex_lock(&data->update_lock); - if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) && + if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) && (((val>>4) & 0xf) != 5)) { /* In automatic mode, the only PWM accepted is 33% */ mutex_unlock(&data->update_lock); @@ -422,21 +407,12 @@ set_pwm(struct device *dev, const char *buf, size_t count, int nr) return count; } -#define pwm_reg(offset) \ -static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm_##offset, set_pwm_##offset) - -pwm_reg(1); -pwm_reg(2); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1); +static SENSOR_DEVICE_ATTR(auto_fan1_min_pwm, S_IRUGO | S_IWUSR, + show_pwm, set_pwm, 0); +static SENSOR_DEVICE_ATTR(auto_fan2_min_pwm, S_IRUGO | S_IWUSR, + show_pwm, set_pwm, 1); /* Fans */ @@ -471,7 +447,7 @@ static int trust_fan_readings(struct adm1031_data *data, int chan) AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[0]) || data->temp[1] >= AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]) - || (data->chip_type == adm1031 + || (data->chip_type == adm1031 && data->temp[2] >= AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2])); break; @@ -483,8 +459,10 @@ static int trust_fan_readings(struct adm1031_data *data, int chan) } -static ssize_t show_fan(struct device *dev, char *buf, int nr) +static ssize_t show_fan(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct adm1031_data *data = adm1031_update_device(dev); int value; @@ -493,28 +471,33 @@ static ssize_t show_fan(struct device *dev, char *buf, int nr) return sprintf(buf, "%d\n", value); } -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +static ssize_t show_fan_div(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct adm1031_data *data = adm1031_update_device(dev); return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[nr])); } -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +static ssize_t show_fan_min(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct adm1031_data *data = adm1031_update_device(dev); return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], FAN_DIV_FROM_REG(data->fan_div[nr]))); } -static ssize_t -set_fan_min(struct device *dev, const char *buf, size_t count, int nr) +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; int val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); if (val) { - data->fan_min[nr] = + data->fan_min[nr] = FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr])); } else { data->fan_min[nr] = 0xff; @@ -523,11 +506,12 @@ set_fan_min(struct device *dev, const char *buf, size_t count, int nr) mutex_unlock(&data->update_lock); return count; } -static ssize_t -set_fan_div(struct device *dev, const char *buf, size_t count, int nr) +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; int val = simple_strtol(buf, NULL, 10); u8 tmp; int old_div; @@ -535,68 +519,53 @@ set_fan_div(struct device *dev, const char *buf, size_t count, int nr) tmp = val == 8 ? 0xc0 : val == 4 ? 0x80 : - val == 2 ? 0x40 : - val == 1 ? 0x00 : + val == 2 ? 0x40 : + val == 1 ? 0x00 : 0xff; if (tmp == 0xff) return -EINVAL; - + mutex_lock(&data->update_lock); + /* Get fresh readings */ + data->fan_div[nr] = adm1031_read_value(client, + ADM1031_REG_FAN_DIV(nr)); + data->fan_min[nr] = adm1031_read_value(client, + ADM1031_REG_FAN_MIN(nr)); + + /* Write the new clock divider and fan min */ old_div = FAN_DIV_FROM_REG(data->fan_div[nr]); - data->fan_div[nr] = (tmp & 0xC0) | (0x3f & data->fan_div[nr]); - new_min = data->fan_min[nr] * old_div / - FAN_DIV_FROM_REG(data->fan_div[nr]); + data->fan_div[nr] = tmp | (0x3f & data->fan_div[nr]); + new_min = data->fan_min[nr] * old_div / val; data->fan_min[nr] = new_min > 0xff ? 0xff : new_min; - data->fan[nr] = data->fan[nr] * old_div / - FAN_DIV_FROM_REG(data->fan_div[nr]); - adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr), + adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr), data->fan_div[nr]); - adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), + adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]); + + /* Invalidate the cache: fan speed is no longer valid */ + data->valid = 0; mutex_unlock(&data->update_lock); return count; } #define fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \ - NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_div, set_fan_##offset##_div); \ -static DEVICE_ATTR(auto_fan##offset##_min_pwm, S_IRUGO | S_IWUSR, \ - show_pwm_##offset, set_pwm_##offset) +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_div, set_fan_div, offset - 1) fan_offset(1); fan_offset(2); /* Temps */ -static ssize_t show_temp(struct device *dev, char *buf, int nr) +static ssize_t show_temp(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct adm1031_data *data = adm1031_update_device(dev); int ext; ext = nr == 0 ? @@ -604,26 +573,33 @@ static ssize_t show_temp(struct device *dev, char *buf, int nr) (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7)); return sprintf(buf, "%d\n", TEMP_FROM_REG_EXT(data->temp[nr], ext)); } -static ssize_t show_temp_min(struct device *dev, char *buf, int nr) +static ssize_t show_temp_min(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct adm1031_data *data = adm1031_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr])); } -static ssize_t show_temp_max(struct device *dev, char *buf, int nr) +static ssize_t show_temp_max(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct adm1031_data *data = adm1031_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr])); } -static ssize_t show_temp_crit(struct device *dev, char *buf, int nr) +static ssize_t show_temp_crit(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct adm1031_data *data = adm1031_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr])); } -static ssize_t -set_temp_min(struct device *dev, const char *buf, size_t count, int nr) +static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; int val; val = simple_strtol(buf, NULL, 10); @@ -635,11 +611,12 @@ set_temp_min(struct device *dev, const char *buf, size_t count, int nr) mutex_unlock(&data->update_lock); return count; } -static ssize_t -set_temp_max(struct device *dev, const char *buf, size_t count, int nr) +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; int val; val = simple_strtol(buf, NULL, 10); @@ -651,11 +628,12 @@ set_temp_max(struct device *dev, const char *buf, size_t count, int nr) mutex_unlock(&data->update_lock); return count; } -static ssize_t -set_temp_crit(struct device *dev, const char *buf, size_t count, int nr) +static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; int val; val = simple_strtol(buf, NULL, 10); @@ -668,46 +646,15 @@ set_temp_crit(struct device *dev, const char *buf, size_t count, int nr) return count; } -#define temp_reg(offset) \ -static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_crit(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_max(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_crit(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \ - NULL); \ -static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_min, set_temp_##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_max, set_temp_##offset##_max); \ -static DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_crit, set_temp_##offset##_crit) +#define temp_reg(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_min, set_temp_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_max, set_temp_max, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \ + show_temp_crit, set_temp_crit, offset - 1) temp_reg(1); temp_reg(2); @@ -722,6 +669,29 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static ssize_t show_alarm(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", (data->alarm >> bitnr) & 1); +} + +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 12); +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 13); +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14); static int adm1031_attach_adapter(struct i2c_adapter *adapter) { @@ -731,29 +701,38 @@ static int adm1031_attach_adapter(struct i2c_adapter *adapter) } static struct attribute *adm1031_attributes[] = { - &dev_attr_fan1_input.attr, - &dev_attr_fan1_div.attr, - &dev_attr_fan1_min.attr, - &dev_attr_pwm1.attr, - &dev_attr_auto_fan1_channel.attr, - &dev_attr_temp1_input.attr, - &dev_attr_temp1_min.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_crit.attr, - &dev_attr_temp2_input.attr, - &dev_attr_temp2_min.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp2_crit.attr, - - &dev_attr_auto_temp1_off.attr, - &dev_attr_auto_temp1_min.attr, - &dev_attr_auto_temp1_max.attr, - - &dev_attr_auto_temp2_off.attr, - &dev_attr_auto_temp2_min.attr, - &dev_attr_auto_temp2_max.attr, - - &dev_attr_auto_fan1_min_pwm.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_fault.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_auto_fan1_channel.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, + + &sensor_dev_attr_auto_temp1_off.dev_attr.attr, + &sensor_dev_attr_auto_temp1_min.dev_attr.attr, + &sensor_dev_attr_auto_temp1_max.dev_attr.attr, + + &sensor_dev_attr_auto_temp2_off.dev_attr.attr, + &sensor_dev_attr_auto_temp2_min.dev_attr.attr, + &sensor_dev_attr_auto_temp2_max.dev_attr.attr, + + &sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr, &dev_attr_alarms.attr, @@ -765,19 +744,25 @@ static const struct attribute_group adm1031_group = { }; static struct attribute *adm1031_attributes_opt[] = { - &dev_attr_fan2_input.attr, - &dev_attr_fan2_div.attr, - &dev_attr_fan2_min.attr, - &dev_attr_pwm2.attr, - &dev_attr_auto_fan2_channel.attr, - &dev_attr_temp3_input.attr, - &dev_attr_temp3_min.attr, - &dev_attr_temp3_max.attr, - &dev_attr_temp3_crit.attr, - &dev_attr_auto_temp3_off.attr, - &dev_attr_auto_temp3_min.attr, - &dev_attr_auto_temp3_max.attr, - &dev_attr_auto_fan2_min_pwm.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + &sensor_dev_attr_fan2_fault.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_auto_fan2_channel.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_crit.dev_attr.attr, + &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, + &sensor_dev_attr_auto_temp3_off.dev_attr.attr, + &sensor_dev_attr_auto_temp3_min.dev_attr.attr, + &sensor_dev_attr_auto_temp3_max.dev_attr.attr, + &sensor_dev_attr_auto_fan2_min_pwm.dev_attr.attr, NULL }; @@ -788,7 +773,7 @@ static const struct attribute_group adm1031_group_opt = { /* This function is called by i2c_probe */ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) { - struct i2c_client *new_client; + struct i2c_client *client; struct adm1031_data *data; int err = 0; const char *name = ""; @@ -801,17 +786,16 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) goto exit; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1031_driver; - new_client->flags = 0; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &adm1031_driver; if (kind < 0) { int id, co; - id = i2c_smbus_read_byte_data(new_client, 0x3d); - co = i2c_smbus_read_byte_data(new_client, 0x3e); + id = i2c_smbus_read_byte_data(client, 0x3d); + co = i2c_smbus_read_byte_data(client, 0x3e); if (!((id == 0x31 || id == 0x30) && co == 0x41)) goto exit_free; @@ -832,28 +816,27 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) } data->chip_type = kind; - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; + strlcpy(client->name, name, I2C_NAME_SIZE); mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto exit_free; /* Initialize the ADM1031 chip */ - adm1031_init_client(new_client); + adm1031_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1031_group))) + if ((err = sysfs_create_group(&client->dev.kobj, &adm1031_group))) goto exit_detach; if (kind == adm1031) { - if ((err = sysfs_create_group(&new_client->dev.kobj, + if ((err = sysfs_create_group(&client->dev.kobj, &adm1031_group_opt))) goto exit_remove; } - data->hwmon_dev = hwmon_device_register(&new_client->dev); + data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exit_remove; @@ -862,10 +845,10 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_remove: - sysfs_remove_group(&new_client->dev.kobj, &adm1031_group); - sysfs_remove_group(&new_client->dev.kobj, &adm1031_group_opt); + sysfs_remove_group(&client->dev.kobj, &adm1031_group); + sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt); exit_detach: - i2c_detach_client(new_client); + i2c_detach_client(client); exit_free: kfree(data); exit: @@ -897,7 +880,7 @@ static void adm1031_init_client(struct i2c_client *client) if (data->chip_type == adm1031) { mask |= (ADM1031_CONF2_PWM2_ENABLE | ADM1031_CONF2_TACH2_ENABLE); - } + } /* Initialize the ADM1031 chip (enables fan speed reading ) */ read_val = adm1031_read_value(client, ADM1031_REG_CONF2); if ((read_val | mask) != read_val) { @@ -976,7 +959,7 @@ static struct adm1031_data *adm1031_update_device(struct device *dev) if (data->chip_type == adm1030) { data->alarm &= 0xc0ff; } - + for (chan=0; chan<(data->chip_type == adm1030 ? 1 : 2); chan++) { data->fan_div[chan] = adm1031_read_value(client, ADM1031_REG_FAN_DIV(chan)); @@ -985,7 +968,7 @@ static struct adm1031_data *adm1031_update_device(struct device *dev) data->fan[chan] = adm1031_read_value(client, ADM1031_REG_FAN_SPEED(chan)); data->pwm[chan] = - 0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >> + 0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >> (4*chan)); } data->last_updated = jiffies; diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index c17d0b6b3283..7671d2bf7800 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -141,7 +141,6 @@ static struct i2c_driver adm9240_driver = { .driver = { .name = "adm9240", }, - .id = I2C_DRIVERID_ADM9240, .attach_adapter = adm9240_attach_adapter, .detach_client = adm9240_detach_client, }; @@ -415,6 +414,23 @@ static ssize_t show_alarms(struct device *dev, } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static ssize_t show_alarm(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); + /* vid */ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) @@ -469,30 +485,39 @@ static struct attribute *adm9240_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in0_min.dev_attr.attr, &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in1_min.dev_attr.attr, &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, &sensor_dev_attr_in2_min.dev_attr.attr, &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, &sensor_dev_attr_in3_input.dev_attr.attr, &sensor_dev_attr_in3_min.dev_attr.attr, &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, &sensor_dev_attr_in4_input.dev_attr.attr, &sensor_dev_attr_in4_min.dev_attr.attr, &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, &sensor_dev_attr_in5_input.dev_attr.attr, &sensor_dev_attr_in5_min.dev_attr.attr, &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, &dev_attr_temp1_input.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, &sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, &dev_attr_alarms.attr, &dev_attr_aout_output.attr, &dev_attr_chassis_clear.attr, diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c new file mode 100644 index 000000000000..6b8a73ef404c --- /dev/null +++ b/drivers/hwmon/ads7828.c @@ -0,0 +1,297 @@ +/* + ads7828.c - lm_sensors driver for ads7828 12-bit 8-channel ADC + (C) 2007 EADS Astrium + + This driver is based on the lm75 and other lm_sensors/hwmon drivers + + Written by Steve Hardy <steve@linuxrealtime.co.uk> + + Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/i2c.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/mutex.h> + +/* The ADS7828 registers */ +#define ADS7828_NCH 8 /* 8 channels of 12-bit A-D supported */ +#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */ +#define ADS7828_CMD_SD_DIFF 0x00 /* Differential inputs */ +#define ADS7828_CMD_PD0 0x0 /* Power Down between A-D conversions */ +#define ADS7828_CMD_PD1 0x04 /* Internal ref OFF && A-D ON */ +#define ADS7828_CMD_PD2 0x08 /* Internal ref ON && A-D OFF */ +#define ADS7828_CMD_PD3 0x0C /* Internal ref ON && A-D ON */ +#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */ + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, + I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_1(ads7828); + +/* Other module parameters */ +static int se_input = 1; /* Default is SE, 0 == diff */ +static int int_vref = 1; /* Default is internal ref ON */ +static int vref_mv = ADS7828_INT_VREF_MV; /* set if vref != 2.5V */ +module_param(se_input, bool, S_IRUGO); +module_param(int_vref, bool, S_IRUGO); +module_param(vref_mv, int, S_IRUGO); + +/* Global Variables */ +static u8 ads7828_cmd_byte; /* cmd byte without channel bits */ +static unsigned int ads7828_lsb_resol; /* resolution of the ADC sample lsb */ + +/* Each client has this additional data */ +struct ads7828_data { + struct i2c_client client; + struct device *hwmon_dev; + struct mutex update_lock; /* mutex protect updates */ + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH 12-bit samples */ +}; + +/* Function declaration - necessary due to function dependencies */ +static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind); + +/* The ADS7828 returns the 12-bit sample in two bytes, + these are read as a word then byte-swapped */ +static u16 ads7828_read_value(struct i2c_client *client, u8 reg) +{ + return swab16(i2c_smbus_read_word_data(client, reg)); +} + +static inline u8 channel_cmd_byte(int ch) +{ + /* cmd byte C2,C1,C0 - see datasheet */ + u8 cmd = (((ch>>1) | (ch&0x01)<<2)<<4); + cmd |= ads7828_cmd_byte; + return cmd; +} + +/* Update data for the device (all 8 channels) */ +static struct ads7828_data *ads7828_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ads7828_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + unsigned int ch; + dev_dbg(&client->dev, "Starting ads7828 update\n"); + + for (ch = 0; ch < ADS7828_NCH; ch++) { + u8 cmd = channel_cmd_byte(ch); + data->adc_input[ch] = ads7828_read_value(client, cmd); + } + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +/* sysfs callback function */ +static ssize_t show_in(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ads7828_data *data = ads7828_update_device(dev); + /* Print value (in mV as specified in sysfs-interface documentation) */ + return sprintf(buf, "%d\n", (data->adc_input[attr->index] * + ads7828_lsb_resol)/1000); +} + +#define in_reg(offset)\ +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\ + NULL, offset) + +in_reg(0); +in_reg(1); +in_reg(2); +in_reg(3); +in_reg(4); +in_reg(5); +in_reg(6); +in_reg(7); + +static struct attribute *ads7828_attributes[] = { + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in7_input.dev_attr.attr, + NULL +}; + +static const struct attribute_group ads7828_group = { + .attrs = ads7828_attributes, +}; + +static int ads7828_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, ads7828_detect); +} + +static int ads7828_detach_client(struct i2c_client *client) +{ + struct ads7828_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &ads7828_group); + i2c_detach_client(client); + kfree(i2c_get_clientdata(client)); + return 0; +} + +/* This is the driver that will be inserted */ +static struct i2c_driver ads7828_driver = { + .driver = { + .name = "ads7828", + }, + .attach_adapter = ads7828_attach_adapter, + .detach_client = ads7828_detach_client, +}; + +/* This function is called by i2c_probe */ +static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct ads7828_data *data; + int err = 0; + const char *name = ""; + + /* Check we have a valid client */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access ads7828_read_value. */ + data = kzalloc(sizeof(struct ads7828_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &ads7828_driver; + + /* Now, we do the remaining detection. There is no identification + dedicated register so attempt to sanity check using knowledge of + the chip + - Read from the 8 channel addresses + - Check the top 4 bits of each result are not set (12 data bits) + */ + if (kind < 0) { + int ch; + for (ch = 0; ch < ADS7828_NCH; ch++) { + u16 in_data; + u8 cmd = channel_cmd_byte(ch); + in_data = ads7828_read_value(client, cmd); + if (in_data & 0xF000) { + printk(KERN_DEBUG + "%s : Doesn't look like an ads7828 device\n", + __FUNCTION__); + goto exit_free; + } + } + } + + /* Determine the chip type - only one kind supported! */ + if (kind <= 0) + kind = ads7828; + + if (kind == ads7828) + name = "ads7828"; + + /* Fill in the remaining client fields, put it into the global list */ + strlcpy(client->name, name, I2C_NAME_SIZE); + + mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + err = i2c_attach_client(client); + if (err) + goto exit_free; + + /* Register sysfs hooks */ + err = sysfs_create_group(&client->dev.kobj, &ads7828_group); + if (err) + goto exit_detach; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &ads7828_group); +exit_detach: + i2c_detach_client(client); +exit_free: + kfree(data); +exit: + return err; +} + +static int __init sensors_ads7828_init(void) +{ + /* Initialize the command byte according to module parameters */ + ads7828_cmd_byte = se_input ? + ADS7828_CMD_SD_SE : ADS7828_CMD_SD_DIFF; + ads7828_cmd_byte |= int_vref ? + ADS7828_CMD_PD3 : ADS7828_CMD_PD1; + + /* Calculate the LSB resolution */ + ads7828_lsb_resol = (vref_mv*1000)/4096; + + return i2c_add_driver(&ads7828_driver); +} + +static void __exit sensors_ads7828_exit(void) +{ + i2c_del_driver(&ads7828_driver); +} + +MODULE_AUTHOR("Steve Hardy <steve@linuxrealtime.co.uk>"); +MODULE_DESCRIPTION("ADS7828 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_ads7828_init); +module_exit(sensors_ads7828_exit); diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 9810aaa0489d..747693ab2ff1 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -48,7 +48,22 @@ I2C_CLIENT_INSMOD_1(adt7470); #define ADT7470_REG_CFG 0x40 #define ADT7470_FSPD_MASK 0x04 #define ADT7470_REG_ALARM1 0x41 +#define ADT7470_R1T_ALARM 0x01 +#define ADT7470_R2T_ALARM 0x02 +#define ADT7470_R3T_ALARM 0x04 +#define ADT7470_R4T_ALARM 0x08 +#define ADT7470_R5T_ALARM 0x10 +#define ADT7470_R6T_ALARM 0x20 +#define ADT7470_R7T_ALARM 0x40 +#define ADT7470_OOL_ALARM 0x80 #define ADT7470_REG_ALARM2 0x42 +#define ADT7470_R8T_ALARM 0x01 +#define ADT7470_R9T_ALARM 0x02 +#define ADT7470_R10T_ALARM 0x04 +#define ADT7470_FAN1_ALARM 0x10 +#define ADT7470_FAN2_ALARM 0x20 +#define ADT7470_FAN3_ALARM 0x40 +#define ADT7470_FAN4_ALARM 0x80 #define ADT7470_REG_TEMP_LIMITS_BASE_ADDR 0x44 #define ADT7470_REG_TEMP_LIMITS_MAX_ADDR 0x57 #define ADT7470_REG_FAN_MIN_BASE_ADDR 0x58 @@ -97,6 +112,8 @@ I2C_CLIENT_INSMOD_1(adt7470); #define ADT7470_REG_PWM_AUTO_TEMP(x) (ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR + \ ((x) / 2)) +#define ALARM2(x) ((x) << 8) + #define ADT7470_VENDOR 0x41 #define ADT7470_DEVICE 0x70 /* datasheet only mentions a revision 2 */ @@ -114,8 +131,6 @@ I2C_CLIENT_INSMOD_1(adt7470); /* sleep 1s while gathering temperature data */ #define TEMP_COLLECTION_TIME 1000 -#define power_of_2(x) (((x) & ((x) - 1)) == 0) - /* datasheet says to divide this number by the fan reading to get fan rpm */ #define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x)) #define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM @@ -138,7 +153,8 @@ struct adt7470_data { u16 fan[ADT7470_FAN_COUNT]; u16 fan_min[ADT7470_FAN_COUNT]; u16 fan_max[ADT7470_FAN_COUNT]; - u16 alarms, alarms_mask; + u16 alarm; + u16 alarms_mask; u8 force_pwm_max; u8 pwm[ADT7470_PWM_COUNT]; u8 pwm_max[ADT7470_PWM_COUNT]; @@ -262,7 +278,10 @@ static struct adt7470_data *adt7470_update_device(struct device *dev) else data->force_pwm_max = 0; - data->alarms = adt7470_read_word_data(client, ADT7470_REG_ALARM1); + data->alarm = i2c_smbus_read_byte_data(client, ADT7470_REG_ALARM1); + if (data->alarm & ADT7470_OOL_ALARM) + data->alarm |= ALARM2(i2c_smbus_read_byte_data(client, + ADT7470_REG_ALARM2)); data->alarms_mask = adt7470_read_word_data(client, ADT7470_REG_ALARM1_MASK); @@ -370,17 +389,13 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]); } -static ssize_t show_alarms(struct device *dev, +static ssize_t show_alarm_mask(struct device *dev, struct device_attribute *devattr, char *buf) { - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct adt7470_data *data = adt7470_update_device(dev); - if (attr->index) - return sprintf(buf, "%x\n", data->alarms); - else - return sprintf(buf, "%x\n", data->alarms_mask); + return sprintf(buf, "%x\n", data->alarms_mask); } static ssize_t show_fan_max(struct device *dev, @@ -677,7 +692,7 @@ static int cvt_auto_temp(int input) { if (input == ADT7470_PWM_ALL_TEMPS) return 0; - if (input < 1 || !power_of_2(input)) + if (input < 1 || !is_power_of_2(input)) return -EINVAL; return ilog2(input) + 1; } @@ -715,8 +730,20 @@ static ssize_t set_pwm_auto_temp(struct device *dev, return count; } -static SENSOR_DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL, 0); -static SENSOR_DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarms, NULL, 1); +static ssize_t show_alarm(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + + if (data->alarm & attr->index) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarm_mask, NULL); static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max, 0); @@ -771,6 +798,27 @@ static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7); static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8); static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_temp, NULL, 9); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, + ADT7470_R1T_ALARM); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, + ADT7470_R2T_ALARM); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, + ADT7470_R3T_ALARM); +static SENSOR_DEVICE_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL, + ADT7470_R4T_ALARM); +static SENSOR_DEVICE_ATTR(temp5_alarm, S_IRUGO, show_alarm, NULL, + ADT7470_R5T_ALARM); +static SENSOR_DEVICE_ATTR(temp6_alarm, S_IRUGO, show_alarm, NULL, + ADT7470_R6T_ALARM); +static SENSOR_DEVICE_ATTR(temp7_alarm, S_IRUGO, show_alarm, NULL, + ADT7470_R7T_ALARM); +static SENSOR_DEVICE_ATTR(temp8_alarm, S_IRUGO, show_alarm, NULL, + ALARM2(ADT7470_R8T_ALARM)); +static SENSOR_DEVICE_ATTR(temp9_alarm, S_IRUGO, show_alarm, NULL, + ALARM2(ADT7470_R9T_ALARM)); +static SENSOR_DEVICE_ATTR(temp10_alarm, S_IRUGO, show_alarm, NULL, + ALARM2(ADT7470_R10T_ALARM)); + static SENSOR_DEVICE_ATTR(fan1_max, S_IWUSR | S_IRUGO, show_fan_max, set_fan_max, 0); static SENSOR_DEVICE_ATTR(fan2_max, S_IWUSR | S_IRUGO, show_fan_max, @@ -794,6 +842,15 @@ static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, + ALARM2(ADT7470_FAN1_ALARM)); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, + ALARM2(ADT7470_FAN2_ALARM)); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, + ALARM2(ADT7470_FAN3_ALARM)); +static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, + ALARM2(ADT7470_FAN4_ALARM)); + static SENSOR_DEVICE_ATTR(force_pwm_max, S_IWUSR | S_IRUGO, show_force_pwm_max, set_force_pwm_max, 0); @@ -858,8 +915,7 @@ static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO, static struct attribute *adt7470_attr[] = { - &sensor_dev_attr_alarms.dev_attr.attr, - &sensor_dev_attr_alarm_mask.dev_attr.attr, + &dev_attr_alarm_mask.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, @@ -890,6 +946,16 @@ static struct attribute *adt7470_attr[] = &sensor_dev_attr_temp8_input.dev_attr.attr, &sensor_dev_attr_temp9_input.dev_attr.attr, &sensor_dev_attr_temp10_input.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_alarm.dev_attr.attr, + &sensor_dev_attr_temp5_alarm.dev_attr.attr, + &sensor_dev_attr_temp6_alarm.dev_attr.attr, + &sensor_dev_attr_temp7_alarm.dev_attr.attr, + &sensor_dev_attr_temp8_alarm.dev_attr.attr, + &sensor_dev_attr_temp9_alarm.dev_attr.attr, + &sensor_dev_attr_temp10_alarm.dev_attr.attr, &sensor_dev_attr_fan1_max.dev_attr.attr, &sensor_dev_attr_fan2_max.dev_attr.attr, &sensor_dev_attr_fan3_max.dev_attr.attr, @@ -902,6 +968,10 @@ static struct attribute *adt7470_attr[] = &sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan3_input.dev_attr.attr, &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, + &sensor_dev_attr_fan4_alarm.dev_attr.attr, &sensor_dev_attr_force_pwm_max.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr, diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index 9460dba4cf74..950cea8d1d65 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -40,6 +40,7 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/hwmon-vid.h> #include <linux/err.h> #include <linux/init.h> @@ -47,12 +48,6 @@ #include <linux/mutex.h> #include "lm75.h" -/* - HISTORY: - 2003-12-29 1.0.0 Ported from lm_sensors project for kernel 2.6 -*/ -#define ASB100_VERSION "1.0.0" - /* I2C addresses to scan */ static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END }; @@ -221,15 +216,16 @@ static struct i2c_driver asb100_driver = { .driver = { .name = "asb100", }, - .id = I2C_DRIVERID_ASB100, .attach_adapter = asb100_attach_adapter, .detach_client = asb100_detach_client, }; /* 7 Voltages */ #define show_in_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ + int nr = to_sensor_dev_attr(attr)->index; \ struct asb100_data *data = asb100_update_device(dev); \ return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \ } @@ -239,9 +235,10 @@ show_in_reg(in_min) show_in_reg(in_max) #define set_in_reg(REG, reg) \ -static ssize_t set_in_##reg(struct device *dev, const char *buf, \ - size_t count, int nr) \ +static ssize_t set_in_##reg(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ + int nr = to_sensor_dev_attr(attr)->index; \ struct i2c_client *client = to_i2c_client(dev); \ struct asb100_data *data = i2c_get_clientdata(client); \ unsigned long val = simple_strtoul(buf, NULL, 10); \ @@ -258,37 +255,12 @@ set_in_reg(MIN, min) set_in_reg(MAX, max) #define sysfs_in(offset) \ -static ssize_t \ - show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset, NULL); \ -static ssize_t \ - show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in, NULL, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, offset) sysfs_in(0); sysfs_in(1); @@ -299,29 +271,36 @@ sysfs_in(5); sysfs_in(6); /* 3 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr]))); } -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]))); } -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); } -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct asb100_data *data = i2c_get_clientdata(client); u32 val = simple_strtoul(buf, NULL, 10); @@ -337,22 +316,23 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, determined in part by the fan divisor. This follows the principle of least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct asb100_data *data = i2c_get_clientdata(client); unsigned long min; unsigned long val = simple_strtoul(buf, NULL, 10); int reg; - + mutex_lock(&data->update_lock); min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); data->fan_div[nr] = DIV_TO_REG(val); - switch(nr) { + switch (nr) { case 0: /* fan 1 */ reg = asb100_read_value(client, ASB100_REG_VID_FANDIV); reg = (reg & 0xcf) | (data->fan_div[0] << 4); @@ -382,34 +362,12 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, } #define sysfs_fan(offset) \ -static ssize_t show_fan##offset(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan##offset, NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan##offset##_min, set_fan##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan##offset##_div, set_fan##offset##_div); +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_div, set_fan_div, offset - 1) sysfs_fan(1); sysfs_fan(2); @@ -430,10 +388,12 @@ static int sprintf_temp_from_reg(u16 reg, char *buf, int nr) } return ret; } - + #define show_temp_reg(reg) \ -static ssize_t show_##reg(struct device *dev, char *buf, int nr) \ +static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ + int nr = to_sensor_dev_attr(attr)->index; \ struct asb100_data *data = asb100_update_device(dev); \ return sprintf_temp_from_reg(data->reg[nr], buf, nr); \ } @@ -443,9 +403,10 @@ show_temp_reg(temp_max); show_temp_reg(temp_hyst); #define set_temp_reg(REG, reg) \ -static ssize_t set_##reg(struct device *dev, const char *buf, \ - size_t count, int nr) \ +static ssize_t set_##reg(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ + int nr = to_sensor_dev_attr(attr)->index; \ struct i2c_client *client = to_i2c_client(dev); \ struct asb100_data *data = i2c_get_clientdata(client); \ long val = simple_strtol(buf, NULL, 10); \ @@ -469,33 +430,12 @@ set_temp_reg(MAX, temp_max); set_temp_reg(HYST, temp_hyst); #define sysfs_temp(num) \ -static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, num-1); \ -} \ -static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL); \ -static ssize_t show_temp_max##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_max(dev, buf, num-1); \ -} \ -static ssize_t set_temp_max##num(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_temp_max(dev, buf, count, num-1); \ -} \ -static DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \ - show_temp_max##num, set_temp_max##num); \ -static ssize_t show_temp_hyst##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_hyst(dev, buf, num-1); \ -} \ -static ssize_t set_temp_hyst##num(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_temp_hyst(dev, buf, count, num-1); \ -} \ -static DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \ - show_temp_hyst##num, set_temp_hyst##num); +static SENSOR_DEVICE_ATTR(temp##num##_input, S_IRUGO, \ + show_temp, NULL, num - 1); \ +static SENSOR_DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \ + show_temp_max, set_temp_max, num - 1); \ +static SENSOR_DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \ + show_temp_hyst, set_temp_hyst, num - 1) sysfs_temp(1); sysfs_temp(2); @@ -503,7 +443,8 @@ sysfs_temp(3); sysfs_temp(4); /* VID */ -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, + char *buf) { struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); @@ -512,25 +453,26 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); /* VRM */ -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, + char *buf) { struct asb100_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct asb100_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - data->vrm = val; + struct asb100_data *data = dev_get_drvdata(dev); + data->vrm = simple_strtoul(buf, NULL, 10); return count; } /* Alarms */ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, + char *buf) { struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%u\n", data->alarms); @@ -538,14 +480,35 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13); + /* 1 PWM */ -static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, + char *buf) { struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", ASB100_PWM_FROM_REG(data->pwm & 0x0f)); } -static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct asb100_data *data = i2c_get_clientdata(client); @@ -559,14 +522,15 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const return count; } -static ssize_t show_pwm_enable1(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_pwm_enable1(struct device *dev, + struct device_attribute *attr, char *buf) { struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", (data->pwm & 0x80) ? 1 : 0); } -static ssize_t set_pwm_enable1(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t set_pwm_enable1(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct asb100_data *data = i2c_get_clientdata(client); @@ -585,50 +549,62 @@ static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable1, set_pwm_enable1); static struct attribute *asb100_attributes[] = { - &dev_attr_in0_input.attr, - &dev_attr_in0_min.attr, - &dev_attr_in0_max.attr, - &dev_attr_in1_input.attr, - &dev_attr_in1_min.attr, - &dev_attr_in1_max.attr, - &dev_attr_in2_input.attr, - &dev_attr_in2_min.attr, - &dev_attr_in2_max.attr, - &dev_attr_in3_input.attr, - &dev_attr_in3_min.attr, - &dev_attr_in3_max.attr, - &dev_attr_in4_input.attr, - &dev_attr_in4_min.attr, - &dev_attr_in4_max.attr, - &dev_attr_in5_input.attr, - &dev_attr_in5_min.attr, - &dev_attr_in5_max.attr, - &dev_attr_in6_input.attr, - &dev_attr_in6_min.attr, - &dev_attr_in6_max.attr, - - &dev_attr_fan1_input.attr, - &dev_attr_fan1_min.attr, - &dev_attr_fan1_div.attr, - &dev_attr_fan2_input.attr, - &dev_attr_fan2_min.attr, - &dev_attr_fan2_div.attr, - &dev_attr_fan3_input.attr, - &dev_attr_fan3_min.attr, - &dev_attr_fan3_div.attr, - - &dev_attr_temp1_input.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_max_hyst.attr, - &dev_attr_temp2_input.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp2_max_hyst.attr, - &dev_attr_temp3_input.attr, - &dev_attr_temp3_max.attr, - &dev_attr_temp3_max_hyst.attr, - &dev_attr_temp4_input.attr, - &dev_attr_temp4_max.attr, - &dev_attr_temp4_max_hyst.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan3_div.dev_attr.attr, + + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp4_max.dev_attr.attr, + &sensor_dev_attr_temp4_max_hyst.dev_attr.attr, + + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, &dev_attr_cpu0_vid.attr, &dev_attr_vrm.attr, @@ -656,10 +632,10 @@ static int asb100_attach_adapter(struct i2c_adapter *adapter) } static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, - int kind, struct i2c_client *new_client) + int kind, struct i2c_client *client) { int i, id, err; - struct asb100_data *data = i2c_get_clientdata(new_client); + struct asb100_data *data = i2c_get_clientdata(client); data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!(data->lm75[0])) { @@ -679,26 +655,26 @@ static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, for (i = 2; i <= 3; i++) { if (force_subclients[i] < 0x48 || force_subclients[i] > 0x4f) { - dev_err(&new_client->dev, "invalid subclient " + dev_err(&client->dev, "invalid subclient " "address %d; must be 0x48-0x4f\n", force_subclients[i]); err = -ENODEV; goto ERROR_SC_2; } } - asb100_write_value(new_client, ASB100_REG_I2C_SUBADDR, + asb100_write_value(client, ASB100_REG_I2C_SUBADDR, (force_subclients[2] & 0x07) | - ((force_subclients[3] & 0x07) <<4)); + ((force_subclients[3] & 0x07) << 4)); data->lm75[0]->addr = force_subclients[2]; data->lm75[1]->addr = force_subclients[3]; } else { - int val = asb100_read_value(new_client, ASB100_REG_I2C_SUBADDR); + int val = asb100_read_value(client, ASB100_REG_I2C_SUBADDR); data->lm75[0]->addr = 0x48 + (val & 0x07); data->lm75[1]->addr = 0x48 + ((val >> 4) & 0x07); } - if(data->lm75[0]->addr == data->lm75[1]->addr) { - dev_err(&new_client->dev, "duplicate addresses 0x%x " + if (data->lm75[0]->addr == data->lm75[1]->addr) { + dev_err(&client->dev, "duplicate addresses 0x%x " "for subclients\n", data->lm75[0]->addr); err = -ENODEV; goto ERROR_SC_2; @@ -708,18 +684,17 @@ static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, i2c_set_clientdata(data->lm75[i], NULL); data->lm75[i]->adapter = adapter; data->lm75[i]->driver = &asb100_driver; - data->lm75[i]->flags = 0; strlcpy(data->lm75[i]->name, "asb100 subclient", I2C_NAME_SIZE); } if ((err = i2c_attach_client(data->lm75[0]))) { - dev_err(&new_client->dev, "subclient %d registration " + dev_err(&client->dev, "subclient %d registration " "at address 0x%x failed.\n", i, data->lm75[0]->addr); goto ERROR_SC_2; } if ((err = i2c_attach_client(data->lm75[1]))) { - dev_err(&new_client->dev, "subclient %d registration " + dev_err(&client->dev, "subclient %d registration " "at address 0x%x failed.\n", i, data->lm75[1]->addr); goto ERROR_SC_3; } @@ -740,7 +715,7 @@ ERROR_SC_0: static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) { int err; - struct i2c_client *new_client; + struct i2c_client *client; struct asb100_data *data; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { @@ -760,13 +735,12 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) goto ERROR0; } - new_client = &data->client; + client = &data->client; mutex_init(&data->lock); - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &asb100_driver; - new_client->flags = 0; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &asb100_driver; /* Now, we do the remaining detection. */ @@ -776,15 +750,15 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) bank. */ if (kind < 0) { - int val1 = asb100_read_value(new_client, ASB100_REG_BANK); - int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); + int val1 = asb100_read_value(client, ASB100_REG_BANK); + int val2 = asb100_read_value(client, ASB100_REG_CHIPMAN); /* If we're in bank 0 */ - if ( (!(val1 & 0x07)) && + if ((!(val1 & 0x07)) && /* Check for ASB100 ID (low byte) */ - ( ((!(val1 & 0x80)) && (val2 != 0x94)) || + (((!(val1 & 0x80)) && (val2 != 0x94)) || /* Check for ASB100 ID (high byte ) */ - ((val1 & 0x80) && (val2 != 0x06)) ) ) { + ((val1 & 0x80) && (val2 != 0x06)))) { pr_debug("asb100.o: detect failed, " "bad chip id 0x%02x!\n", val2); err = -ENODEV; @@ -795,19 +769,19 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) /* We have either had a force parameter, or we have already detected Winbond. Put it now into bank 0 and Vendor ID High Byte */ - asb100_write_value(new_client, ASB100_REG_BANK, - (asb100_read_value(new_client, ASB100_REG_BANK) & 0x78) | 0x80); + asb100_write_value(client, ASB100_REG_BANK, + (asb100_read_value(client, ASB100_REG_BANK) & 0x78) | 0x80); /* Determine the chip type. */ if (kind <= 0) { - int val1 = asb100_read_value(new_client, ASB100_REG_WCHIPID); - int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); + int val1 = asb100_read_value(client, ASB100_REG_WCHIPID); + int val2 = asb100_read_value(client, ASB100_REG_CHIPMAN); if ((val1 == 0x31) && (val2 == 0x06)) kind = asb100; else { if (kind == 0) - dev_warn(&new_client->dev, "ignoring " + dev_warn(&client->dev, "ignoring " "'force' parameter for unknown chip " "at adapter %d, address 0x%02x.\n", i2c_adapter_id(adapter), address); @@ -817,34 +791,32 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) } /* Fill in remaining client fields and put it into the global list */ - strlcpy(new_client->name, "asb100", I2C_NAME_SIZE); + strlcpy(client->name, "asb100", I2C_NAME_SIZE); data->type = kind; - - data->valid = 0; mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto ERROR1; /* Attach secondary lm75 clients */ if ((err = asb100_detect_subclients(adapter, address, kind, - new_client))) + client))) goto ERROR2; /* Initialize the chip */ - asb100_init_client(new_client); + asb100_init_client(client); /* A few vars need to be filled upon startup */ - data->fan_min[0] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(0)); - data->fan_min[1] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(1)); - data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2)); + data->fan_min[0] = asb100_read_value(client, ASB100_REG_FAN_MIN(0)); + data->fan_min[1] = asb100_read_value(client, ASB100_REG_FAN_MIN(1)); + data->fan_min[2] = asb100_read_value(client, ASB100_REG_FAN_MIN(2)); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &asb100_group))) + if ((err = sysfs_create_group(&client->dev.kobj, &asb100_group))) goto ERROR3; - data->hwmon_dev = hwmon_device_register(&new_client->dev); + data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto ERROR4; @@ -853,14 +825,14 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) return 0; ERROR4: - sysfs_remove_group(&new_client->dev.kobj, &asb100_group); + sysfs_remove_group(&client->dev.kobj, &asb100_group); ERROR3: i2c_detach_client(data->lm75[1]); i2c_detach_client(data->lm75[0]); kfree(data->lm75[1]); kfree(data->lm75[0]); ERROR2: - i2c_detach_client(new_client); + i2c_detach_client(client); ERROR1: kfree(data); ERROR0: @@ -916,17 +888,17 @@ static int asb100_read_value(struct i2c_client *client, u16 reg) /* convert from ISA to LM75 I2C addresses */ switch (reg & 0xff) { case 0x50: /* TEMP */ - res = swab16(i2c_smbus_read_word_data (cl, 0)); + res = swab16(i2c_smbus_read_word_data(cl, 0)); break; case 0x52: /* CONFIG */ res = i2c_smbus_read_byte_data(cl, 1); break; case 0x53: /* HYST */ - res = swab16(i2c_smbus_read_word_data (cl, 2)); + res = swab16(i2c_smbus_read_word_data(cl, 2)); break; case 0x55: /* MAX */ default: - res = swab16(i2c_smbus_read_word_data (cl, 3)); + res = swab16(i2c_smbus_read_word_data(cl, 3)); break; } } @@ -989,7 +961,7 @@ static void asb100_init_client(struct i2c_client *client) vid = vid_from_reg(vid, data->vrm); /* Start monitoring */ - asb100_write_value(client, ASB100_REG_CONFIG, + asb100_write_value(client, ASB100_REG_CONFIG, (asb100_read_value(client, ASB100_REG_CONFIG) & 0xf7) | 0x01); } @@ -1078,4 +1050,3 @@ MODULE_LICENSE("GPL"); module_init(asb100_init); module_exit(asb100_exit); - diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index a878c98e252e..ddddd9f34c19 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -44,6 +44,10 @@ static int force_start; module_param(force_start, bool, 0); MODULE_PARM_DESC(force_start, "Force the chip to start monitoring inputs"); +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + /* Addresses to scan */ static unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END}; @@ -279,14 +283,21 @@ static inline int TEMP_HYST_TO_REG(int val, int ix, int reg) /* Fan input RPM */ static inline int FAN_FROM_REG(int reg, int tpc) { - return (reg == 0 || reg == 0xffff) ? 0 : - (tpc == 0) ? 90000 * 60 / reg : tpc * reg; + if (tpc) { + return tpc * reg; + } else { + return (reg == 0 || reg == 0xffff) ? 0 : 90000 * 60 / reg; + } } static inline int FAN_TO_REG(int val, int tpc) { - return SENSORS_LIMIT((tpc == 0) ? 90000 * 60 / val : val / tpc, - 0, 0xffff); + if (tpc) { + return SENSORS_LIMIT(val / tpc, 0, 0xffff); + } else { + return (val <= 0) ? 0xffff : + SENSORS_LIMIT(90000 * 60 / val, 0, 0xfffe); + } } /* Fan TPC (tach pulse count) @@ -2019,7 +2030,7 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data) /* Check device ID * The DME1737 can return either 0x78 or 0x77 as its device ID. */ - reg = dme1737_sio_inb(sio_cip, 0x20); + reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20); if (!(reg == 0x77 || reg == 0x78)) { err = -ENODEV; goto exit; @@ -2191,7 +2202,7 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr) /* Check device ID * We currently know about SCH3112 (0x7c), SCH3114 (0x7d), and * SCH3116 (0x7f). */ - reg = dme1737_sio_inb(sio_cip, 0x20); + reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20); if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) { err = -ENODEV; goto exit; diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index b7bd000b130f..3f5163de13c1 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -94,7 +94,6 @@ static struct i2c_driver ds1621_driver = { .driver = { .name = "ds1621", }, - .id = I2C_DRIVERID_DS1621, .attach_adapter = ds1621_attach_adapter, .detach_client = ds1621_detach_client, }; diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 5d9d5cc816a2..7a14a2dbb752 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -41,6 +41,10 @@ #include <linux/ioport.h> #include <asm/io.h> +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + static struct platform_device *pdev; #define DRVNAME "f71805f" @@ -1497,7 +1501,7 @@ static int __init f71805f_find(int sioaddr, unsigned short *address, if (devid != SIO_FINTEK_ID) goto exit; - devid = superio_inw(sioaddr, SIO_REG_DEVID); + devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID); switch (devid) { case SIO_F71805F_ID: sio_data->kind = f71805f; diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 6db74434a02e..cbeb4984b5c7 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -74,6 +74,10 @@ #define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */ +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + static struct platform_device *f71882fg_pdev = NULL; /* Super-I/O Function prototypes */ @@ -843,7 +847,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address) goto exit; } - devid = superio_inw(sioaddr, SIO_REG_DEVID); + devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID); if (devid != SIO_F71882_ID) { printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n"); goto exit; diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c index e67c36953b2d..721c70177b17 100644 --- a/drivers/hwmon/fscher.c +++ b/drivers/hwmon/fscher.c @@ -123,7 +123,6 @@ static struct i2c_driver fscher_driver = { .driver = { .name = "fscher", }, - .id = I2C_DRIVERID_FSCHER, .attach_adapter = fscher_attach_adapter, .detach_client = fscher_detach_client, }; diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index 63a4df0580db..b7c9eef0f928 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -41,6 +41,7 @@ #include <linux/err.h> #include <linux/mutex.h> #include <linux/sysfs.h> +#include <linux/dmi.h> /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; @@ -133,7 +134,7 @@ static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { { 0x71, 0x81, 0x91 }, /* her */ { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ { 0x71, 0x81, 0x91 }, /* hrc */ - { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /*Â hmd */ + { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ }; /* temperature high limit registers, FSC does not document these. Proven to be @@ -146,7 +147,7 @@ static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = { { 0x76, 0x86, 0x96 }, /* her */ { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ { 0x76, 0x86, 0x96 }, /* hrc */ - { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /*Â hmd */ + { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ }; /* These were found through experimenting with an fscher, currently they are @@ -210,6 +211,13 @@ struct fschmd_data { u8 fan_ripple[6]; /* divider for rps */ }; +/* Global variables to hold information read from special DMI tables, which are + available on FSC machines with an fscher or later chip. */ +static int dmi_mult[3] = { 490, 200, 100 }; +static int dmi_offset[3] = { 0, 0, 0 }; +static int dmi_vref = -1; + + /* * Sysfs attr show / store functions */ @@ -221,8 +229,13 @@ static ssize_t show_in_value(struct device *dev, int index = to_sensor_dev_attr(devattr)->index; struct fschmd_data *data = fschmd_update_device(dev); - return sprintf(buf, "%d\n", (data->volt[index] * - max_reading[index] + 128) / 255); + /* fscher / fschrc - 1 as data->kind is an array index, not a chips */ + if (data->kind == (fscher - 1) || data->kind >= (fschrc - 1)) + return sprintf(buf, "%d\n", (data->volt[index] * dmi_vref * + dmi_mult[index]) / 255 + dmi_offset[index]); + else + return sprintf(buf, "%d\n", (data->volt[index] * + max_reading[index] + 128) / 255); } @@ -525,6 +538,68 @@ static struct sensor_device_attribute fschmd_fan_attr[] = { * Real code */ +/* DMI decode routine to read voltage scaling factors from special DMI tables, + which are available on FSC machines with an fscher or later chip. */ +static void fschmd_dmi_decode(const struct dmi_header *header) +{ + int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0; + + /* dmi code ugliness, we get passed the address of the contents of + a complete DMI record, but in the form of a dmi_header pointer, in + reality this address holds header->length bytes of which the header + are the first 4 bytes */ + u8 *dmi_data = (u8 *)header; + + /* We are looking for OEM-specific type 185 */ + if (header->type != 185) + return; + + /* we are looking for what Siemens calls "subtype" 19, the subtype + is stored in byte 5 of the dmi block */ + if (header->length < 5 || dmi_data[4] != 19) + return; + + /* After the subtype comes 1 unknown byte and then blocks of 5 bytes, + consisting of what Siemens calls an "Entity" number, followed by + 2 16-bit words in LSB first order */ + for (i = 6; (i + 4) < header->length; i += 5) { + /* entity 1 - 3: voltage multiplier and offset */ + if (dmi_data[i] >= 1 && dmi_data[i] <= 3) { + /* Our in sensors order and the DMI order differ */ + const int shuffle[3] = { 1, 0, 2 }; + int in = shuffle[dmi_data[i] - 1]; + + /* Check for twice the same entity */ + if (found & (1 << in)) + return; + + mult[in] = dmi_data[i + 1] | (dmi_data[i + 2] << 8); + offset[in] = dmi_data[i + 3] | (dmi_data[i + 4] << 8); + + found |= 1 << in; + } + + /* entity 7: reference voltage */ + if (dmi_data[i] == 7) { + /* Check for twice the same entity */ + if (found & 0x08) + return; + + vref = dmi_data[i + 1] | (dmi_data[i + 2] << 8); + + found |= 0x08; + } + } + + if (found == 0x0F) { + for (i = 0; i < 3; i++) { + dmi_mult[i] = mult[i] * 10; + dmi_offset[i] = offset[i] * 10; + } + dmi_vref = vref; + } +} + static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *client; @@ -586,6 +661,17 @@ static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind) data->temp_max[2] = 50 + 128; } + /* Read the special DMI table for fscher and newer chips */ + if (kind == fscher || kind >= fschrc) { + dmi_walk(fschmd_dmi_decode); + if (dmi_vref == -1) { + printk(KERN_WARNING FSCHMD_NAME + ": Couldn't get voltage scaling factors from " + "BIOS DMI table, using builtin defaults\n"); + dmi_vref = 33; + } + } + /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ data->kind = kind - 1; strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE); diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c index 92c9703d0ac0..2f1075323a1e 100644 --- a/drivers/hwmon/fscpos.c +++ b/drivers/hwmon/fscpos.c @@ -105,7 +105,6 @@ static struct i2c_driver fscpos_driver = { .driver = { .name = "fscpos", }, - .id = I2C_DRIVERID_FSCPOS, .attach_adapter = fscpos_attach_adapter, .detach_client = fscpos_detach_client, }; diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index bb58d9866a37..3b1ac48fce23 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -30,10 +30,6 @@ * We did not keep that part of the original driver in the Linux 2.6 * version, since it was making the driver significantly more complex * with no real benefit. - * - * History: - * 2004-01-28 Original port. (Hong-Gunn Chew) - * 2004-01-31 Code review and approval. (Jean Delvare) */ #include <linux/module.h> @@ -42,6 +38,7 @@ #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> #include <linux/sysfs.h> @@ -99,10 +96,10 @@ static inline u8 FAN_TO_REG(long rpm, int div) long rpmdiv; if (rpm == 0) return 0; - rpmdiv = SENSORS_LIMIT(rpm, 1, 1920000) * div; - return SENSORS_LIMIT((960000 + rpmdiv / 2) / rpmdiv, 1, 255); + rpmdiv = SENSORS_LIMIT(rpm, 1, 960000) * div; + return SENSORS_LIMIT((480000 + rpmdiv / 2) / rpmdiv, 1, 255); } -#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (960000/((val)*(div)))) +#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val)*(div)))) #define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) #define IN_FROM_REG(val) ((val)*19) @@ -110,7 +107,6 @@ static inline u8 FAN_TO_REG(long rpm, int div) #define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) #define VDD_FROM_REG(val) (((val)*95+2)/4) -#define DIV_TO_REG(val) ((val)==4?2:(val)==2?1:(val)==1?0:3) #define DIV_FROM_REG(val) (1 << (val)) #define BEEP_MASK_TO_REG(val) ((val) & 0x7f & data->alarm_mask) @@ -129,7 +125,6 @@ struct gl518_data { u8 voltage_in[4]; /* Register values; [0] = VDD */ u8 voltage_min[4]; /* Register values; [0] = VDD */ u8 voltage_max[4]; /* Register values; [0] = VDD */ - u8 iter_voltage_in[4]; /* Register values; [0] = VDD */ u8 fan_in[2]; u8 fan_min[2]; u8 fan_div[2]; /* Register encoding, shifted right */ @@ -138,7 +133,7 @@ struct gl518_data { u8 temp_max; /* Register values */ u8 temp_hyst; /* Register values */ u8 alarms; /* Register value */ - u8 alarm_mask; /* Register value */ + u8 alarm_mask; u8 beep_mask; /* Register value */ u8 beep_enable; /* Boolean */ }; @@ -156,7 +151,6 @@ static struct i2c_driver gl518_driver = { .driver = { .name = "gl518sm", }, - .id = I2C_DRIVERID_GL518, .attach_adapter = gl518_attach_adapter, .detach_client = gl518_detach_client, }; @@ -172,24 +166,10 @@ static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", type##_FROM_REG(data->value)); \ } -#define show_fan(suffix, value, index) \ -static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct gl518_data *data = gl518_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[index], \ - DIV_FROM_REG(data->fan_div[index]))); \ -} - show(TEMP, temp_input1, temp_in); show(TEMP, temp_max1, temp_max); show(TEMP, temp_hyst1, temp_hyst); show(BOOL, fan_auto1, fan_auto1); -show_fan(fan_input1, fan_in, 0); -show_fan(fan_input2, fan_in, 1); -show_fan(fan_min1, fan_min, 0); -show_fan(fan_min2, fan_min, 1); -show(DIV, fan_div1, fan_div[0]); -show(DIV, fan_div2, fan_div[1]); show(VDD, in_input0, voltage_in[0]); show(IN, in_input1, voltage_in[1]); show(IN, in_input2, voltage_in[2]); @@ -206,6 +186,32 @@ show(RAW, alarms, alarms); show(BOOL, beep_enable, beep_enable); show(BEEP_MASK, beep_mask, beep_mask); +static ssize_t show_fan_input(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct gl518_data *data = gl518_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_in[nr], + DIV_FROM_REG(data->fan_div[nr]))); +} + +static ssize_t show_fan_min(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct gl518_data *data = gl518_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr]))); +} + +static ssize_t show_fan_div(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct gl518_data *data = gl518_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); +} + #define set(type, suffix, value, reg) \ static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ @@ -247,8 +253,6 @@ static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, c set(TEMP, temp_max1, temp_max, GL518_REG_TEMP_MAX); set(TEMP, temp_hyst1, temp_hyst, GL518_REG_TEMP_HYST); set_bits(BOOL, fan_auto1, fan_auto1, GL518_REG_MISC, 0x08, 3); -set_bits(DIV, fan_div1, fan_div[0], GL518_REG_MISC, 0xc0, 6); -set_bits(DIV, fan_div2, fan_div[1], GL518_REG_MISC, 0x30, 4); set_low(VDD, in_min0, voltage_min[0], GL518_REG_VDD_LIMIT); set_low(IN, in_min1, voltage_min[1], GL518_REG_VIN1_LIMIT); set_low(IN, in_min2, voltage_min[2], GL518_REG_VIN2_LIMIT); @@ -260,25 +264,27 @@ set_high(IN, in_max3, voltage_max[3], GL518_REG_VIN3_LIMIT); set_bits(BOOL, beep_enable, beep_enable, GL518_REG_CONF, 0x04, 2); set(BEEP_MASK, beep_mask, beep_mask, GL518_REG_ALARM); -static ssize_t set_fan_min1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct gl518_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; int regvalue; unsigned long val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT); - data->fan_min[0] = FAN_TO_REG(val, - DIV_FROM_REG(data->fan_div[0])); - regvalue = (regvalue & 0x00ff) | (data->fan_min[0] << 8); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + regvalue = (regvalue & (0xff << (8 * nr))) + | (data->fan_min[nr] << (8 * (1 - nr))); gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue); data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); - if (data->fan_min[0] == 0) - data->alarm_mask &= ~0x20; + if (data->fan_min[nr] == 0) + data->alarm_mask &= ~(0x20 << nr); else - data->alarm_mask |= 0x20; + data->alarm_mask |= (0x20 << nr); data->beep_mask &= data->alarm_mask; gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); @@ -286,28 +292,32 @@ static ssize_t set_fan_min1(struct device *dev, struct device_attribute *attr, c return count; } -static ssize_t set_fan_min2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct gl518_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; int regvalue; unsigned long val = simple_strtoul(buf, NULL, 10); - mutex_lock(&data->update_lock); - regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT); - data->fan_min[1] = FAN_TO_REG(val, - DIV_FROM_REG(data->fan_div[1])); - regvalue = (regvalue & 0xff00) | data->fan_min[1]; - gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue); - - data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); - if (data->fan_min[1] == 0) - data->alarm_mask &= ~0x40; - else - data->alarm_mask |= 0x40; - data->beep_mask &= data->alarm_mask; - gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); + switch (val) { + case 1: val = 0; break; + case 2: val = 1; break; + case 4: val = 2; break; + case 8: val = 3; break; + default: + dev_err(dev, "Invalid fan clock divider %lu, choose one " + "of 1, 2, 4 or 8\n", val); + return -EINVAL; + } + mutex_lock(&data->update_lock); + regvalue = gl518_read_value(client, GL518_REG_MISC); + data->fan_div[nr] = val; + regvalue = (regvalue & ~(0xc0 >> (2 * nr))) + | (data->fan_div[nr] << (6 - 2 * nr)); + gl518_write_value(client, GL518_REG_MISC, regvalue); mutex_unlock(&data->update_lock); return count; } @@ -317,12 +327,16 @@ static DEVICE_ATTR(temp1_max, S_IWUSR|S_IRUGO, show_temp_max1, set_temp_max1); static DEVICE_ATTR(temp1_max_hyst, S_IWUSR|S_IRUGO, show_temp_hyst1, set_temp_hyst1); static DEVICE_ATTR(fan1_auto, S_IWUSR|S_IRUGO, show_fan_auto1, set_fan_auto1); -static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL); -static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL); -static DEVICE_ATTR(fan1_min, S_IWUSR|S_IRUGO, show_fan_min1, set_fan_min1); -static DEVICE_ATTR(fan2_min, S_IWUSR|S_IRUGO, show_fan_min2, set_fan_min2); -static DEVICE_ATTR(fan1_div, S_IWUSR|S_IRUGO, show_fan_div1, set_fan_div1); -static DEVICE_ATTR(fan2_div, S_IWUSR|S_IRUGO, show_fan_div2, set_fan_div2); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1); +static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR|S_IRUGO, + show_fan_min, set_fan_min, 0); +static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR|S_IRUGO, + show_fan_min, set_fan_min, 1); +static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR|S_IRUGO, + show_fan_div, set_fan_div, 0); +static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR|S_IRUGO, + show_fan_div, set_fan_div, 1); static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL); static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL); static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL); @@ -341,10 +355,62 @@ static DEVICE_ATTR(beep_enable, S_IWUSR|S_IRUGO, static DEVICE_ATTR(beep_mask, S_IWUSR|S_IRUGO, show_beep_mask, set_beep_mask); +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct gl518_data *data = gl518_update_device(dev); + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} + +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 6); + +static ssize_t show_beep(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct gl518_data *data = gl518_update_device(dev); + return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1); +} + +static ssize_t set_beep(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gl518_data *data = i2c_get_clientdata(client); + int bitnr = to_sensor_dev_attr(attr)->index; + unsigned long bit; + + bit = simple_strtoul(buf, NULL, 10); + if (bit & ~1) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); + if (bit) + data->beep_mask |= (1 << bitnr); + else + data->beep_mask &= ~(1 << bitnr); + gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); + mutex_unlock(&data->update_lock); + return count; +} + +static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 0); +static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 1); +static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 2); +static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 3); +static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 4); +static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 5); +static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 6); + static struct attribute *gl518_attributes[] = { - &dev_attr_in0_input.attr, - &dev_attr_in1_input.attr, - &dev_attr_in2_input.attr, &dev_attr_in3_input.attr, &dev_attr_in0_min.attr, &dev_attr_in1_min.attr, @@ -354,18 +420,32 @@ static struct attribute *gl518_attributes[] = { &dev_attr_in1_max.attr, &dev_attr_in2_max.attr, &dev_attr_in3_max.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + &sensor_dev_attr_in0_beep.dev_attr.attr, + &sensor_dev_attr_in1_beep.dev_attr.attr, + &sensor_dev_attr_in2_beep.dev_attr.attr, + &sensor_dev_attr_in3_beep.dev_attr.attr, &dev_attr_fan1_auto.attr, - &dev_attr_fan1_input.attr, - &dev_attr_fan2_input.attr, - &dev_attr_fan1_min.attr, - &dev_attr_fan2_min.attr, - &dev_attr_fan1_div.attr, - &dev_attr_fan2_div.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_beep.dev_attr.attr, + &sensor_dev_attr_fan2_beep.dev_attr.attr, &dev_attr_temp1_input.attr, &dev_attr_temp1_max.attr, &dev_attr_temp1_max_hyst.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_beep.dev_attr.attr, &dev_attr_alarms.attr, &dev_attr_beep_enable.attr, @@ -377,6 +457,17 @@ static const struct attribute_group gl518_group = { .attrs = gl518_attributes, }; +static struct attribute *gl518_attributes_r80[] = { + &dev_attr_in0_input.attr, + &dev_attr_in1_input.attr, + &dev_attr_in2_input.attr, + NULL +}; + +static const struct attribute_group gl518_group_r80 = { + .attrs = gl518_attributes_r80, +}; + /* * Real code */ @@ -391,7 +482,7 @@ static int gl518_attach_adapter(struct i2c_adapter *adapter) static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) { int i; - struct i2c_client *new_client; + struct i2c_client *client; struct gl518_data *data; int err = 0; @@ -408,25 +499,24 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) goto exit; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); + client = &data->client; + i2c_set_clientdata(client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &gl518_driver; - new_client->flags = 0; + client->addr = address; + client->adapter = adapter; + client->driver = &gl518_driver; /* Now, we do the remaining detection. */ if (kind < 0) { - if ((gl518_read_value(new_client, GL518_REG_CHIP_ID) != 0x80) - || (gl518_read_value(new_client, GL518_REG_CONF) & 0x80)) + if ((gl518_read_value(client, GL518_REG_CHIP_ID) != 0x80) + || (gl518_read_value(client, GL518_REG_CONF) & 0x80)) goto exit_free; } /* Determine the chip type. */ if (kind <= 0) { - i = gl518_read_value(new_client, GL518_REG_REVISION); + i = gl518_read_value(client, GL518_REG_REVISION); if (i == 0x00) { kind = gl518sm_r00; } else if (i == 0x80) { @@ -442,25 +532,27 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) } /* Fill in the remaining client fields */ - strlcpy(new_client->name, "gl518sm", I2C_NAME_SIZE); + strlcpy(client->name, "gl518sm", I2C_NAME_SIZE); data->type = kind; - data->valid = 0; mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto exit_free; /* Initialize the GL518SM chip */ data->alarm_mask = 0xff; - data->voltage_in[0]=data->voltage_in[1]=data->voltage_in[2]=0; - gl518_init_client((struct i2c_client *) new_client); + gl518_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &gl518_group))) + if ((err = sysfs_create_group(&client->dev.kobj, &gl518_group))) goto exit_detach; + if (data->type == gl518sm_r80) + if ((err = sysfs_create_group(&client->dev.kobj, + &gl518_group_r80))) + goto exit_remove_files; - data->hwmon_dev = hwmon_device_register(&new_client->dev); + data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; @@ -469,9 +561,11 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_remove_files: - sysfs_remove_group(&new_client->dev.kobj, &gl518_group); + sysfs_remove_group(&client->dev.kobj, &gl518_group); + if (data->type == gl518sm_r80) + sysfs_remove_group(&client->dev.kobj, &gl518_group_r80); exit_detach: - i2c_detach_client(new_client); + i2c_detach_client(client); exit_free: kfree(data); exit: @@ -504,6 +598,8 @@ static int gl518_detach_client(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &gl518_group); + if (data->type == gl518sm_r80) + sysfs_remove_group(&client->dev.kobj, &gl518_group_r80); if ((err = i2c_detach_client(client))) return err; @@ -512,9 +608,9 @@ static int gl518_detach_client(struct i2c_client *client) return 0; } -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized +/* Registers 0x07 to 0x0c are word-sized, others are byte-sized GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ + the SMBus standard. */ static int gl518_read_value(struct i2c_client *client, u8 reg) { if ((reg >= 0x07) && (reg <= 0x0c)) @@ -523,9 +619,6 @@ static int gl518_read_value(struct i2c_client *client, u8 reg) return i2c_smbus_read_byte_data(client, reg); } -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) { if ((reg >= 0x07) && (reg <= 0x0c)) diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index 2d39d8fc2389..03ecdc334764 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -27,6 +27,7 @@ #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/hwmon-vid.h> #include <linux/err.h> #include <linux/mutex.h> @@ -43,9 +44,9 @@ static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; /* Insmod parameters */ I2C_CLIENT_INSMOD_1(gl520sm); -/* Many GL520 constants specified below +/* Many GL520 constants specified below One of the inputs can be configured as either temp or voltage. -That's why _TEMP2 and _IN4 access the same register +That's why _TEMP2 and _IN4 access the same register */ /* The GL520 registers */ @@ -56,37 +57,14 @@ That's why _TEMP2 and _IN4 access the same register #define GL520_REG_VID_INPUT 0x02 -#define GL520_REG_IN0_INPUT 0x15 -#define GL520_REG_IN0_LIMIT 0x0c -#define GL520_REG_IN0_MIN GL520_REG_IN0_LIMIT -#define GL520_REG_IN0_MAX GL520_REG_IN0_LIMIT +static const u8 GL520_REG_IN_INPUT[] = { 0x15, 0x14, 0x13, 0x0d, 0x0e }; +static const u8 GL520_REG_IN_LIMIT[] = { 0x0c, 0x09, 0x0a, 0x0b }; +static const u8 GL520_REG_IN_MIN[] = { 0x0c, 0x09, 0x0a, 0x0b, 0x18 }; +static const u8 GL520_REG_IN_MAX[] = { 0x0c, 0x09, 0x0a, 0x0b, 0x17 }; -#define GL520_REG_IN1_INPUT 0x14 -#define GL520_REG_IN1_LIMIT 0x09 -#define GL520_REG_IN1_MIN GL520_REG_IN1_LIMIT -#define GL520_REG_IN1_MAX GL520_REG_IN1_LIMIT - -#define GL520_REG_IN2_INPUT 0x13 -#define GL520_REG_IN2_LIMIT 0x0a -#define GL520_REG_IN2_MIN GL520_REG_IN2_LIMIT -#define GL520_REG_IN2_MAX GL520_REG_IN2_LIMIT - -#define GL520_REG_IN3_INPUT 0x0d -#define GL520_REG_IN3_LIMIT 0x0b -#define GL520_REG_IN3_MIN GL520_REG_IN3_LIMIT -#define GL520_REG_IN3_MAX GL520_REG_IN3_LIMIT - -#define GL520_REG_IN4_INPUT 0x0e -#define GL520_REG_IN4_MAX 0x17 -#define GL520_REG_IN4_MIN 0x18 - -#define GL520_REG_TEMP1_INPUT 0x04 -#define GL520_REG_TEMP1_MAX 0x05 -#define GL520_REG_TEMP1_MAX_HYST 0x06 - -#define GL520_REG_TEMP2_INPUT 0x0e -#define GL520_REG_TEMP2_MAX 0x17 -#define GL520_REG_TEMP2_MAX_HYST 0x18 +static const u8 GL520_REG_TEMP_INPUT[] = { 0x04, 0x0e }; +static const u8 GL520_REG_TEMP_MAX[] = { 0x05, 0x17 }; +static const u8 GL520_REG_TEMP_MAX_HYST[] = { 0x06, 0x18 }; #define GL520_REG_FAN_INPUT 0x07 #define GL520_REG_FAN_MIN 0x08 @@ -114,7 +92,6 @@ static struct i2c_driver gl520_driver = { .driver = { .name = "gl520sm", }, - .id = I2C_DRIVERID_GL520, .attach_adapter = gl520_attach_adapter, .detach_client = gl520_detach_client, }; @@ -150,93 +127,13 @@ struct gl520_data { * Sysfs stuff */ -#define sysfs_r(type, n, item, reg) \ -static ssize_t get_##type##item (struct gl520_data *, char *, int); \ -static ssize_t get_##type##n##item (struct device *, struct device_attribute *attr, char *); \ -static ssize_t get_##type##n##item (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct gl520_data *data = gl520_update_device(dev); \ - return get_##type##item(data, buf, (n)); \ -} - -#define sysfs_w(type, n, item, reg) \ -static ssize_t set_##type##item (struct i2c_client *, struct gl520_data *, const char *, size_t, int, int); \ -static ssize_t set_##type##n##item (struct device *, struct device_attribute *attr, const char *, size_t); \ -static ssize_t set_##type##n##item (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct gl520_data *data = i2c_get_clientdata(client); \ - return set_##type##item(client, data, buf, count, (n), reg); \ -} - -#define sysfs_rw_n(type, n, item, reg) \ -sysfs_r(type, n, item, reg) \ -sysfs_w(type, n, item, reg) \ -static DEVICE_ATTR(type##n##item, S_IRUGO | S_IWUSR, get_##type##n##item, set_##type##n##item); - -#define sysfs_ro_n(type, n, item, reg) \ -sysfs_r(type, n, item, reg) \ -static DEVICE_ATTR(type##n##item, S_IRUGO, get_##type##n##item, NULL); - -#define sysfs_rw(type, item, reg) \ -sysfs_r(type, 0, item, reg) \ -sysfs_w(type, 0, item, reg) \ -static DEVICE_ATTR(type##item, S_IRUGO | S_IWUSR, get_##type##0##item, set_##type##0##item); - -#define sysfs_ro(type, item, reg) \ -sysfs_r(type, 0, item, reg) \ -static DEVICE_ATTR(type##item, S_IRUGO, get_##type##0##item, NULL); - - -#define sysfs_vid(n) \ -sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT) - -#define sysfs_in(n) \ -sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \ -sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \ -sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \ - -#define sysfs_fan(n) \ -sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \ -sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \ -sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV) - -#define sysfs_fan_off(n) \ -sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \ - -#define sysfs_temp(n) \ -sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \ -sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \ -sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST) - -#define sysfs_alarms() \ -sysfs_ro(alarms, , GL520_REG_ALARMS) \ -sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \ -sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK) - - -sysfs_vid(0) - -sysfs_in(0) -sysfs_in(1) -sysfs_in(2) -sysfs_in(3) -sysfs_in(4) - -sysfs_fan(1) -sysfs_fan(2) -sysfs_fan_off(1) - -sysfs_temp(1) -sysfs_temp(2) - -sysfs_alarms() - - -static ssize_t get_cpu_vid(struct gl520_data *data, char *buf, int n) +static ssize_t get_cpu_vid(struct device *dev, struct device_attribute *attr, + char *buf) { + struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); } +static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL); #define VDD_FROM_REG(val) (((val)*95+2)/4) #define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) @@ -244,8 +141,11 @@ static ssize_t get_cpu_vid(struct gl520_data *data, char *buf, int n) #define IN_FROM_REG(val) ((val)*19) #define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) -static ssize_t get_in_input(struct gl520_data *data, char *buf, int n) +static ssize_t get_in_input(struct device *dev, struct device_attribute *attr, + char *buf) { + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); u8 r = data->in_input[n]; if (n == 0) @@ -254,8 +154,11 @@ static ssize_t get_in_input(struct gl520_data *data, char *buf, int n) return sprintf(buf, "%d\n", IN_FROM_REG(r)); } -static ssize_t get_in_min(struct gl520_data *data, char *buf, int n) +static ssize_t get_in_min(struct device *dev, struct device_attribute *attr, + char *buf) { + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); u8 r = data->in_min[n]; if (n == 0) @@ -264,8 +167,11 @@ static ssize_t get_in_min(struct gl520_data *data, char *buf, int n) return sprintf(buf, "%d\n", IN_FROM_REG(r)); } -static ssize_t get_in_max(struct gl520_data *data, char *buf, int n) +static ssize_t get_in_max(struct device *dev, struct device_attribute *attr, + char *buf) { + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); u8 r = data->in_max[n]; if (n == 0) @@ -274,8 +180,12 @@ static ssize_t get_in_max(struct gl520_data *data, char *buf, int n) return sprintf(buf, "%d\n", IN_FROM_REG(r)); } -static ssize_t set_in_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int n = to_sensor_dev_attr(attr)->index; long v = simple_strtol(buf, NULL, 10); u8 r; @@ -289,16 +199,22 @@ static ssize_t set_in_min(struct i2c_client *client, struct gl520_data *data, co data->in_min[n] = r; if (n < 4) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); + gl520_write_value(client, GL520_REG_IN_MIN[n], + (gl520_read_value(client, GL520_REG_IN_MIN[n]) + & ~0xff) | r); else - gl520_write_value(client, reg, r); + gl520_write_value(client, GL520_REG_IN_MIN[n], r); mutex_unlock(&data->update_lock); return count; } -static ssize_t set_in_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int n = to_sensor_dev_attr(attr)->index; long v = simple_strtol(buf, NULL, 10); u8 r; @@ -312,57 +228,109 @@ static ssize_t set_in_max(struct i2c_client *client, struct gl520_data *data, co data->in_max[n] = r; if (n < 4) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); + gl520_write_value(client, GL520_REG_IN_MAX[n], + (gl520_read_value(client, GL520_REG_IN_MAX[n]) + & ~0xff00) | (r << 8)); else - gl520_write_value(client, reg, r); + gl520_write_value(client, GL520_REG_IN_MAX[n], r); mutex_unlock(&data->update_lock); return count; } +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, get_in_input, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, get_in_input, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, get_in_input, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, get_in_input, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, get_in_input, NULL, 4); +static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, + get_in_min, set_in_min, 0); +static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, + get_in_min, set_in_min, 1); +static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR, + get_in_min, set_in_min, 2); +static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO | S_IWUSR, + get_in_min, set_in_min, 3); +static SENSOR_DEVICE_ATTR(in4_min, S_IRUGO | S_IWUSR, + get_in_min, set_in_min, 4); +static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, + get_in_max, set_in_max, 0); +static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, + get_in_max, set_in_max, 1); +static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR, + get_in_max, set_in_max, 2); +static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO | S_IWUSR, + get_in_max, set_in_max, 3); +static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR, + get_in_max, set_in_max, 4); + #define DIV_FROM_REG(val) (1 << (val)) #define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val) << (div)))) #define FAN_TO_REG(val,div) ((val)<=0?0:SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255)); -static ssize_t get_fan_input(struct gl520_data *data, char *buf, int n) +static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr, + char *buf) { - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n - 1], data->fan_div[n - 1])); + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n], + data->fan_div[n])); } -static ssize_t get_fan_min(struct gl520_data *data, char *buf, int n) +static ssize_t get_fan_min(struct device *dev, struct device_attribute *attr, + char *buf) { - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n - 1], data->fan_div[n - 1])); + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n], + data->fan_div[n])); } -static ssize_t get_fan_div(struct gl520_data *data, char *buf, int n) +static ssize_t get_fan_div(struct device *dev, struct device_attribute *attr, + char *buf) { - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n - 1])); + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n])); } -static ssize_t get_fan_off(struct gl520_data *data, char *buf, int n) +static ssize_t get_fan_off(struct device *dev, struct device_attribute *attr, + char *buf) { + struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%d\n", data->fan_off); } -static ssize_t set_fan_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int n = to_sensor_dev_attr(attr)->index; unsigned long v = simple_strtoul(buf, NULL, 10); u8 r; mutex_lock(&data->update_lock); - r = FAN_TO_REG(v, data->fan_div[n - 1]); - data->fan_min[n - 1] = r; + r = FAN_TO_REG(v, data->fan_div[n]); + data->fan_min[n] = r; - if (n == 1) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); + if (n == 0) + gl520_write_value(client, GL520_REG_FAN_MIN, + (gl520_read_value(client, GL520_REG_FAN_MIN) + & ~0xff00) | (r << 8)); else - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); + gl520_write_value(client, GL520_REG_FAN_MIN, + (gl520_read_value(client, GL520_REG_FAN_MIN) + & ~0xff) | r); data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); - if (data->fan_min[n - 1] == 0) - data->alarm_mask &= (n == 1) ? ~0x20 : ~0x40; + if (data->fan_min[n] == 0) + data->alarm_mask &= (n == 0) ? ~0x20 : ~0x40; else - data->alarm_mask |= (n == 1) ? 0x20 : 0x40; + data->alarm_mask |= (n == 0) ? 0x20 : 0x40; data->beep_mask &= data->alarm_mask; gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); @@ -370,8 +338,12 @@ static ssize_t set_fan_min(struct i2c_client *client, struct gl520_data *data, c return count; } -static ssize_t set_fan_div(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int n = to_sensor_dev_attr(attr)->index; unsigned long v = simple_strtoul(buf, NULL, 10); u8 r; @@ -386,133 +358,282 @@ static ssize_t set_fan_div(struct i2c_client *client, struct gl520_data *data, c } mutex_lock(&data->update_lock); - data->fan_div[n - 1] = r; + data->fan_div[n] = r; - if (n == 1) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xc0) | (r << 6)); + if (n == 0) + gl520_write_value(client, GL520_REG_FAN_DIV, + (gl520_read_value(client, GL520_REG_FAN_DIV) + & ~0xc0) | (r << 6)); else - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x30) | (r << 4)); + gl520_write_value(client, GL520_REG_FAN_DIV, + (gl520_read_value(client, GL520_REG_FAN_DIV) + & ~0x30) | (r << 4)); mutex_unlock(&data->update_lock); return count; } -static ssize_t set_fan_off(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_fan_off(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); u8 r = simple_strtoul(buf, NULL, 10)?1:0; mutex_lock(&data->update_lock); data->fan_off = r; - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x0c) | (r << 2)); + gl520_write_value(client, GL520_REG_FAN_OFF, + (gl520_read_value(client, GL520_REG_FAN_OFF) + & ~0x0c) | (r << 2)); mutex_unlock(&data->update_lock); return count; } +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan_input, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan_input, NULL, 1); +static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, + get_fan_min, set_fan_min, 0); +static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR, + get_fan_min, set_fan_min, 1); +static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, + get_fan_div, set_fan_div, 0); +static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, + get_fan_div, set_fan_div, 1); +static DEVICE_ATTR(fan1_off, S_IRUGO | S_IWUSR, + get_fan_off, set_fan_off); + #define TEMP_FROM_REG(val) (((val) - 130) * 1000) #define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-500:(val)+500) / 1000)+130),0,255)) -static ssize_t get_temp_input(struct gl520_data *data, char *buf, int n) +static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr, + char *buf) { - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n - 1])); + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n])); } -static ssize_t get_temp_max(struct gl520_data *data, char *buf, int n) +static ssize_t get_temp_max(struct device *dev, struct device_attribute *attr, + char *buf) { - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n - 1])); + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n])); } -static ssize_t get_temp_max_hyst(struct gl520_data *data, char *buf, int n) +static ssize_t get_temp_max_hyst(struct device *dev, struct device_attribute + *attr, char *buf) { - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n - 1])); + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n])); } -static ssize_t set_temp_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int n = to_sensor_dev_attr(attr)->index; long v = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); - data->temp_max[n - 1] = TEMP_TO_REG(v); - gl520_write_value(client, reg, data->temp_max[n - 1]); + data->temp_max[n] = TEMP_TO_REG(v); + gl520_write_value(client, GL520_REG_TEMP_MAX[n], data->temp_max[n]); mutex_unlock(&data->update_lock); return count; } -static ssize_t set_temp_max_hyst(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_temp_max_hyst(struct device *dev, struct device_attribute + *attr, const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int n = to_sensor_dev_attr(attr)->index; long v = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); - data->temp_max_hyst[n - 1] = TEMP_TO_REG(v); - gl520_write_value(client, reg, data->temp_max_hyst[n - 1]); + data->temp_max_hyst[n] = TEMP_TO_REG(v); + gl520_write_value(client, GL520_REG_TEMP_MAX_HYST[n], + data->temp_max_hyst[n]); mutex_unlock(&data->update_lock); return count; } -static ssize_t get_alarms(struct gl520_data *data, char *buf, int n) +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_temp_input, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_temp_input, NULL, 1); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, + get_temp_max, set_temp_max, 0); +static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, + get_temp_max, set_temp_max, 1); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, + get_temp_max_hyst, set_temp_max_hyst, 0); +static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, + get_temp_max_hyst, set_temp_max_hyst, 1); + +static ssize_t get_alarms(struct device *dev, struct device_attribute *attr, + char *buf) { + struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%d\n", data->alarms); } -static ssize_t get_beep_enable(struct gl520_data *data, char *buf, int n) +static ssize_t get_beep_enable(struct device *dev, struct device_attribute + *attr, char *buf) { + struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%d\n", data->beep_enable); } -static ssize_t get_beep_mask(struct gl520_data *data, char *buf, int n) +static ssize_t get_beep_mask(struct device *dev, struct device_attribute *attr, + char *buf) { + struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%d\n", data->beep_mask); } -static ssize_t set_beep_enable(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_beep_enable(struct device *dev, struct device_attribute + *attr, const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); u8 r = simple_strtoul(buf, NULL, 10)?0:1; mutex_lock(&data->update_lock); data->beep_enable = !r; - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x04) | (r << 2)); + gl520_write_value(client, GL520_REG_BEEP_ENABLE, + (gl520_read_value(client, GL520_REG_BEEP_ENABLE) + & ~0x04) | (r << 2)); mutex_unlock(&data->update_lock); return count; } -static ssize_t set_beep_mask(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_beep_mask(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); u8 r = simple_strtoul(buf, NULL, 10); - + mutex_lock(&data->update_lock); r &= data->alarm_mask; data->beep_mask = r; - gl520_write_value(client, reg, r); + gl520_write_value(client, GL520_REG_BEEP_MASK, r); + mutex_unlock(&data->update_lock); + return count; +} + +static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); +static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR, + get_beep_enable, set_beep_enable); +static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR, + get_beep_mask, set_beep_mask); + +static ssize_t get_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int bit_nr = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", (data->alarms >> bit_nr) & 1); +} + +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, get_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, get_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, get_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, get_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, get_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, get_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, get_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, get_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, get_alarm, NULL, 7); + +static ssize_t get_beep(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", (data->beep_mask >> bitnr) & 1); +} + +static ssize_t set_beep(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int bitnr = to_sensor_dev_attr(attr)->index; + unsigned long bit; + + bit = simple_strtoul(buf, NULL, 10); + if (bit & ~1) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); + if (bit) + data->beep_mask |= (1 << bitnr); + else + data->beep_mask &= ~(1 << bitnr); + gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); mutex_unlock(&data->update_lock); return count; } +static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 0); +static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 1); +static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 2); +static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 3); +static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 4); +static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 5); +static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 6); +static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 7); +static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 7); + static struct attribute *gl520_attributes[] = { &dev_attr_cpu0_vid.attr, - &dev_attr_in0_input.attr, - &dev_attr_in0_min.attr, - &dev_attr_in0_max.attr, - &dev_attr_in1_input.attr, - &dev_attr_in1_min.attr, - &dev_attr_in1_max.attr, - &dev_attr_in2_input.attr, - &dev_attr_in2_min.attr, - &dev_attr_in2_max.attr, - &dev_attr_in3_input.attr, - &dev_attr_in3_min.attr, - &dev_attr_in3_max.attr, - - &dev_attr_fan1_input.attr, - &dev_attr_fan1_min.attr, - &dev_attr_fan1_div.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in0_beep.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in1_beep.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in2_beep.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + &sensor_dev_attr_in3_beep.dev_attr.attr, + + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_beep.dev_attr.attr, &dev_attr_fan1_off.attr, - &dev_attr_fan2_input.attr, - &dev_attr_fan2_min.attr, - &dev_attr_fan2_div.attr, - - &dev_attr_temp1_input.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_max_hyst.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + &sensor_dev_attr_fan2_beep.dev_attr.attr, + + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_beep.dev_attr.attr, &dev_attr_alarms.attr, &dev_attr_beep_enable.attr, @@ -525,13 +646,17 @@ static const struct attribute_group gl520_group = { }; static struct attribute *gl520_attributes_opt[] = { - &dev_attr_in4_input.attr, - &dev_attr_in4_min.attr, - &dev_attr_in4_max.attr, - - &dev_attr_temp2_input.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp2_max_hyst.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + &sensor_dev_attr_in4_beep.dev_attr.attr, + + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_beep.dev_attr.attr, NULL }; @@ -553,7 +678,7 @@ static int gl520_attach_adapter(struct i2c_adapter *adapter) static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) { - struct i2c_client *new_client; + struct i2c_client *client; struct gl520_data *data; int err = 0; @@ -570,59 +695,65 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) goto exit; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &gl520_driver; - new_client->flags = 0; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &gl520_driver; /* Determine the chip type. */ if (kind < 0) { - if ((gl520_read_value(new_client, GL520_REG_CHIP_ID) != 0x20) || - ((gl520_read_value(new_client, GL520_REG_REVISION) & 0x7f) != 0x00) || - ((gl520_read_value(new_client, GL520_REG_CONF) & 0x80) != 0x00)) { - dev_dbg(&new_client->dev, "Unknown chip type, skipping\n"); + if ((gl520_read_value(client, GL520_REG_CHIP_ID) != 0x20) || + ((gl520_read_value(client, GL520_REG_REVISION) & 0x7f) != 0x00) || + ((gl520_read_value(client, GL520_REG_CONF) & 0x80) != 0x00)) { + dev_dbg(&client->dev, "Unknown chip type, skipping\n"); goto exit_free; } } /* Fill in the remaining client fields */ - strlcpy(new_client->name, "gl520sm", I2C_NAME_SIZE); - data->valid = 0; + strlcpy(client->name, "gl520sm", I2C_NAME_SIZE); mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto exit_free; /* Initialize the GL520SM chip */ - gl520_init_client(new_client); + gl520_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &gl520_group))) + if ((err = sysfs_create_group(&client->dev.kobj, &gl520_group))) goto exit_detach; if (data->two_temps) { - if ((err = device_create_file(&new_client->dev, - &dev_attr_temp2_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_temp2_max)) - || (err = device_create_file(&new_client->dev, - &dev_attr_temp2_max_hyst))) + if ((err = device_create_file(&client->dev, + &sensor_dev_attr_temp2_input.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_temp2_max.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_temp2_max_hyst.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_temp2_alarm.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_temp2_beep.dev_attr))) goto exit_remove_files; } else { - if ((err = device_create_file(&new_client->dev, - &dev_attr_in4_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in4_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in4_max))) + if ((err = device_create_file(&client->dev, + &sensor_dev_attr_in4_input.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_in4_min.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_in4_max.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_in4_alarm.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_in4_beep.dev_attr))) goto exit_remove_files; } - data->hwmon_dev = hwmon_device_register(&new_client->dev); + data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; @@ -631,10 +762,10 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_remove_files: - sysfs_remove_group(&new_client->dev.kobj, &gl520_group); - sysfs_remove_group(&new_client->dev.kobj, &gl520_group_opt); + sysfs_remove_group(&client->dev.kobj, &gl520_group); + sysfs_remove_group(&client->dev.kobj, &gl520_group_opt); exit_detach: - i2c_detach_client(new_client); + i2c_detach_client(client); exit_free: kfree(data); exit: @@ -697,7 +828,7 @@ static int gl520_detach_client(struct i2c_client *client) } -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized +/* Registers 0x07 to 0x0c are word-sized, others are byte-sized GL520 uses a high-byte first convention */ static int gl520_read_value(struct i2c_client *client, u8 reg) { @@ -720,7 +851,7 @@ static struct gl520_data *gl520_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct gl520_data *data = i2c_get_clientdata(client); - int val; + int val, i; mutex_lock(&data->update_lock); @@ -732,18 +863,13 @@ static struct gl520_data *gl520_update_device(struct device *dev) data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); data->vid = gl520_read_value(client, GL520_REG_VID_INPUT) & 0x1f; - val = gl520_read_value(client, GL520_REG_IN0_LIMIT); - data->in_min[0] = val & 0xff; - data->in_max[0] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_IN1_LIMIT); - data->in_min[1] = val & 0xff; - data->in_max[1] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_IN2_LIMIT); - data->in_min[2] = val & 0xff; - data->in_max[2] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_IN3_LIMIT); - data->in_min[3] = val & 0xff; - data->in_max[3] = (val >> 8) & 0xff; + for (i = 0; i < 4; i++) { + data->in_input[i] = gl520_read_value(client, + GL520_REG_IN_INPUT[i]); + val = gl520_read_value(client, GL520_REG_IN_LIMIT[i]); + data->in_min[i] = val & 0xff; + data->in_max[i] = (val >> 8) & 0xff; + } val = gl520_read_value(client, GL520_REG_FAN_INPUT); data->fan_input[0] = (val >> 8) & 0xff; @@ -753,9 +879,12 @@ static struct gl520_data *gl520_update_device(struct device *dev) data->fan_min[0] = (val >> 8) & 0xff; data->fan_min[1] = val & 0xff; - data->temp_input[0] = gl520_read_value(client, GL520_REG_TEMP1_INPUT); - data->temp_max[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX); - data->temp_max_hyst[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX_HYST); + data->temp_input[0] = gl520_read_value(client, + GL520_REG_TEMP_INPUT[0]); + data->temp_max[0] = gl520_read_value(client, + GL520_REG_TEMP_MAX[0]); + data->temp_max_hyst[0] = gl520_read_value(client, + GL520_REG_TEMP_MAX_HYST[0]); val = gl520_read_value(client, GL520_REG_FAN_DIV); data->fan_div[0] = (val >> 6) & 0x03; @@ -767,20 +896,21 @@ static struct gl520_data *gl520_update_device(struct device *dev) val = gl520_read_value(client, GL520_REG_CONF); data->beep_enable = !((val >> 2) & 1); - data->in_input[0] = gl520_read_value(client, GL520_REG_IN0_INPUT); - data->in_input[1] = gl520_read_value(client, GL520_REG_IN1_INPUT); - data->in_input[2] = gl520_read_value(client, GL520_REG_IN2_INPUT); - data->in_input[3] = gl520_read_value(client, GL520_REG_IN3_INPUT); - /* Temp1 and Vin4 are the same input */ if (data->two_temps) { - data->temp_input[1] = gl520_read_value(client, GL520_REG_TEMP2_INPUT); - data->temp_max[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX); - data->temp_max_hyst[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX_HYST); + data->temp_input[1] = gl520_read_value(client, + GL520_REG_TEMP_INPUT[1]); + data->temp_max[1] = gl520_read_value(client, + GL520_REG_TEMP_MAX[1]); + data->temp_max_hyst[1] = gl520_read_value(client, + GL520_REG_TEMP_MAX_HYST[1]); } else { - data->in_input[4] = gl520_read_value(client, GL520_REG_IN4_INPUT); - data->in_min[4] = gl520_read_value(client, GL520_REG_IN4_MIN); - data->in_max[4] = gl520_read_value(client, GL520_REG_IN4_MAX); + data->in_input[4] = gl520_read_value(client, + GL520_REG_IN_INPUT[4]); + data->in_min[4] = gl520_read_value(client, + GL520_REG_IN_MIN[4]); + data->in_max[4] = gl520_read_value(client, + GL520_REG_IN_MAX[4]); } data->last_updated = jiffies; diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index ad6c8a319903..e12c132ff83a 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -17,8 +17,8 @@ IT8726F Super I/O chip w/LPC interface Sis950 A clone of the IT8705F - Copyright (C) 2001 Chris Gauthron <chrisg@0-in.com> - Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.org> + Copyright (C) 2001 Chris Gauthron + Copyright (C) 2005-2007 Jean Delvare <khali@linux-fr.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -52,6 +52,10 @@ enum chips { it87, it8712, it8716, it8718 }; +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + static struct platform_device *pdev; #define REG 0x2e /* The register to read/write */ @@ -776,6 +780,30 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 12); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 13); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 14); +static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 15); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 16); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 17); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 18); + static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { @@ -837,6 +865,14 @@ static struct attribute *it87_attributes[] = { &sensor_dev_attr_in5_max.dev_attr.attr, &sensor_dev_attr_in6_max.dev_attr.attr, &sensor_dev_attr_in7_max.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, @@ -850,6 +886,9 @@ static struct attribute *it87_attributes[] = { &sensor_dev_attr_temp1_type.dev_attr.attr, &sensor_dev_attr_temp2_type.dev_attr.attr, &sensor_dev_attr_temp3_type.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, &dev_attr_alarms.attr, &dev_attr_name.attr, @@ -882,12 +921,21 @@ static struct attribute *it87_attributes_opt[] = { &sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan3_div.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, + &sensor_dev_attr_fan4_alarm.dev_attr.attr, + &sensor_dev_attr_fan5_alarm.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, &sensor_dev_attr_pwm2_enable.dev_attr.attr, &sensor_dev_attr_pwm3_enable.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr, &sensor_dev_attr_pwm3.dev_attr.attr, + &dev_attr_pwm1_freq.attr, + &dev_attr_pwm2_freq.attr, + &dev_attr_pwm3_freq.attr, &dev_attr_vrm.attr, &dev_attr_cpu0_vid.attr, @@ -906,7 +954,7 @@ static int __init it87_find(unsigned short *address, u16 chip_type; superio_enter(); - chip_type = superio_inw(DEVID); + chip_type = force_id ? force_id : superio_inw(DEVID); switch (chip_type) { case IT8705F_DEVID: @@ -1027,35 +1075,45 @@ static int __devinit it87_probe(struct platform_device *pdev) if ((err = device_create_file(dev, &sensor_dev_attr_fan1_input16.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_fan1_min16.dev_attr))) + &sensor_dev_attr_fan1_min16.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan1_alarm.dev_attr))) goto ERROR4; } if (data->has_fan & (1 << 1)) { if ((err = device_create_file(dev, &sensor_dev_attr_fan2_input16.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_fan2_min16.dev_attr))) + &sensor_dev_attr_fan2_min16.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan2_alarm.dev_attr))) goto ERROR4; } if (data->has_fan & (1 << 2)) { if ((err = device_create_file(dev, &sensor_dev_attr_fan3_input16.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_fan3_min16.dev_attr))) + &sensor_dev_attr_fan3_min16.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan3_alarm.dev_attr))) goto ERROR4; } if (data->has_fan & (1 << 3)) { if ((err = device_create_file(dev, &sensor_dev_attr_fan4_input16.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_fan4_min16.dev_attr))) + &sensor_dev_attr_fan4_min16.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan4_alarm.dev_attr))) goto ERROR4; } if (data->has_fan & (1 << 4)) { if ((err = device_create_file(dev, &sensor_dev_attr_fan5_input16.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_fan5_min16.dev_attr))) + &sensor_dev_attr_fan5_min16.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan5_alarm.dev_attr))) goto ERROR4; } } else { @@ -1066,7 +1124,9 @@ static int __devinit it87_probe(struct platform_device *pdev) || (err = device_create_file(dev, &sensor_dev_attr_fan1_min.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_fan1_div.dev_attr))) + &sensor_dev_attr_fan1_div.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan1_alarm.dev_attr))) goto ERROR4; } if (data->has_fan & (1 << 1)) { @@ -1075,7 +1135,9 @@ static int __devinit it87_probe(struct platform_device *pdev) || (err = device_create_file(dev, &sensor_dev_attr_fan2_min.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_fan2_div.dev_attr))) + &sensor_dev_attr_fan2_div.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan2_alarm.dev_attr))) goto ERROR4; } if (data->has_fan & (1 << 2)) { @@ -1084,7 +1146,9 @@ static int __devinit it87_probe(struct platform_device *pdev) || (err = device_create_file(dev, &sensor_dev_attr_fan3_min.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_fan3_div.dev_attr))) + &sensor_dev_attr_fan3_div.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan3_alarm.dev_attr))) goto ERROR4; } } @@ -1488,7 +1552,7 @@ static void __exit sm_it87_exit(void) } -MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>, " +MODULE_AUTHOR("Chris Gauthron, " "Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8726F, SiS950 driver"); module_param(update_vbat, bool, 0); diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 37a8cc032ffa..e5c35a355a57 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -74,7 +74,6 @@ static struct i2c_driver lm75_driver = { .driver = { .name = "lm75", }, - .id = I2C_DRIVERID_LM75, .attach_adapter = lm75_attach_adapter, .detach_client = lm75_detach_client, }; diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index cee5c2e8cfad..459b70ad6bee 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -31,6 +31,7 @@ #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> @@ -113,7 +114,6 @@ show(temp_input); show(temp_crit); show(temp_min); show(temp_max); -show(alarms); /* read routines for hysteresis values */ static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) @@ -186,6 +186,14 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, return count; } +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct lm77_data *data = lm77_update_device(dev); + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} + static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, @@ -202,8 +210,9 @@ static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_max_hyst, NULL); -static DEVICE_ATTR(alarms, S_IRUGO, - show_alarms, NULL); +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1); static int lm77_attach_adapter(struct i2c_adapter *adapter) { @@ -220,8 +229,9 @@ static struct attribute *lm77_attributes[] = { &dev_attr_temp1_crit_hyst.attr, &dev_attr_temp1_min_hyst.attr, &dev_attr_temp1_max_hyst.attr, - &dev_attr_alarms.attr, - + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, NULL }; diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 3f7055ee679f..0a9eb1f6f4e4 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -37,10 +37,8 @@ static struct platform_device *pdev; /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, - 0x25, 0x26, 0x27, 0x28, 0x29, - 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, I2C_CLIENT_END }; +static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, I2C_CLIENT_END }; static unsigned short isa_address = 0x290; /* Insmod parameters */ @@ -170,7 +168,6 @@ static struct i2c_driver lm78_driver = { .driver = { .name = "lm78", }, - .id = I2C_DRIVERID_LM78, .attach_adapter = lm78_attach_adapter, .detach_client = lm78_detach_client, }; diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 063cdba00a88..a2ca055f3922 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -27,6 +27,7 @@ #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> @@ -127,7 +128,7 @@ struct lm80_data { u16 alarms; /* Register encoding, combined */ }; -/* +/* * Functions declaration */ @@ -147,7 +148,6 @@ static struct i2c_driver lm80_driver = { .driver = { .name = "lm80", }, - .id = I2C_DRIVERID_LM80, .attach_adapter = lm80_attach_adapter, .detach_client = lm80_detach_client, }; @@ -159,105 +159,74 @@ static struct i2c_driver lm80_driver = { #define show_in(suffix, value) \ static ssize_t show_in_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ { \ + int nr = to_sensor_dev_attr(attr)->index; \ struct lm80_data *data = lm80_update_device(dev); \ - return sprintf(buf, "%d\n", IN_FROM_REG(data->value)); \ + return sprintf(buf, "%d\n", IN_FROM_REG(data->value[nr])); \ } -show_in(min0, in_min[0]); -show_in(min1, in_min[1]); -show_in(min2, in_min[2]); -show_in(min3, in_min[3]); -show_in(min4, in_min[4]); -show_in(min5, in_min[5]); -show_in(min6, in_min[6]); -show_in(max0, in_max[0]); -show_in(max1, in_max[1]); -show_in(max2, in_max[2]); -show_in(max3, in_max[3]); -show_in(max4, in_max[4]); -show_in(max5, in_max[5]); -show_in(max6, in_max[6]); -show_in(input0, in[0]); -show_in(input1, in[1]); -show_in(input2, in[2]); -show_in(input3, in[3]); -show_in(input4, in[4]); -show_in(input5, in[5]); -show_in(input6, in[6]); +show_in(min, in_min) +show_in(max, in_max) +show_in(input, in) #define set_in(suffix, value, reg) \ static ssize_t set_in_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ { \ + int nr = to_sensor_dev_attr(attr)->index; \ struct i2c_client *client = to_i2c_client(dev); \ struct lm80_data *data = i2c_get_clientdata(client); \ long val = simple_strtol(buf, NULL, 10); \ \ mutex_lock(&data->update_lock);\ - data->value = IN_TO_REG(val); \ - lm80_write_value(client, reg, data->value); \ + data->value[nr] = IN_TO_REG(val); \ + lm80_write_value(client, reg(nr), data->value[nr]); \ mutex_unlock(&data->update_lock);\ return count; \ } -set_in(min0, in_min[0], LM80_REG_IN_MIN(0)); -set_in(min1, in_min[1], LM80_REG_IN_MIN(1)); -set_in(min2, in_min[2], LM80_REG_IN_MIN(2)); -set_in(min3, in_min[3], LM80_REG_IN_MIN(3)); -set_in(min4, in_min[4], LM80_REG_IN_MIN(4)); -set_in(min5, in_min[5], LM80_REG_IN_MIN(5)); -set_in(min6, in_min[6], LM80_REG_IN_MIN(6)); -set_in(max0, in_max[0], LM80_REG_IN_MAX(0)); -set_in(max1, in_max[1], LM80_REG_IN_MAX(1)); -set_in(max2, in_max[2], LM80_REG_IN_MAX(2)); -set_in(max3, in_max[3], LM80_REG_IN_MAX(3)); -set_in(max4, in_max[4], LM80_REG_IN_MAX(4)); -set_in(max5, in_max[5], LM80_REG_IN_MAX(5)); -set_in(max6, in_max[6], LM80_REG_IN_MAX(6)); - -#define show_fan(suffix, value, div) \ +set_in(min, in_min, LM80_REG_IN_MIN) +set_in(max, in_max, LM80_REG_IN_MAX) + +#define show_fan(suffix, value) \ static ssize_t show_fan_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ { \ + int nr = to_sensor_dev_attr(attr)->index; \ struct lm80_data *data = lm80_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->value, \ - DIV_FROM_REG(data->div))); \ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[nr], \ + DIV_FROM_REG(data->fan_div[nr]))); \ } -show_fan(min1, fan_min[0], fan_div[0]); -show_fan(min2, fan_min[1], fan_div[1]); -show_fan(input1, fan[0], fan_div[0]); -show_fan(input2, fan[1], fan_div[1]); +show_fan(min, fan_min) +show_fan(input, fan) -#define show_fan_div(suffix, value) \ -static ssize_t show_fan_div##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm80_data *data = lm80_update_device(dev); \ - return sprintf(buf, "%d\n", DIV_FROM_REG(data->value)); \ +static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct lm80_data *data = lm80_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); } -show_fan_div(1, fan_div[0]); -show_fan_div(2, fan_div[1]); -#define set_fan(suffix, value, reg, div) \ -static ssize_t set_fan_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm80_data *data = i2c_get_clientdata(client); \ - long val = simple_strtoul(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock);\ - data->value = FAN_TO_REG(val, DIV_FROM_REG(data->div)); \ - lm80_write_value(client, reg, data->value); \ - mutex_unlock(&data->update_lock);\ - return count; \ +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct lm80_data *data = i2c_get_clientdata(client); + long val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); + mutex_unlock(&data->update_lock); + return count; } -set_fan(min1, fan_min[0], LM80_REG_FAN_MIN(1), fan_div[0]); -set_fan(min2, fan_min[1], LM80_REG_FAN_MIN(2), fan_div[1]); /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan divisor. This follows the principle of least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm80_data *data = i2c_get_clientdata(client); unsigned long min, val = simple_strtoul(buf, NULL, 10); @@ -292,15 +261,6 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, return count; } -#define set_fan_div(number) \ -static ssize_t set_fan_div##number(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_div(dev, buf, count, number - 1); \ -} -set_fan_div(1); -set_fan_div(2); - static ssize_t show_temp_input1(struct device *dev, struct device_attribute *attr, char *buf) { struct lm80_data *data = lm80_update_device(dev); @@ -337,41 +297,66 @@ set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST); set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX); set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST); -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, + char *buf) { struct lm80_data *data = lm80_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } -static DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min0, set_in_min0); -static DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min1, set_in_min1); -static DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min2, set_in_min2); -static DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min3, set_in_min3); -static DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min4, set_in_min4); -static DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min5, set_in_min5); -static DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min6, set_in_min6); -static DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max0, set_in_max0); -static DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max1, set_in_max1); -static DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max2, set_in_max2); -static DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max3, set_in_max3); -static DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max4, set_in_max4); -static DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max5, set_in_max5); -static DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max6, set_in_max6); -static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL); -static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL); -static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL); -static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL); -static DEVICE_ATTR(in4_input, S_IRUGO, show_in_input4, NULL); -static DEVICE_ATTR(in5_input, S_IRUGO, show_in_input5, NULL); -static DEVICE_ATTR(in6_input, S_IRUGO, show_in_input6, NULL); -static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min1, - set_fan_min1); -static DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min2, - set_fan_min2); -static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL); -static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL); -static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div1, set_fan_div1); -static DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div2, set_fan_div2); +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct lm80_data *data = lm80_update_device(dev); + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} + +static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, + show_in_min, set_in_min, 0); +static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, + show_in_min, set_in_min, 1); +static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, + show_in_min, set_in_min, 2); +static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, + show_in_min, set_in_min, 3); +static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, + show_in_min, set_in_min, 4); +static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, + show_in_min, set_in_min, 5); +static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, + show_in_min, set_in_min, 6); +static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, + show_in_max, set_in_max, 0); +static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, + show_in_max, set_in_max, 1); +static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, + show_in_max, set_in_max, 2); +static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, + show_in_max, set_in_max, 3); +static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, + show_in_max, set_in_max, 4); +static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, + show_in_max, set_in_max, 5); +static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, + show_in_max, set_in_max, 6); +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in_input, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in_input, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in_input, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in_input, NULL, 4); +static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in_input, NULL, 5); +static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in_input, NULL, 6); +static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, + show_fan_min, set_fan_min, 0); +static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, + show_fan_min, set_fan_min, 1); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1); +static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, + show_fan_div, set_fan_div, 0); +static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, + show_fan_div, set_fan_div, 1); static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max, set_temp_hot_max); @@ -382,6 +367,17 @@ static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max, static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst, set_temp_os_hyst); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 13); /* * Real code @@ -395,40 +391,50 @@ static int lm80_attach_adapter(struct i2c_adapter *adapter) } static struct attribute *lm80_attributes[] = { - &dev_attr_in0_min.attr, - &dev_attr_in1_min.attr, - &dev_attr_in2_min.attr, - &dev_attr_in3_min.attr, - &dev_attr_in4_min.attr, - &dev_attr_in5_min.attr, - &dev_attr_in6_min.attr, - &dev_attr_in0_max.attr, - &dev_attr_in1_max.attr, - &dev_attr_in2_max.attr, - &dev_attr_in3_max.attr, - &dev_attr_in4_max.attr, - &dev_attr_in5_max.attr, - &dev_attr_in6_max.attr, - &dev_attr_in0_input.attr, - &dev_attr_in1_input.attr, - &dev_attr_in2_input.attr, - &dev_attr_in3_input.attr, - &dev_attr_in4_input.attr, - &dev_attr_in5_input.attr, - &dev_attr_in6_input.attr, - &dev_attr_fan1_min.attr, - &dev_attr_fan2_min.attr, - &dev_attr_fan1_input.attr, - &dev_attr_fan2_input.attr, - &dev_attr_fan1_div.attr, - &dev_attr_fan2_div.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, &dev_attr_temp1_input.attr, &dev_attr_temp1_max.attr, &dev_attr_temp1_max_hyst.attr, &dev_attr_temp1_crit.attr, &dev_attr_temp1_crit_hyst.attr, &dev_attr_alarms.attr, - + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, NULL }; @@ -439,7 +445,7 @@ static const struct attribute_group lm80_group = { static int lm80_detect(struct i2c_adapter *adapter, int address, int kind) { int i, cur; - struct i2c_client *new_client; + struct i2c_client *client; struct lm80_data *data; int err = 0; const char *name; @@ -455,21 +461,20 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind) goto exit; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm80_driver; - new_client->flags = 0; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &lm80_driver; /* Now, we do the remaining detection. It is lousy. */ - if (lm80_read_value(new_client, LM80_REG_ALARM2) & 0xc0) + if (lm80_read_value(client, LM80_REG_ALARM2) & 0xc0) goto error_free; for (i = 0x2a; i <= 0x3d; i++) { - cur = i2c_smbus_read_byte_data(new_client, i); - if ((i2c_smbus_read_byte_data(new_client, i + 0x40) != cur) - || (i2c_smbus_read_byte_data(new_client, i + 0x80) != cur) - || (i2c_smbus_read_byte_data(new_client, i + 0xc0) != cur)) + cur = i2c_smbus_read_byte_data(client, i); + if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur) + || (i2c_smbus_read_byte_data(client, i + 0x80) != cur) + || (i2c_smbus_read_byte_data(client, i + 0xc0) != cur)) goto error_free; } @@ -477,27 +482,26 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind) kind = lm80; name = "lm80"; - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; + /* Fill in the remaining client fields */ + strlcpy(client->name, name, I2C_NAME_SIZE); mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto error_free; /* Initialize the LM80 chip */ - lm80_init_client(new_client); + lm80_init_client(client); /* A few vars need to be filled upon startup */ - data->fan_min[0] = lm80_read_value(new_client, LM80_REG_FAN_MIN(1)); - data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2)); + data->fan_min[0] = lm80_read_value(client, LM80_REG_FAN_MIN(1)); + data->fan_min[1] = lm80_read_value(client, LM80_REG_FAN_MIN(2)); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &lm80_group))) + if ((err = sysfs_create_group(&client->dev.kobj, &lm80_group))) goto error_detach; - data->hwmon_dev = hwmon_device_register(&new_client->dev); + data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto error_remove; @@ -506,9 +510,9 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind) return 0; error_remove: - sysfs_remove_group(&new_client->dev.kobj, &lm80_group); + sysfs_remove_group(&client->dev.kobj, &lm80_group); error_detach: - i2c_detach_client(new_client); + i2c_detach_client(client); error_free: kfree(data); exit: diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index 0336b4572a61..6e8903a6e902 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -133,7 +133,6 @@ static struct i2c_driver lm83_driver = { .driver = { .name = "lm83", }, - .id = I2C_DRIVERID_LM83, .attach_adapter = lm83_attach_adapter, .detach_client = lm83_detach_client, }; diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index a02480be65f2..4bb0f291a6b8 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -367,7 +367,6 @@ static struct i2c_driver lm85_driver = { .driver = { .name = "lm85", }, - .id = I2C_DRIVERID_LM85, .attach_adapter = lm85_attach_adapter, .detach_client = lm85_detach_client, }; @@ -444,12 +443,8 @@ static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, c static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - data->vrm = val; + struct lm85_data *data = dev_get_drvdata(dev); + data->vrm = simple_strtoul(buf, NULL, 10); return count; } @@ -519,17 +514,64 @@ static ssize_t show_pwm_enable(struct device *dev, struct device_attribute { int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); - int pwm_zone; + int pwm_zone, enable; pwm_zone = ZONE_FROM_REG(data->autofan[nr].config); - return sprintf(buf,"%d\n", (pwm_zone != 0 && pwm_zone != -1) ); + switch (pwm_zone) { + case -1: /* PWM is always at 100% */ + enable = 0; + break; + case 0: /* PWM is always at 0% */ + case -2: /* PWM responds to manual control */ + enable = 1; + break; + default: /* PWM in automatic mode */ + enable = 2; + } + return sprintf(buf, "%d\n", enable); +} + +static ssize_t set_pwm_enable(struct device *dev, struct device_attribute + *attr, const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + u8 config; + + switch (val) { + case 0: + config = 3; + break; + case 1: + config = 7; + break; + case 2: + /* Here we have to choose arbitrarily one of the 5 possible + configurations; I go for the safest */ + config = 6; + break; + default: + return -EINVAL; + } + + mutex_lock(&data->update_lock); + data->autofan[nr].config = lm85_read_value(client, + LM85_REG_AFAN_CONFIG(nr)); + data->autofan[nr].config = (data->autofan[nr].config & ~0xe0) + | (config << 5); + lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), + data->autofan[nr].config); + mutex_unlock(&data->update_lock); + return count; } #define show_pwm_reg(offset) \ static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ show_pwm, set_pwm, offset - 1); \ -static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \ - show_pwm_enable, NULL, offset - 1) +static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ + show_pwm_enable, set_pwm_enable, offset - 1) show_pwm_reg(1); show_pwm_reg(2); diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index 28cdff0c556b..8ee07c5c97a1 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -5,7 +5,7 @@ * Philip Edelbrock <phil@netroedge.com> * Stephen Rousset <stephen.rousset@rocketlogix.com> * Dan Eaton <dan.eaton@rocketlogix.com> - * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> + * Copyright (C) 2004,2007 Jean Delvare <khali@linux-fr.org> * * Original port to Linux 2.6 by Jeff Oliver. * @@ -37,6 +37,11 @@ * instead. The LM87 is the only hardware monitoring chipset I know of * which uses amplitude modulation. Be careful when using this feature. * + * This driver also supports the ADM1024, a sensor chip made by Analog + * Devices. That chip is fully compatible with the LM87. Complete + * datasheet can be obtained from Analog's website at: + * http://www.analog.com/en/prod/0,2877,ADM1024,00.html + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -74,7 +79,7 @@ static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; * Insmod parameters */ -I2C_CLIENT_INSMOD_1(lm87); +I2C_CLIENT_INSMOD_2(lm87, adm1024); /* * The LM87 registers @@ -166,7 +171,6 @@ static struct i2c_driver lm87_driver = { .driver = { .name = "lm87", }, - .id = I2C_DRIVERID_LM87, .attach_adapter = lm87_attach_adapter, .detach_client = lm87_detach_client, }; @@ -506,8 +510,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char } static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); + struct lm87_data *data = dev_get_drvdata(dev); data->vrm = simple_strtoul(buf, NULL, 10); return count; } @@ -662,6 +665,7 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) struct i2c_client *new_client; struct lm87_data *data; int err = 0; + static const char *names[] = { "lm87", "adm1024" }; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; @@ -686,11 +690,18 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) /* Now, we do the remaining detection. */ if (kind < 0) { + u8 cid = lm87_read_value(new_client, LM87_REG_COMPANY_ID); u8 rev = lm87_read_value(new_client, LM87_REG_REVISION); - if (rev < 0x01 || rev > 0x08 - || (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80) - || lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02) { + if (cid == 0x02 /* National Semiconductor */ + && (rev >= 0x01 && rev <= 0x08)) + kind = lm87; + else if (cid == 0x41 /* Analog Devices */ + && (rev & 0xf0) == 0x10) + kind = adm1024; + + if (kind < 0 + || (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80)) { dev_dbg(&adapter->dev, "LM87 detection failed at 0x%02x.\n", address); @@ -699,7 +710,7 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) } /* We can fill in the remaining client fields */ - strlcpy(new_client->name, "lm87", I2C_NAME_SIZE); + strlcpy(new_client->name, names[kind - 1], I2C_NAME_SIZE); data->valid = 0; mutex_init(&data->update_lock); diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 960df9fa75af..f7ec95bedbf6 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -204,7 +204,6 @@ static struct i2c_driver lm90_driver = { .driver = { .name = "lm90", }, - .id = I2C_DRIVERID_LM90, .attach_adapter = lm90_attach_adapter, .detach_client = lm90_detach_client, }; @@ -531,24 +530,24 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) kind = lm90; if (kind < 0) { /* detection and identification */ - u8 man_id, chip_id, reg_config1, reg_convrate; - - if (lm90_read_reg(new_client, LM90_REG_R_MAN_ID, - &man_id) < 0 - || lm90_read_reg(new_client, LM90_REG_R_CHIP_ID, - &chip_id) < 0 - || lm90_read_reg(new_client, LM90_REG_R_CONFIG1, - ®_config1) < 0 - || lm90_read_reg(new_client, LM90_REG_R_CONVRATE, - ®_convrate) < 0) + int man_id, chip_id, reg_config1, reg_convrate; + + if ((man_id = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_MAN_ID)) < 0 + || (chip_id = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CHIP_ID)) < 0 + || (reg_config1 = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONFIG1)) < 0 + || (reg_convrate = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONVRATE)) < 0) goto exit_free; if ((address == 0x4C || address == 0x4D) && man_id == 0x01) { /* National Semiconductor */ - u8 reg_config2; + int reg_config2; - if (lm90_read_reg(new_client, LM90_REG_R_CONFIG2, - ®_config2) < 0) + if ((reg_config2 = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONFIG2)) < 0) goto exit_free; if ((reg_config1 & 0x2A) == 0x00 diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 61d1bd1d5b6e..af5c77d568fe 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -428,7 +428,6 @@ static struct i2c_driver lm92_driver = { .driver = { .name = "lm92", }, - .id = I2C_DRIVERID_LM92, .attach_adapter = lm92_attach_adapter, .detach_client = lm92_detach_client, }; diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index 9d660133d517..9b462bb13fa3 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -59,6 +59,10 @@ MODULE_PARM_DESC(init, " 2: Forcibly enable all voltage and temperature channels, except in9\n" " 3: Forcibly enable all voltage and temperature channels, including in9"); +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + /* * Super-I/O registers and operations */ @@ -826,7 +830,7 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses /* No superio_enter */ /* Identify device */ - val = superio_inb(sioaddr, DEVID); + val = force_id ? force_id : superio_inb(sioaddr, DEVID); switch (val) { case 0xE1: /* PC87360 */ case 0xE8: /* PC87363 */ diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index d40509ad6ae6..7265f22ae5cd 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -34,6 +34,10 @@ #include <linux/ioport.h> #include <asm/io.h> +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + static struct platform_device *pdev; #define DRVNAME "pc87427" @@ -555,7 +559,7 @@ static int __init pc87427_find(int sioaddr, unsigned short *address) int i, err = 0; /* Identify device */ - val = superio_inb(sioaddr, SIOREG_DEVID); + val = force_id ? force_id : superio_inb(sioaddr, SIOREG_DEVID); if (val != 0xf2) { /* PC87427 */ err = -ENODEV; goto exit; diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index 0b57d2ea2cf7..f61d8f4185b2 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -38,6 +38,10 @@ #include <linux/mutex.h> #include <asm/io.h> +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + static struct platform_device *pdev; #define DRVNAME "smsc47b397" @@ -333,7 +337,7 @@ static int __init smsc47b397_find(unsigned short *addr) u8 id, rev; superio_enter(); - id = superio_inb(SUPERIO_REG_DEVID); + id = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID); if ((id != 0x6f) && (id != 0x81) && (id != 0x85)) { superio_exit(); diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index a10a380868e2..0d7f0c4d06bb 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -39,6 +39,10 @@ #include <linux/sysfs.h> #include <asm/io.h> +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + static struct platform_device *pdev; #define DRVNAME "smsc47m1" @@ -399,7 +403,7 @@ static int __init smsc47m1_find(unsigned short *addr, u8 val; superio_enter(); - val = superio_inb(SUPERIO_REG_DEVID); + val = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID); /* * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index b87552652588..8b0c188e60f6 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -341,8 +341,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m192_data *data = i2c_get_clientdata(client); + struct smsc47m192_data *data = dev_get_drvdata(dev); data->vrm = simple_strtoul(buf, NULL, 10); return count; } diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 7dfcc8dd316d..12b43590fa53 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -42,6 +42,10 @@ static int int_mode = -1; module_param(int_mode, int, 0); MODULE_PARM_DESC(int_mode, "Force the temperature interrupt mode"); +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + static struct platform_device *pdev; #define DRVNAME "vt1211" @@ -1280,10 +1284,12 @@ EXIT: static int __init vt1211_find(int sio_cip, unsigned short *address) { int err = -ENODEV; + int devid; superio_enter(sio_cip); - if (superio_inb(sio_cip, SIO_VT1211_DEVID) != SIO_VT1211_ID) { + devid = force_id ? force_id : superio_inb(sio_cip, SIO_VT1211_DEVID); + if (devid != SIO_VT1211_ID) { goto EXIT; } diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 2196a84603f5..f87661775fe0 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -504,7 +504,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, case 4: data->fan_div[nr] = 2; break; case 8: data->fan_div[nr] = 3; break; default: - dev_err(dev, "fan_div value %ld not supported." + dev_err(dev, "fan_div value %ld not supported. " "Choose one of 1, 2, 4 or 8!\n", val); mutex_unlock(&data->update_lock); return -EINVAL; diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index d5aa25ce5dbd..075164dd65a7 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -59,6 +59,10 @@ static const char * w83627ehf_device_names[] = { "w83627dhg", }; +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + #define DRVNAME "w83627ehf" /* @@ -1198,8 +1202,7 @@ static void w83627ehf_device_remove_files(struct device *dev) device_remove_file(dev, &sda_temp[i].dev_attr); device_remove_file(dev, &dev_attr_name); - if (data->vid != 0x3f) - device_remove_file(dev, &dev_attr_cpu0_vid); + device_remove_file(dev, &dev_attr_cpu0_vid); } /* Get the monitoring functions started */ @@ -1299,11 +1302,16 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) } } - data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA) & 0x3f; + data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA); + if (sio_data->kind == w83627ehf) /* 6 VID pins only */ + data->vid &= 0x3f; + + err = device_create_file(dev, &dev_attr_cpu0_vid); + if (err) + goto exit_release; } else { dev_info(dev, "VID pins in output mode, CPU VID not " "available\n"); - data->vid = 0x3f; } /* fan4 and fan5 share some pins with the GPIO and serial flash */ @@ -1386,12 +1394,6 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) if (err) goto exit_remove; - if (data->vid != 0x3f) { - err = device_create_file(dev, &dev_attr_cpu0_vid); - if (err) - goto exit_remove; - } - data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); @@ -1445,8 +1447,11 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, superio_enter(sioaddr); - val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) - | superio_inb(sioaddr, SIO_REG_DEVID + 1); + if (force_id) + val = force_id; + else + val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) + | superio_inb(sioaddr, SIO_REG_DEVID + 1); switch (val & SIO_ID_MASK) { case SIO_W83627EHF_ID: sio_data->kind = w83627ehf; diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 879d0a6544cc..9564fb069957 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -75,6 +75,10 @@ static int init = 1; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + /* modified from kernel/include/traps.c */ static int REG; /* The register to read/write */ #define DEV 0x07 /* Register: Logical device select */ @@ -319,10 +323,8 @@ static inline u8 pwm_freq_to_reg(unsigned long val) return (0x80 | (180000UL / (val << 8))); } -#define BEEP_MASK_FROM_REG(val) (val) -#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff) -#define BEEP_ENABLE_TO_REG(val) ((val)?1:0) -#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0) +#define BEEP_MASK_FROM_REG(val) ((val) & 0xff7fff) +#define BEEP_MASK_TO_REG(val) ((val) & 0xff7fff) #define DIV_FROM_REG(val) (1 << (val)) @@ -363,7 +365,6 @@ struct w83627hf_data { u8 vid; /* Register encoding, combined */ u32 alarms; /* Register encoding, combined */ u32 beep_mask; /* Register encoding, combined */ - u8 beep_enable; /* Boolean */ u8 pwm[3]; /* Register value */ u8 pwm_freq[3]; /* Register value */ u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode; @@ -713,65 +714,151 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); -#define show_beep_reg(REG, reg) \ -static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - return sprintf(buf,"%ld\n", \ - (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \ +static ssize_t +show_alarm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + int bitnr = to_sensor_dev_attr(attr)->index; + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); } -show_beep_reg(ENABLE, enable) -show_beep_reg(MASK, mask) +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16); +static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13); -#define BEEP_ENABLE 0 /* Store beep_enable */ -#define BEEP_MASK 1 /* Store beep_mask */ +static ssize_t +show_beep_mask(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", + (long)BEEP_MASK_FROM_REG(data->beep_mask)); +} static ssize_t -store_beep_reg(struct device *dev, const char *buf, size_t count, - int update_mask) +store_beep_mask(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct w83627hf_data *data = dev_get_drvdata(dev); - u32 val, val2; + unsigned long val; val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); - if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ - data->beep_mask = BEEP_MASK_TO_REG(val); - w83627hf_write_value(data, W83781D_REG_BEEP_INTS1, - data->beep_mask & 0xff); - w83627hf_write_value(data, W83781D_REG_BEEP_INTS3, - ((data->beep_mask) >> 16) & 0xff); - val2 = (data->beep_mask >> 8) & 0x7f; - } else { /* We are storing beep_enable */ - val2 = - w83627hf_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f; - data->beep_enable = BEEP_ENABLE_TO_REG(val); - } - + /* preserve beep enable */ + data->beep_mask = (data->beep_mask & 0x8000) + | BEEP_MASK_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_BEEP_INTS1, + data->beep_mask & 0xff); + w83627hf_write_value(data, W83781D_REG_BEEP_INTS3, + ((data->beep_mask) >> 16) & 0xff); w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, - val2 | data->beep_enable << 7); + (data->beep_mask >> 8) & 0xff); mutex_unlock(&data->update_lock); return count; } -#define sysfs_beep(REG, reg) \ -static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_beep_##reg(dev, attr, buf); \ -} \ -static ssize_t \ -store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_beep_reg(dev, buf, count, BEEP_##REG); \ -} \ -static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \ - show_regs_beep_##reg, store_regs_beep_##reg); +static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR, + show_beep_mask, store_beep_mask); + +static ssize_t +show_beep(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + int bitnr = to_sensor_dev_attr(attr)->index; + return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1); +} + +static ssize_t +store_beep(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct w83627hf_data *data = dev_get_drvdata(dev); + int bitnr = to_sensor_dev_attr(attr)->index; + unsigned long bit; + u8 reg; + + bit = simple_strtoul(buf, NULL, 10); + if (bit & ~1) + return -EINVAL; + + mutex_lock(&data->update_lock); + if (bit) + data->beep_mask |= (1 << bitnr); + else + data->beep_mask &= ~(1 << bitnr); + + if (bitnr < 8) { + reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS1); + if (bit) + reg |= (1 << bitnr); + else + reg &= ~(1 << bitnr); + w83627hf_write_value(data, W83781D_REG_BEEP_INTS1, reg); + } else if (bitnr < 16) { + reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2); + if (bit) + reg |= (1 << (bitnr - 8)); + else + reg &= ~(1 << (bitnr - 8)); + w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, reg); + } else { + reg = w83627hf_read_value(data, W83781D_REG_BEEP_INTS3); + if (bit) + reg |= (1 << (bitnr - 16)); + else + reg &= ~(1 << (bitnr - 16)); + w83627hf_write_value(data, W83781D_REG_BEEP_INTS3, reg); + } + mutex_unlock(&data->update_lock); + + return count; +} -sysfs_beep(ENABLE, enable); -sysfs_beep(MASK, mask); +static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 0); +static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 1); +static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 2); +static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 3); +static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 8); +static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 9); +static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 10); +static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 16); +static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 17); +static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 6); +static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 7); +static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 11); +static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 4); +static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 5); +static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 13); +static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR, + show_beep, store_beep, 15); static ssize_t show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf) @@ -1014,7 +1101,7 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr, VAL = sioaddr + 1; superio_enter(); - val= superio_inb(DEVID); + val = force_id ? force_id : superio_inb(DEVID); switch (val) { case W627_DEVID: sio_data->type = w83627hf; @@ -1073,23 +1160,31 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr, #define VIN_UNIT_ATTRS(_X_) \ &sensor_dev_attr_in##_X_##_input.dev_attr.attr, \ &sensor_dev_attr_in##_X_##_min.dev_attr.attr, \ - &sensor_dev_attr_in##_X_##_max.dev_attr.attr + &sensor_dev_attr_in##_X_##_max.dev_attr.attr, \ + &sensor_dev_attr_in##_X_##_alarm.dev_attr.attr, \ + &sensor_dev_attr_in##_X_##_beep.dev_attr.attr #define FAN_UNIT_ATTRS(_X_) \ &sensor_dev_attr_fan##_X_##_input.dev_attr.attr, \ &sensor_dev_attr_fan##_X_##_min.dev_attr.attr, \ - &sensor_dev_attr_fan##_X_##_div.dev_attr.attr + &sensor_dev_attr_fan##_X_##_div.dev_attr.attr, \ + &sensor_dev_attr_fan##_X_##_alarm.dev_attr.attr, \ + &sensor_dev_attr_fan##_X_##_beep.dev_attr.attr #define TEMP_UNIT_ATTRS(_X_) \ &sensor_dev_attr_temp##_X_##_input.dev_attr.attr, \ &sensor_dev_attr_temp##_X_##_max.dev_attr.attr, \ &sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr, \ - &sensor_dev_attr_temp##_X_##_type.dev_attr.attr + &sensor_dev_attr_temp##_X_##_type.dev_attr.attr, \ + &sensor_dev_attr_temp##_X_##_alarm.dev_attr.attr, \ + &sensor_dev_attr_temp##_X_##_beep.dev_attr.attr static struct attribute *w83627hf_attributes[] = { &dev_attr_in0_input.attr, &dev_attr_in0_min.attr, &dev_attr_in0_max.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in0_beep.dev_attr.attr, VIN_UNIT_ATTRS(2), VIN_UNIT_ATTRS(3), VIN_UNIT_ATTRS(4), @@ -1103,7 +1198,7 @@ static struct attribute *w83627hf_attributes[] = { TEMP_UNIT_ATTRS(2), &dev_attr_alarms.attr, - &dev_attr_beep_enable.attr, + &sensor_dev_attr_beep_enable.dev_attr.attr, &dev_attr_beep_mask.attr, &sensor_dev_attr_pwm1.dev_attr.attr, @@ -1193,12 +1288,20 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) || (err = device_create_file(dev, &sensor_dev_attr_in5_max.dev_attr)) || (err = device_create_file(dev, + &sensor_dev_attr_in5_alarm.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in5_beep.dev_attr)) + || (err = device_create_file(dev, &sensor_dev_attr_in6_input.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_in6_min.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_in6_max.dev_attr)) || (err = device_create_file(dev, + &sensor_dev_attr_in6_alarm.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in6_beep.dev_attr)) + || (err = device_create_file(dev, &sensor_dev_attr_pwm1_freq.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_pwm2_freq.dev_attr))) @@ -1212,18 +1315,30 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) || (err = device_create_file(dev, &sensor_dev_attr_in1_max.dev_attr)) || (err = device_create_file(dev, + &sensor_dev_attr_in1_alarm.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in1_beep.dev_attr)) + || (err = device_create_file(dev, &sensor_dev_attr_fan3_input.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_fan3_min.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_fan3_div.dev_attr)) || (err = device_create_file(dev, + &sensor_dev_attr_fan3_alarm.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan3_beep.dev_attr)) + || (err = device_create_file(dev, &sensor_dev_attr_temp3_input.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_temp3_max.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_temp3_max_hyst.dev_attr)) || (err = device_create_file(dev, + &sensor_dev_attr_temp3_alarm.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_beep.dev_attr)) + || (err = device_create_file(dev, &sensor_dev_attr_temp3_type.dev_attr))) goto ERROR4; @@ -1511,6 +1626,11 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev) (w83627hf_read_value(data, W83781D_REG_CONFIG) & 0xf7) | 0x01); + + /* Enable VBAT monitoring if needed */ + tmp = w83627hf_read_value(data, W83781D_REG_VBAT); + if (!(tmp & 0x01)) + w83627hf_write_value(data, W83781D_REG_VBAT, tmp | 0x01); } static void w83627hf_update_fan_div(struct w83627hf_data *data) @@ -1603,8 +1723,7 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev) (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) | (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16); i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2); - data->beep_enable = i >> 7; - data->beep_mask = ((i & 0x7f) << 8) | + data->beep_mask = (i << 8) | w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) | w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16; data->last_updated = jiffies; diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index e0fa7520400d..7421f6ea53e1 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -28,7 +28,6 @@ as99127f 7 3 0 3 0x31 0x12c3 yes no as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes - w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no @@ -54,13 +53,12 @@ static struct platform_device *pdev; /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, - 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; +static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, I2C_CLIENT_END }; static unsigned short isa_address = 0x290; /* Insmod parameters */ -I2C_CLIENT_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f); +I2C_CLIENT_INSMOD_4(w83781d, w83782d, w83783s, as99127f); I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " "{bus, clientaddr, subclientaddr1, subclientaddr2}"); @@ -114,7 +112,7 @@ MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); #define W83781D_REG_ALARM1 0x41 #define W83781D_REG_ALARM2 0x42 -/* Real-time status (W83782D, W83783S, W83627HF) */ +/* Real-time status (W83782D, W83783S) */ #define W83782D_REG_ALARM1 0x459 #define W83782D_REG_ALARM2 0x45A #define W83782D_REG_ALARM3 0x45B @@ -153,10 +151,6 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; #define W83781D_DEFAULT_BETA 3435 -/* RT Table registers */ -#define W83781D_REG_RT_IDX 0x50 -#define W83781D_REG_RT_VAL 0x51 - /* Conversions */ #define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255) #define IN_FROM_REG(val) ((val) * 16) @@ -271,7 +265,6 @@ static struct i2c_driver w83781d_driver = { .driver = { .name = "w83781d", }, - .id = I2C_DRIVERID_W83781D, .attach_adapter = w83781d_attach_adapter, .detach_client = w83781d_detach_client, }; @@ -696,7 +689,7 @@ store_fan_div(struct device *dev, struct device_attribute *da, unsigned long val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); - + /* Save fan_min */ min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); @@ -963,8 +956,6 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, client_name = "w83782d subclient"; else if (kind == w83783s) client_name = "w83783s subclient"; - else if (kind == w83627hf) - client_name = "w83627hf subclient"; else if (kind == as99127f) client_name = "as99127f subclient"; @@ -1004,7 +995,7 @@ ERROR_SC_0: #define IN_UNIT_ATTRS(X) \ &sensor_dev_attr_in##X##_input.dev_attr.attr, \ &sensor_dev_attr_in##X##_min.dev_attr.attr, \ - &sensor_dev_attr_in##X##_max.dev_attr.attr, \ + &sensor_dev_attr_in##X##_max.dev_attr.attr, \ &sensor_dev_attr_in##X##_alarm.dev_attr.attr, \ &sensor_dev_attr_in##X##_beep.dev_attr.attr @@ -1268,9 +1259,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) kind = w83782d; else if (val1 == 0x40 && vendid == winbond && address == 0x2d) kind = w83783s; - else if (val1 == 0x21 && vendid == winbond) - kind = w83627hf; - else if (val1 == 0x31 && address >= 0x28) + else if (val1 == 0x31) kind = as99127f; else { if (kind == 0) @@ -1288,8 +1277,6 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) client_name = "w83782d"; } else if (kind == w83783s) { client_name = "w83783s"; - } else if (kind == w83627hf) { - client_name = "w83627hf"; } else if (kind == as99127f) { client_name = "as99127f"; } @@ -1396,10 +1383,6 @@ w83781d_isa_probe(struct platform_device *pdev) reg = w83781d_read_value(data, W83781D_REG_WCHIPID); switch (reg) { - case 0x21: - data->type = w83627hf; - name = "w83627hf"; - break; case 0x30: data->type = w83782d; name = "w83782d"; @@ -1453,9 +1436,9 @@ w83781d_isa_remove(struct platform_device *pdev) } /* The SMBus locks itself, usually, but nothing may access the Winbond between - bank switches. ISA access must always be locked explicitly! + bank switches. ISA access must always be locked explicitly! We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. + would slow down the W83781D access and should not be necessary. There are some ugly typecasts here, but the good news is - they should nowhere else be necessary! */ static int @@ -1599,11 +1582,6 @@ w83781d_init_device(struct device *dev) int type = data->type; u8 tmp; - if (type == w83627hf) - dev_info(dev, "The W83627HF chip is better supported by the " - "w83627hf driver, support will be dropped from the " - "w83781d driver soon\n"); - if (reset && type != as99127f) { /* this resets registers we don't have documentation for on the as99127f */ /* Resetting the chip has been the default for a long time, @@ -1717,8 +1695,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) w83781d_read_value(data, W83781D_REG_IN_MIN(i)); data->in_max[i] = w83781d_read_value(data, W83781D_REG_IN_MAX(i)); - if ((data->type != w83782d) - && (data->type != w83627hf) && (i == 6)) + if ((data->type != w83782d) && (i == 6)) break; } for (i = 0; i < 3; i++) { @@ -1776,7 +1753,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) data->fan_div[1] |= (i >> 4) & 0x04; data->fan_div[2] |= (i >> 5) & 0x04; } - if ((data->type == w83782d) || (data->type == w83627hf)) { + if (data->type == w83782d) { data->alarms = w83781d_read_value(data, W83782D_REG_ALARM1) | (w83781d_read_value(data, @@ -1886,13 +1863,11 @@ w83781d_isa_found(unsigned short address) outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET); val = inb_p(address + W83781D_DATA_REG_OFFSET); if ((val & 0xfe) == 0x10 /* W83781D */ - || val == 0x30 /* W83782D */ - || val == 0x21) /* W83627HF */ + || val == 0x30) /* W83782D */ found = 1; if (found) pr_info("w83781d: Found a %s chip at %#x\n", - val == 0x21 ? "W83627HF" : val == 0x30 ? "W83782D" : "W83781D", (int)address); release: diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index a9c01a6f0057..85bd21ee3298 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -840,14 +840,12 @@ static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83791d_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); + struct w83791d_data *data = dev_get_drvdata(dev); /* No lock needed as vrm is internal to the driver (not read from a chip register) and so is not updated in w83791d_update_device() */ - data->vrm = val; + data->vrm = simple_strtoul(buf, NULL, 10); return count; } diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 48599e1cc554..3ba1d6b33473 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -131,6 +131,7 @@ static u8 scale_in_add[] = { 0, 0, 0, 0, 0, 0, 0, 150, 150, 0 }; #define PWM_DUTY 0 #define PWM_START 1 #define PWM_NONSTOP 2 +#define PWM_STOP_TIME 3 #define W83793_REG_PWM(index, nr) (((nr) == 0 ? 0xb3 : \ (nr) == 1 ? 0x220 : 0x218) + (index)) @@ -242,9 +243,7 @@ static struct i2c_driver w83793_driver = { static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct w83793_data *data = i2c_get_clientdata(client); - + struct w83793_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } @@ -263,9 +262,7 @@ static ssize_t store_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83793_data *data = i2c_get_clientdata(client); - + struct w83793_data *data = dev_get_drvdata(dev); data->vrm = simple_strtoul(buf, NULL, 10); return count; } @@ -407,10 +404,6 @@ store_fan_min(struct device *dev, struct device_attribute *attr, return count; } -#define PWM_DUTY 0 -#define PWM_START 1 -#define PWM_NONSTOP 2 -#define PWM_STOP_TIME 3 static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index b5db354e2f19..1d6259d29e74 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -96,7 +96,6 @@ static struct i2c_driver w83l785ts_driver = { .driver = { .name = "w83l785ts", }, - .id = I2C_DRIVERID_W83L785TS, .attach_adapter = w83l785ts_attach_adapter, .detach_client = w83l785ts_detach_client, }; diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c new file mode 100644 index 000000000000..1dbee4fa23ad --- /dev/null +++ b/drivers/hwmon/w83l786ng.c @@ -0,0 +1,821 @@ +/* + w83l786ng.c - Linux kernel driver for hardware monitoring + Copyright (c) 2007 Kevin Lo <kevlo@kevlo.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation - version 2. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. +*/ + +/* + Supports following chips: + + Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + w83l786ng 3 2 2 2 0x7b 0x5ca3 yes no +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/hwmon.h> +#include <linux/hwmon-vid.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/mutex.h> + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2e, 0x2f, I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_1(w83l786ng); + +static int reset; +module_param(reset, bool, 0); +MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); + +#define W83L786NG_REG_IN_MIN(nr) (0x2C + (nr) * 2) +#define W83L786NG_REG_IN_MAX(nr) (0x2B + (nr) * 2) +#define W83L786NG_REG_IN(nr) ((nr) + 0x20) + +#define W83L786NG_REG_FAN(nr) ((nr) + 0x28) +#define W83L786NG_REG_FAN_MIN(nr) ((nr) + 0x3B) + +#define W83L786NG_REG_CONFIG 0x40 +#define W83L786NG_REG_ALARM1 0x41 +#define W83L786NG_REG_ALARM2 0x42 +#define W83L786NG_REG_GPIO_EN 0x47 +#define W83L786NG_REG_MAN_ID2 0x4C +#define W83L786NG_REG_MAN_ID1 0x4D +#define W83L786NG_REG_CHIP_ID 0x4E + +#define W83L786NG_REG_DIODE 0x53 +#define W83L786NG_REG_FAN_DIV 0x54 +#define W83L786NG_REG_FAN_CFG 0x80 + +#define W83L786NG_REG_TOLERANCE 0x8D + +static const u8 W83L786NG_REG_TEMP[2][3] = { + { 0x25, /* TEMP 0 in DataSheet */ + 0x35, /* TEMP 0 Over in DataSheet */ + 0x36 }, /* TEMP 0 Hyst in DataSheet */ + { 0x26, /* TEMP 1 in DataSheet */ + 0x37, /* TEMP 1 Over in DataSheet */ + 0x38 } /* TEMP 1 Hyst in DataSheet */ +}; + +static const u8 W83L786NG_PWM_MODE_SHIFT[] = {6, 7}; +static const u8 W83L786NG_PWM_ENABLE_SHIFT[] = {2, 4}; + +/* FAN Duty Cycle, be used to control */ +static const u8 W83L786NG_REG_PWM[] = {0x81, 0x87}; + + +static inline u8 +FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \ + ((val) == 255 ? 0 : \ + 1350000 / ((val) * (div)))) + +/* for temp */ +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \ + : (val)) / 1000, 0, 0xff)) +#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) + +/* The analog voltage inputs have 8mV LSB. Since the sysfs output is + in mV as would be measured on the chip input pin, need to just + multiply/divide by 8 to translate from/to register values. */ +#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 4) / 8), 0, 255)) +#define IN_FROM_REG(val) ((val) * 8) + +#define DIV_FROM_REG(val) (1 << (val)) + +static inline u8 +DIV_TO_REG(long val) +{ + int i; + val = SENSORS_LIMIT(val, 1, 128) >> 1; + for (i = 0; i < 7; i++) { + if (val == 0) + break; + val >>= 1; + } + return ((u8) i); +} + +struct w83l786ng_data { + struct i2c_client client; + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + unsigned long last_nonvolatile; /* In jiffies, last time we update the + nonvolatile registers */ + + u8 in[3]; + u8 in_max[3]; + u8 in_min[3]; + u8 fan[2]; + u8 fan_div[2]; + u8 fan_min[2]; + u8 temp_type[2]; + u8 temp[2][3]; + u8 pwm[2]; + u8 pwm_mode[2]; /* 0->DC variable voltage + 1->PWM variable duty cycle */ + + u8 pwm_enable[2]; /* 1->manual + 2->thermal cruise (also called SmartFan I) */ + u8 tolerance[2]; +}; + +static int w83l786ng_attach_adapter(struct i2c_adapter *adapter); +static int w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind); +static int w83l786ng_detach_client(struct i2c_client *client); +static void w83l786ng_init_client(struct i2c_client *client); +static struct w83l786ng_data *w83l786ng_update_device(struct device *dev); + +static struct i2c_driver w83l786ng_driver = { + .driver = { + .name = "w83l786ng", + }, + .attach_adapter = w83l786ng_attach_adapter, + .detach_client = w83l786ng_detach_client, +}; + +static u8 +w83l786ng_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int +w83l786ng_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* following are the sysfs callback functions */ +#define show_in_reg(reg) \ +static ssize_t \ +show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + int nr = to_sensor_dev_attr(attr)->index; \ + struct w83l786ng_data *data = w83l786ng_update_device(dev); \ + return sprintf(buf,"%d\n", IN_FROM_REG(data->reg[nr])); \ +} + +show_in_reg(in) +show_in_reg(in_min) +show_in_reg(in_max) + +#define store_in_reg(REG, reg) \ +static ssize_t \ +store_in_##reg (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + int nr = to_sensor_dev_attr(attr)->index; \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83l786ng_data *data = i2c_get_clientdata(client); \ + unsigned long val = simple_strtoul(buf, NULL, 10); \ + mutex_lock(&data->update_lock); \ + data->in_##reg[nr] = IN_TO_REG(val); \ + w83l786ng_write_value(client, W83L786NG_REG_IN_##REG(nr), \ + data->in_##reg[nr]); \ + mutex_unlock(&data->update_lock); \ + return count; \ +} + +store_in_reg(MIN, min) +store_in_reg(MAX, max) + +static struct sensor_device_attribute sda_in_input[] = { + SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), + SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), + SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), +}; + +static struct sensor_device_attribute sda_in_min[] = { + SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0), + SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1), + SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2), +}; + +static struct sensor_device_attribute sda_in_max[] = { + SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0), + SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1), + SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2), +}; + +#define show_fan_reg(reg) \ +static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + int nr = to_sensor_dev_attr(attr)->index; \ + struct w83l786ng_data *data = w83l786ng_update_device(dev); \ + return sprintf(buf,"%d\n", \ + FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr]))); \ +} + +show_fan_reg(fan); +show_fan_reg(fan_min); + +static ssize_t +store_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct w83l786ng_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + mutex_lock(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + w83l786ng_write_value(client, W83L786NG_REG_FAN_MIN(nr), + data->fan_min[nr]); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t +show_fan_div(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct w83l786ng_data *data = w83l786ng_update_device(dev); + return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr])); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least surprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t +store_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct w83l786ng_data *data = i2c_get_clientdata(client); + + unsigned long min; + u8 tmp_fan_div; + u8 fan_div_reg; + u8 keep_mask = 0; + u8 new_shift = 0; + + /* Save fan_min */ + mutex_lock(&data->update_lock); + min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); + + data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10)); + + switch (nr) { + case 0: + keep_mask = 0xf8; + new_shift = 0; + break; + case 1: + keep_mask = 0x8f; + new_shift = 4; + break; + } + + fan_div_reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV) + & keep_mask; + + tmp_fan_div = (data->fan_div[nr] << new_shift) & ~keep_mask; + + w83l786ng_write_value(client, W83L786NG_REG_FAN_DIV, + fan_div_reg | tmp_fan_div); + + /* Restore fan_min */ + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + w83l786ng_write_value(client, W83L786NG_REG_FAN_MIN(nr), + data->fan_min[nr]); + mutex_unlock(&data->update_lock); + + return count; +} + +static struct sensor_device_attribute sda_fan_input[] = { + SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0), + SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1), +}; + +static struct sensor_device_attribute sda_fan_min[] = { + SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, + store_fan_min, 0), + SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, + store_fan_min, 1), +}; + +static struct sensor_device_attribute sda_fan_div[] = { + SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, + store_fan_div, 0), + SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, + store_fan_div, 1), +}; + + +/* read/write the temperature, includes measured value and limits */ + +static ssize_t +show_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + struct w83l786ng_data *data = w83l786ng_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index])); +} + +static ssize_t +store_temp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct w83l786ng_data *data = i2c_get_clientdata(client); + s32 val; + + val = simple_strtol(buf, NULL, 10); + mutex_lock(&data->update_lock); + data->temp[nr][index] = TEMP_TO_REG(val); + w83l786ng_write_value(client, W83L786NG_REG_TEMP[nr][index], + data->temp[nr][index]); + mutex_unlock(&data->update_lock); + + return count; +} + +static struct sensor_device_attribute_2 sda_temp_input[] = { + SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0), + SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0), +}; + +static struct sensor_device_attribute_2 sda_temp_max[] = { + SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0, 1), + SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, + show_temp, store_temp, 1, 1), +}; + +static struct sensor_device_attribute_2 sda_temp_max_hyst[] = { + SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0, 2), + SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, + show_temp, store_temp, 1, 2), +}; + +#define show_pwm_reg(reg) \ +static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct w83l786ng_data *data = w83l786ng_update_device(dev); \ + int nr = to_sensor_dev_attr(attr)->index; \ + return sprintf(buf, "%d\n", data->reg[nr]); \ +} + +show_pwm_reg(pwm_mode) +show_pwm_reg(pwm_enable) +show_pwm_reg(pwm) + +static ssize_t +store_pwm_mode(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct w83l786ng_data *data = i2c_get_clientdata(client); + u32 val = simple_strtoul(buf, NULL, 10); + u8 reg; + + if (val > 1) + return -EINVAL; + mutex_lock(&data->update_lock); + data->pwm_mode[nr] = val; + reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG); + reg &= ~(1 << W83L786NG_PWM_MODE_SHIFT[nr]); + if (!val) + reg |= 1 << W83L786NG_PWM_MODE_SHIFT[nr]; + w83l786ng_write_value(client, W83L786NG_REG_FAN_CFG, reg); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t +store_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct w83l786ng_data *data = i2c_get_clientdata(client); + u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255); + + mutex_lock(&data->update_lock); + data->pwm[nr] = val; + w83l786ng_write_value(client, W83L786NG_REG_PWM[nr], val); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t +store_pwm_enable(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct w83l786ng_data *data = i2c_get_clientdata(client); + u32 val = simple_strtoul(buf, NULL, 10); + + u8 reg; + + if (!val || (val > 2)) /* only modes 1 and 2 are supported */ + return -EINVAL; + + mutex_lock(&data->update_lock); + reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG); + data->pwm_enable[nr] = val; + reg &= ~(0x02 << W83L786NG_PWM_ENABLE_SHIFT[nr]); + reg |= (val - 1) << W83L786NG_PWM_ENABLE_SHIFT[nr]; + w83l786ng_write_value(client, W83L786NG_REG_FAN_CFG, reg); + mutex_unlock(&data->update_lock); + return count; +} + +static struct sensor_device_attribute sda_pwm[] = { + SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0), + SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1), +}; + +static struct sensor_device_attribute sda_pwm_mode[] = { + SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode, + store_pwm_mode, 0), + SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode, + store_pwm_mode, 1), +}; + +static struct sensor_device_attribute sda_pwm_enable[] = { + SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable, + store_pwm_enable, 0), + SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable, + store_pwm_enable, 1), +}; + +/* For Smart Fan I/Thermal Cruise and Smart Fan II */ +static ssize_t +show_tolerance(struct device *dev, struct device_attribute *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct w83l786ng_data *data = w83l786ng_update_device(dev); + return sprintf(buf, "%ld\n", (long)data->tolerance[nr]); +} + +static ssize_t +store_tolerance(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct w83l786ng_data *data = i2c_get_clientdata(client); + u32 val; + u8 tol_tmp, tol_mask; + + val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + tol_mask = w83l786ng_read_value(client, + W83L786NG_REG_TOLERANCE) & ((nr == 1) ? 0x0f : 0xf0); + tol_tmp = SENSORS_LIMIT(val, 0, 15); + tol_tmp &= 0x0f; + data->tolerance[nr] = tol_tmp; + if (nr == 1) { + tol_tmp <<= 4; + } + + w83l786ng_write_value(client, W83L786NG_REG_TOLERANCE, + tol_mask | tol_tmp); + mutex_unlock(&data->update_lock); + return count; +} + +static struct sensor_device_attribute sda_tolerance[] = { + SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, + show_tolerance, store_tolerance, 0), + SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, + show_tolerance, store_tolerance, 1), +}; + + +#define IN_UNIT_ATTRS(X) \ + &sda_in_input[X].dev_attr.attr, \ + &sda_in_min[X].dev_attr.attr, \ + &sda_in_max[X].dev_attr.attr + +#define FAN_UNIT_ATTRS(X) \ + &sda_fan_input[X].dev_attr.attr, \ + &sda_fan_min[X].dev_attr.attr, \ + &sda_fan_div[X].dev_attr.attr + +#define TEMP_UNIT_ATTRS(X) \ + &sda_temp_input[X].dev_attr.attr, \ + &sda_temp_max[X].dev_attr.attr, \ + &sda_temp_max_hyst[X].dev_attr.attr + +#define PWM_UNIT_ATTRS(X) \ + &sda_pwm[X].dev_attr.attr, \ + &sda_pwm_mode[X].dev_attr.attr, \ + &sda_pwm_enable[X].dev_attr.attr + +#define TOLERANCE_UNIT_ATTRS(X) \ + &sda_tolerance[X].dev_attr.attr + +static struct attribute *w83l786ng_attributes[] = { + IN_UNIT_ATTRS(0), + IN_UNIT_ATTRS(1), + IN_UNIT_ATTRS(2), + FAN_UNIT_ATTRS(0), + FAN_UNIT_ATTRS(1), + TEMP_UNIT_ATTRS(0), + TEMP_UNIT_ATTRS(1), + PWM_UNIT_ATTRS(0), + PWM_UNIT_ATTRS(1), + TOLERANCE_UNIT_ATTRS(0), + TOLERANCE_UNIT_ATTRS(1), + NULL +}; + +static const struct attribute_group w83l786ng_group = { + .attrs = w83l786ng_attributes, +}; + +static int +w83l786ng_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, w83l786ng_detect); +} + +static int +w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct device *dev; + struct w83l786ng_data *data; + int i, err = 0; + u8 reg_tmp; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + goto exit; + } + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access w83l786ng_{read,write}_value. */ + + if (!(data = kzalloc(sizeof(struct w83l786ng_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + client = &data->client; + dev = &client->dev; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &w83l786ng_driver; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip (actually there is only + * one possible kind of chip for now, W83L786NG). A zero kind means + * that the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + */ + if (kind < 0) { /* detection */ + if (((w83l786ng_read_value(client, + W83L786NG_REG_CONFIG) & 0x80) != 0x00)) { + dev_dbg(&adapter->dev, + "W83L786NG detection failed at 0x%02x.\n", + address); + goto exit_free; + } + } + + if (kind <= 0) { /* identification */ + u16 man_id; + u8 chip_id; + + man_id = (w83l786ng_read_value(client, + W83L786NG_REG_MAN_ID1) << 8) + + w83l786ng_read_value(client, W83L786NG_REG_MAN_ID2); + chip_id = w83l786ng_read_value(client, W83L786NG_REG_CHIP_ID); + + if (man_id == 0x5CA3) { /* Winbond */ + if (chip_id == 0x80) { /* W83L786NG */ + kind = w83l786ng; + } + } + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, + "Unsupported chip (man_id=0x%04X, " + "chip_id=0x%02X).\n", man_id, chip_id); + goto exit_free; + } + } + + /* Fill in the remaining client fields and put into the global list */ + strlcpy(client->name, "w83l786ng", I2C_NAME_SIZE); + mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(client))) + goto exit_free; + + /* Initialize the chip */ + w83l786ng_init_client(client); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 2; i++) { + data->fan_min[i] = w83l786ng_read_value(client, + W83L786NG_REG_FAN_MIN(i)); + } + + /* Update the fan divisor */ + reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV); + data->fan_div[0] = reg_tmp & 0x07; + data->fan_div[1] = (reg_tmp >> 4) & 0x07; + + /* Register sysfs hooks */ + if ((err = sysfs_create_group(&client->dev.kobj, &w83l786ng_group))) + goto exit_remove; + + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + return 0; + + /* Unregister sysfs hooks */ + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &w83l786ng_group); + i2c_detach_client(client); +exit_free: + kfree(data); +exit: + return err; +} + +static int +w83l786ng_detach_client(struct i2c_client *client) +{ + struct w83l786ng_data *data = i2c_get_clientdata(client); + int err; + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &w83l786ng_group); + + if ((err = i2c_detach_client(client))) + return err; + + kfree(data); + + return 0; +} + +static void +w83l786ng_init_client(struct i2c_client *client) +{ + u8 tmp; + + if (reset) + w83l786ng_write_value(client, W83L786NG_REG_CONFIG, 0x80); + + /* Start monitoring */ + tmp = w83l786ng_read_value(client, W83L786NG_REG_CONFIG); + if (!(tmp & 0x01)) + w83l786ng_write_value(client, W83L786NG_REG_CONFIG, tmp | 0x01); +} + +static struct w83l786ng_data *w83l786ng_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83l786ng_data *data = i2c_get_clientdata(client); + int i, j; + u8 reg_tmp, pwmcfg; + + mutex_lock(&data->update_lock); + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Updating w83l786ng data.\n"); + + /* Update the voltages measured value and limits */ + for (i = 0; i < 3; i++) { + data->in[i] = w83l786ng_read_value(client, + W83L786NG_REG_IN(i)); + data->in_min[i] = w83l786ng_read_value(client, + W83L786NG_REG_IN_MIN(i)); + data->in_max[i] = w83l786ng_read_value(client, + W83L786NG_REG_IN_MAX(i)); + } + + /* Update the fan counts and limits */ + for (i = 0; i < 2; i++) { + data->fan[i] = w83l786ng_read_value(client, + W83L786NG_REG_FAN(i)); + data->fan_min[i] = w83l786ng_read_value(client, + W83L786NG_REG_FAN_MIN(i)); + } + + /* Update the fan divisor */ + reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV); + data->fan_div[0] = reg_tmp & 0x07; + data->fan_div[1] = (reg_tmp >> 4) & 0x07; + + pwmcfg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG); + for (i = 0; i < 2; i++) { + data->pwm_mode[i] = + ((pwmcfg >> W83L786NG_PWM_MODE_SHIFT[i]) & 1) + ? 0 : 1; + data->pwm_enable[i] = + ((pwmcfg >> W83L786NG_PWM_ENABLE_SHIFT[i]) & 2) + 1; + data->pwm[i] = w83l786ng_read_value(client, + W83L786NG_REG_PWM[i]); + } + + + /* Update the temperature sensors */ + for (i = 0; i < 2; i++) { + for (j = 0; j < 3; j++) { + data->temp[i][j] = w83l786ng_read_value(client, + W83L786NG_REG_TEMP[i][j]); + } + } + + /* Update Smart Fan I/II tolerance */ + reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_TOLERANCE); + data->tolerance[0] = reg_tmp & 0x0f; + data->tolerance[1] = (reg_tmp >> 4) & 0x0f; + + data->last_updated = jiffies; + data->valid = 1; + + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init +sensors_w83l786ng_init(void) +{ + return i2c_add_driver(&w83l786ng_driver); +} + +static void __exit +sensors_w83l786ng_exit(void) +{ + i2c_del_driver(&w83l786ng_driver); +} + +MODULE_AUTHOR("Kevin Lo"); +MODULE_DESCRIPTION("w83l786ng driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83l786ng_init); +module_exit(sensors_w83l786ng_exit); diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index fde297b21ad7..7dee001e5133 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -71,7 +71,6 @@ static struct i2c_driver eeprom_driver = { .driver = { .name = "eeprom", }, - .id = I2C_DRIVERID_EEPROM, .attach_adapter = eeprom_attach_adapter, .detach_client = eeprom_detach_client, }; diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index b3b830ccf209..e5b31329b56e 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -67,7 +67,6 @@ static struct i2c_driver pcf8574_driver = { .driver = { .name = "pcf8574", }, - .id = I2C_DRIVERID_PCF8574, .attach_adapter = pcf8574_attach_adapter, .detach_client = pcf8574_detach_client, }; diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c index 865f4409c06b..66c7c3bb9429 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/i2c/chips/pcf8591.c @@ -92,7 +92,6 @@ static struct i2c_driver pcf8591_driver = { .driver = { .name = "pcf8591", }, - .id = I2C_DRIVERID_PCF8591, .attach_adapter = pcf8591_attach_adapter, .detach_client = pcf8591_detach_client, }; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 78cd33861766..7b5220ca7d7f 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -285,4 +285,13 @@ config INTEL_MENLOW If unsure, say N. +config ENCLOSURE_SERVICES + tristate "Enclosure Services" + default n + help + Provides support for intelligent enclosures (bays which + contain storage devices). You also need either a host + driver (SCSI/ATA) which supports enclosures + or a SCSI enclosure device (SES) to use these services. + endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 1f41654aae4d..7f13549cc87e 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o +obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c new file mode 100644 index 000000000000..6fcb0e96adf4 --- /dev/null +++ b/drivers/misc/enclosure.c @@ -0,0 +1,484 @@ +/* + * Enclosure Services + * + * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com> + * +**----------------------------------------------------------------------------- +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** version 2 as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +**----------------------------------------------------------------------------- +*/ +#include <linux/device.h> +#include <linux/enclosure.h> +#include <linux/err.h> +#include <linux/list.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> + +static LIST_HEAD(container_list); +static DEFINE_MUTEX(container_list_lock); +static struct class enclosure_class; +static struct class enclosure_component_class; + +/** + * enclosure_find - find an enclosure given a device + * @dev: the device to find for + * + * Looks through the list of registered enclosures to see + * if it can find a match for a device. Returns NULL if no + * enclosure is found. Obtains a reference to the enclosure class + * device which must be released with class_device_put(). + */ +struct enclosure_device *enclosure_find(struct device *dev) +{ + struct enclosure_device *edev = NULL; + + mutex_lock(&container_list_lock); + list_for_each_entry(edev, &container_list, node) { + if (edev->cdev.dev == dev) { + class_device_get(&edev->cdev); + mutex_unlock(&container_list_lock); + return edev; + } + } + mutex_unlock(&container_list_lock); + + return NULL; +} +EXPORT_SYMBOL_GPL(enclosure_find); + +/** + * enclosure_for_each_device - calls a function for each enclosure + * @fn: the function to call + * @data: the data to pass to each call + * + * Loops over all the enclosures calling the function. + * + * Note, this function uses a mutex which will be held across calls to + * @fn, so it must have non atomic context, and @fn may (although it + * should not) sleep or otherwise cause the mutex to be held for + * indefinite periods + */ +int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *), + void *data) +{ + int error = 0; + struct enclosure_device *edev; + + mutex_lock(&container_list_lock); + list_for_each_entry(edev, &container_list, node) { + error = fn(edev, data); + if (error) + break; + } + mutex_unlock(&container_list_lock); + + return error; +} +EXPORT_SYMBOL_GPL(enclosure_for_each_device); + +/** + * enclosure_register - register device as an enclosure + * + * @dev: device containing the enclosure + * @components: number of components in the enclosure + * + * This sets up the device for being an enclosure. Note that @dev does + * not have to be a dedicated enclosure device. It may be some other type + * of device that additionally responds to enclosure services + */ +struct enclosure_device * +enclosure_register(struct device *dev, const char *name, int components, + struct enclosure_component_callbacks *cb) +{ + struct enclosure_device *edev = + kzalloc(sizeof(struct enclosure_device) + + sizeof(struct enclosure_component)*components, + GFP_KERNEL); + int err, i; + + BUG_ON(!cb); + + if (!edev) + return ERR_PTR(-ENOMEM); + + edev->components = components; + + edev->cdev.class = &enclosure_class; + edev->cdev.dev = get_device(dev); + edev->cb = cb; + snprintf(edev->cdev.class_id, BUS_ID_SIZE, "%s", name); + err = class_device_register(&edev->cdev); + if (err) + goto err; + + for (i = 0; i < components; i++) + edev->component[i].number = -1; + + mutex_lock(&container_list_lock); + list_add_tail(&edev->node, &container_list); + mutex_unlock(&container_list_lock); + + return edev; + + err: + put_device(edev->cdev.dev); + kfree(edev); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(enclosure_register); + +static struct enclosure_component_callbacks enclosure_null_callbacks; + +/** + * enclosure_unregister - remove an enclosure + * + * @edev: the registered enclosure to remove; + */ +void enclosure_unregister(struct enclosure_device *edev) +{ + int i; + + mutex_lock(&container_list_lock); + list_del(&edev->node); + mutex_unlock(&container_list_lock); + + for (i = 0; i < edev->components; i++) + if (edev->component[i].number != -1) + class_device_unregister(&edev->component[i].cdev); + + /* prevent any callbacks into service user */ + edev->cb = &enclosure_null_callbacks; + class_device_unregister(&edev->cdev); +} +EXPORT_SYMBOL_GPL(enclosure_unregister); + +static void enclosure_release(struct class_device *cdev) +{ + struct enclosure_device *edev = to_enclosure_device(cdev); + + put_device(cdev->dev); + kfree(edev); +} + +static void enclosure_component_release(struct class_device *cdev) +{ + if (cdev->dev) + put_device(cdev->dev); + class_device_put(cdev->parent); +} + +/** + * enclosure_component_register - add a particular component to an enclosure + * @edev: the enclosure to add the component + * @num: the device number + * @type: the type of component being added + * @name: an optional name to appear in sysfs (leave NULL if none) + * + * Registers the component. The name is optional for enclosures that + * give their components a unique name. If not, leave the field NULL + * and a name will be assigned. + * + * Returns a pointer to the enclosure component or an error. + */ +struct enclosure_component * +enclosure_component_register(struct enclosure_device *edev, + unsigned int number, + enum enclosure_component_type type, + const char *name) +{ + struct enclosure_component *ecomp; + struct class_device *cdev; + int err; + + if (number >= edev->components) + return ERR_PTR(-EINVAL); + + ecomp = &edev->component[number]; + + if (ecomp->number != -1) + return ERR_PTR(-EINVAL); + + ecomp->type = type; + ecomp->number = number; + cdev = &ecomp->cdev; + cdev->parent = class_device_get(&edev->cdev); + cdev->class = &enclosure_component_class; + if (name) + snprintf(cdev->class_id, BUS_ID_SIZE, "%s", name); + else + snprintf(cdev->class_id, BUS_ID_SIZE, "%u", number); + + err = class_device_register(cdev); + if (err) + ERR_PTR(err); + + return ecomp; +} +EXPORT_SYMBOL_GPL(enclosure_component_register); + +/** + * enclosure_add_device - add a device as being part of an enclosure + * @edev: the enclosure device being added to. + * @num: the number of the component + * @dev: the device being added + * + * Declares a real device to reside in slot (or identifier) @num of an + * enclosure. This will cause the relevant sysfs links to appear. + * This function may also be used to change a device associated with + * an enclosure without having to call enclosure_remove_device() in + * between. + * + * Returns zero on success or an error. + */ +int enclosure_add_device(struct enclosure_device *edev, int component, + struct device *dev) +{ + struct class_device *cdev; + + if (!edev || component >= edev->components) + return -EINVAL; + + cdev = &edev->component[component].cdev; + + class_device_del(cdev); + if (cdev->dev) + put_device(cdev->dev); + cdev->dev = get_device(dev); + return class_device_add(cdev); +} +EXPORT_SYMBOL_GPL(enclosure_add_device); + +/** + * enclosure_remove_device - remove a device from an enclosure + * @edev: the enclosure device + * @num: the number of the component to remove + * + * Returns zero on success or an error. + * + */ +int enclosure_remove_device(struct enclosure_device *edev, int component) +{ + struct class_device *cdev; + + if (!edev || component >= edev->components) + return -EINVAL; + + cdev = &edev->component[component].cdev; + + class_device_del(cdev); + if (cdev->dev) + put_device(cdev->dev); + cdev->dev = NULL; + return class_device_add(cdev); +} +EXPORT_SYMBOL_GPL(enclosure_remove_device); + +/* + * sysfs pieces below + */ + +static ssize_t enclosure_show_components(struct class_device *cdev, char *buf) +{ + struct enclosure_device *edev = to_enclosure_device(cdev); + + return snprintf(buf, 40, "%d\n", edev->components); +} + +static struct class_device_attribute enclosure_attrs[] = { + __ATTR(components, S_IRUGO, enclosure_show_components, NULL), + __ATTR_NULL +}; + +static struct class enclosure_class = { + .name = "enclosure", + .owner = THIS_MODULE, + .release = enclosure_release, + .class_dev_attrs = enclosure_attrs, +}; + +static const char *const enclosure_status [] = { + [ENCLOSURE_STATUS_UNSUPPORTED] = "unsupported", + [ENCLOSURE_STATUS_OK] = "OK", + [ENCLOSURE_STATUS_CRITICAL] = "critical", + [ENCLOSURE_STATUS_NON_CRITICAL] = "non-critical", + [ENCLOSURE_STATUS_UNRECOVERABLE] = "unrecoverable", + [ENCLOSURE_STATUS_NOT_INSTALLED] = "not installed", + [ENCLOSURE_STATUS_UNKNOWN] = "unknown", + [ENCLOSURE_STATUS_UNAVAILABLE] = "unavailable", +}; + +static const char *const enclosure_type [] = { + [ENCLOSURE_COMPONENT_DEVICE] = "device", + [ENCLOSURE_COMPONENT_ARRAY_DEVICE] = "array device", +}; + +static ssize_t get_component_fault(struct class_device *cdev, char *buf) +{ + struct enclosure_device *edev = to_enclosure_device(cdev->parent); + struct enclosure_component *ecomp = to_enclosure_component(cdev); + + if (edev->cb->get_fault) + edev->cb->get_fault(edev, ecomp); + return snprintf(buf, 40, "%d\n", ecomp->fault); +} + +static ssize_t set_component_fault(struct class_device *cdev, const char *buf, + size_t count) +{ + struct enclosure_device *edev = to_enclosure_device(cdev->parent); + struct enclosure_component *ecomp = to_enclosure_component(cdev); + int val = simple_strtoul(buf, NULL, 0); + + if (edev->cb->set_fault) + edev->cb->set_fault(edev, ecomp, val); + return count; +} + +static ssize_t get_component_status(struct class_device *cdev, char *buf) +{ + struct enclosure_device *edev = to_enclosure_device(cdev->parent); + struct enclosure_component *ecomp = to_enclosure_component(cdev); + + if (edev->cb->get_status) + edev->cb->get_status(edev, ecomp); + return snprintf(buf, 40, "%s\n", enclosure_status[ecomp->status]); +} + +static ssize_t set_component_status(struct class_device *cdev, const char *buf, + size_t count) +{ + struct enclosure_device *edev = to_enclosure_device(cdev->parent); + struct enclosure_component *ecomp = to_enclosure_component(cdev); + int i; + + for (i = 0; enclosure_status[i]; i++) { + if (strncmp(buf, enclosure_status[i], + strlen(enclosure_status[i])) == 0 && + (buf[strlen(enclosure_status[i])] == '\n' || + buf[strlen(enclosure_status[i])] == '\0')) + break; + } + + if (enclosure_status[i] && edev->cb->set_status) { + edev->cb->set_status(edev, ecomp, i); + return count; + } else + return -EINVAL; +} + +static ssize_t get_component_active(struct class_device *cdev, char *buf) +{ + struct enclosure_device *edev = to_enclosure_device(cdev->parent); + struct enclosure_component *ecomp = to_enclosure_component(cdev); + + if (edev->cb->get_active) + edev->cb->get_active(edev, ecomp); + return snprintf(buf, 40, "%d\n", ecomp->active); +} + +static ssize_t set_component_active(struct class_device *cdev, const char *buf, + size_t count) +{ + struct enclosure_device *edev = to_enclosure_device(cdev->parent); + struct enclosure_component *ecomp = to_enclosure_component(cdev); + int val = simple_strtoul(buf, NULL, 0); + + if (edev->cb->set_active) + edev->cb->set_active(edev, ecomp, val); + return count; +} + +static ssize_t get_component_locate(struct class_device *cdev, char *buf) +{ + struct enclosure_device *edev = to_enclosure_device(cdev->parent); + struct enclosure_component *ecomp = to_enclosure_component(cdev); + + if (edev->cb->get_locate) + edev->cb->get_locate(edev, ecomp); + return snprintf(buf, 40, "%d\n", ecomp->locate); +} + +static ssize_t set_component_locate(struct class_device *cdev, const char *buf, + size_t count) +{ + struct enclosure_device *edev = to_enclosure_device(cdev->parent); + struct enclosure_component *ecomp = to_enclosure_component(cdev); + int val = simple_strtoul(buf, NULL, 0); + + if (edev->cb->set_locate) + edev->cb->set_locate(edev, ecomp, val); + return count; +} + +static ssize_t get_component_type(struct class_device *cdev, char *buf) +{ + struct enclosure_component *ecomp = to_enclosure_component(cdev); + + return snprintf(buf, 40, "%s\n", enclosure_type[ecomp->type]); +} + + +static struct class_device_attribute enclosure_component_attrs[] = { + __ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault, + set_component_fault), + __ATTR(status, S_IRUGO | S_IWUSR, get_component_status, + set_component_status), + __ATTR(active, S_IRUGO | S_IWUSR, get_component_active, + set_component_active), + __ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate, + set_component_locate), + __ATTR(type, S_IRUGO, get_component_type, NULL), + __ATTR_NULL +}; + +static struct class enclosure_component_class = { + .name = "enclosure_component", + .owner = THIS_MODULE, + .class_dev_attrs = enclosure_component_attrs, + .release = enclosure_component_release, +}; + +static int __init enclosure_init(void) +{ + int err; + + err = class_register(&enclosure_class); + if (err) + return err; + err = class_register(&enclosure_component_class); + if (err) + goto err_out; + + return 0; + err_out: + class_unregister(&enclosure_class); + + return err; +} + +static void __exit enclosure_exit(void) +{ + class_unregister(&enclosure_component_class); + class_unregister(&enclosure_class); +} + +module_init(enclosure_init); +module_exit(enclosure_exit); + +MODULE_AUTHOR("James Bottomley"); +MODULE_DESCRIPTION("Enclosure Services"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 14fc7f39e83e..a5f0aaaf0dd4 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -179,7 +179,15 @@ config CHR_DEV_SCH say M here and read <file:Documentation/kbuild/modules.txt> and <file:Documentation/scsi/scsi.txt>. The module will be called ch.o. If unsure, say N. - + +config SCSI_ENCLOSURE + tristate "SCSI Enclosure Support" + depends on SCSI && ENCLOSURE_SERVICES + help + Enclosures are devices sitting on or in SCSI backplanes that + manage devices. If you have a disk cage, the chances are that + it has an enclosure device. Selecting this option will just allow + certain enclosure conditions to be reported and is not required. comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" depends on SCSI @@ -350,17 +358,6 @@ config SGIWD93_SCSI If you have a Western Digital WD93 SCSI controller on an SGI MIPS system, say Y. Otherwise, say N. -config SCSI_DECNCR - tristate "DEC NCR53C94 Scsi Driver" - depends on MACH_DECSTATION && SCSI && TC - help - Say Y here to support the NCR53C94 SCSI controller chips on IOASIC - based TURBOchannel DECstations and TURBOchannel PMAZ-A cards. - -config SCSI_DECSII - tristate "DEC SII Scsi Driver" - depends on MACH_DECSTATION && SCSI && 32BIT - config BLK_DEV_3W_XXXX_RAID tristate "3ware 5/6/7/8xxx ATA-RAID support" depends on PCI && SCSI @@ -1263,17 +1260,6 @@ config SCSI_NCR53C8XX_NO_DISCONNECT not allow targets to disconnect is not reasonable if there is more than 1 device on a SCSI bus. The normal answer therefore is N. -config SCSI_MCA_53C9X - tristate "NCR MCA 53C9x SCSI support" - depends on MCA_LEGACY && SCSI && BROKEN_ON_SMP - help - Some MicroChannel machines, notably the NCR 35xx line, use a SCSI - controller based on the NCR 53C94. This driver will allow use of - the controller on the 3550, and very possibly others. - - To compile this driver as a module, choose M here: the - module will be called mca_53c9x. - config SCSI_PAS16 tristate "PAS16 SCSI support" depends on ISA && SCSI @@ -1600,45 +1586,6 @@ config GVP11_SCSI To compile this driver as a module, choose M here: the module will be called gvp11. -config CYBERSTORM_SCSI - tristate "CyberStorm SCSI support" - depends on ZORRO && SCSI - help - If you have an Amiga with an original (MkI) Phase5 Cyberstorm - accelerator board and the optional Cyberstorm SCSI controller, - answer Y. Otherwise, say N. - -config CYBERSTORMII_SCSI - tristate "CyberStorm Mk II SCSI support" - depends on ZORRO && SCSI - help - If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board - and the optional Cyberstorm SCSI controller, say Y. Otherwise, - answer N. - -config BLZ2060_SCSI - tristate "Blizzard 2060 SCSI support" - depends on ZORRO && SCSI - help - If you have an Amiga with a Phase5 Blizzard 2060 accelerator board - and want to use the onboard SCSI controller, say Y. Otherwise, - answer N. - -config BLZ1230_SCSI - tristate "Blizzard 1230IV/1260 SCSI support" - depends on ZORRO && SCSI - help - If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard - 1260 accelerator, and the optional SCSI module, say Y. Otherwise, - say N. - -config FASTLANE_SCSI - tristate "Fastlane SCSI support" - depends on ZORRO && SCSI - help - If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use - one in the near future, say Y to this question. Otherwise, say N. - config SCSI_A4000T tristate "A4000T NCR53c710 SCSI support (EXPERIMENTAL)" depends on AMIGA && SCSI && EXPERIMENTAL @@ -1666,15 +1613,6 @@ config SCSI_ZORRO7XX accelerator card for the Amiga 1200, - the SCSI controller on the GVP Turbo 040/060 accelerator. -config OKTAGON_SCSI - tristate "BSC Oktagon SCSI support (EXPERIMENTAL)" - depends on ZORRO && SCSI && EXPERIMENTAL - help - If you have the BSC Oktagon SCSI disk controller for the Amiga, say - Y to this question. If you're in doubt about whether you have one, - see the picture at - <http://amiga.resource.cx/exp/search.pl?product=oktagon>. - config ATARI_SCSI tristate "Atari native SCSI support" depends on ATARI && SCSI @@ -1727,18 +1665,6 @@ config MAC_SCSI SCSI-HOWTO, available from <http://www.tldp.org/docs.html#howto>. -config SCSI_MAC_ESP - tristate "Macintosh NCR53c9[46] SCSI" - depends on MAC && SCSI - help - This is the NCR 53c9x SCSI controller found on most of the 68040 - based Macintoshes. If you have one of these say Y and read the - SCSI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - To compile this driver as a module, choose M here: the - module will be called mac_esp. - config MVME147_SCSI bool "WD33C93 SCSI driver for MVME147" depends on MVME147 && SCSI=y @@ -1779,6 +1705,7 @@ config SUN3_SCSI config SUN3X_ESP bool "Sun3x ESP SCSI" depends on SUN3X && SCSI=y + select SCSI_SPI_ATTRS help The ESP was an on-board SCSI controller used on Sun 3/80 machines. Say Y here to compile in support for it. diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 93e1428d03fc..925c26b4fff9 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -44,15 +44,8 @@ obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o obj-$(CONFIG_MVME147_SCSI) += mvme147.o wd33c93.o obj-$(CONFIG_SGIWD93_SCSI) += sgiwd93.o wd33c93.o -obj-$(CONFIG_CYBERSTORM_SCSI) += NCR53C9x.o cyberstorm.o -obj-$(CONFIG_CYBERSTORMII_SCSI) += NCR53C9x.o cyberstormII.o -obj-$(CONFIG_BLZ2060_SCSI) += NCR53C9x.o blz2060.o -obj-$(CONFIG_BLZ1230_SCSI) += NCR53C9x.o blz1230.o -obj-$(CONFIG_FASTLANE_SCSI) += NCR53C9x.o fastlane.o -obj-$(CONFIG_OKTAGON_SCSI) += NCR53C9x.o oktagon_esp_mod.o obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o obj-$(CONFIG_MAC_SCSI) += mac_scsi.o -obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o obj-$(CONFIG_MVME16x_SCSI) += 53c700.o mvme16x_scsi.o obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o @@ -95,7 +88,6 @@ obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/ obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o obj-$(CONFIG_SCSI_7000FASST) += wd7000.o -obj-$(CONFIG_SCSI_MCA_53C9X) += NCR53C9x.o mca_53c9x.o obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o obj-$(CONFIG_SCSI_EATA) += eata.o obj-$(CONFIG_SCSI_DC395x) += dc395x.o @@ -112,13 +104,12 @@ obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o obj-$(CONFIG_BLK_DEV_IDESCSI) += ide-scsi.o obj-$(CONFIG_SCSI_MESH) += mesh.o obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o -obj-$(CONFIG_SCSI_DECNCR) += NCR53C9x.o dec_esp.o obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o obj-$(CONFIG_SCSI_PPA) += ppa.o obj-$(CONFIG_SCSI_IMM) += imm.o obj-$(CONFIG_JAZZ_ESP) += esp_scsi.o jazz_esp.o -obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o +obj-$(CONFIG_SUN3X_ESP) += esp_scsi.o sun3x_esp.o obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o obj-$(CONFIG_SCSI_SNI_53C710) += 53c700.o sni_53c710.o obj-$(CONFIG_SCSI_NSP32) += nsp32.o @@ -138,6 +129,7 @@ obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o obj-$(CONFIG_CHR_DEV_SCH) += ch.o +obj-$(CONFIG_SCSI_ENCLOSURE) += ses.o # This goes last, so that "real" scsi devices probe earlier obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c deleted file mode 100644 index 5b0efc903918..000000000000 --- a/drivers/scsi/NCR53C9x.c +++ /dev/null @@ -1,3654 +0,0 @@ -/* NCR53C9x.c: Generic SCSI driver code for NCR53C9x chips. - * - * Originally esp.c : EnhancedScsiProcessor Sun SCSI driver code. - * - * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu) - * - * Most DMA dependencies put in driver specific files by - * Jesper Skov (jskov@cygnus.co.uk) - * - * Set up to use esp_read/esp_write (preprocessor macros in NCR53c9x.h) by - * Tymm Twillman (tymm@coe.missouri.edu) - */ - -/* TODO: - * - * 1) Maybe disable parity checking in config register one for SCSI1 - * targets. (Gilmore says parity error on the SBus can lock up - * old sun4c's) - * 2) Add support for DMA2 pipelining. - * 3) Add tagged queueing. - * 4) Maybe change use of "esp" to something more "NCR"'ish. - */ - -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/blkdev.h> -#include <linux/interrupt.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/init.h> - -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "NCR53C9x.h" - -#include <asm/system.h> -#include <asm/ptrace.h> -#include <asm/pgtable.h> -#include <asm/io.h> -#include <asm/irq.h> - -/* Command phase enumeration. */ -enum { - not_issued = 0x00, /* Still in the issue_SC queue. */ - - /* Various forms of selecting a target. */ -#define in_slct_mask 0x10 - in_slct_norm = 0x10, /* ESP is arbitrating, normal selection */ - in_slct_stop = 0x11, /* ESP will select, then stop with IRQ */ - in_slct_msg = 0x12, /* select, then send a message */ - in_slct_tag = 0x13, /* select and send tagged queue msg */ - in_slct_sneg = 0x14, /* select and acquire sync capabilities */ - - /* Any post selection activity. */ -#define in_phases_mask 0x20 - in_datain = 0x20, /* Data is transferring from the bus */ - in_dataout = 0x21, /* Data is transferring to the bus */ - in_data_done = 0x22, /* Last DMA data operation done (maybe) */ - in_msgin = 0x23, /* Eating message from target */ - in_msgincont = 0x24, /* Eating more msg bytes from target */ - in_msgindone = 0x25, /* Decide what to do with what we got */ - in_msgout = 0x26, /* Sending message to target */ - in_msgoutdone = 0x27, /* Done sending msg out */ - in_cmdbegin = 0x28, /* Sending cmd after abnormal selection */ - in_cmdend = 0x29, /* Done sending slow cmd */ - in_status = 0x2a, /* Was in status phase, finishing cmd */ - in_freeing = 0x2b, /* freeing the bus for cmd cmplt or disc */ - in_the_dark = 0x2c, /* Don't know what bus phase we are in */ - - /* Special states, ie. not normal bus transitions... */ -#define in_spec_mask 0x80 - in_abortone = 0x80, /* Aborting one command currently */ - in_abortall = 0x81, /* Blowing away all commands we have */ - in_resetdev = 0x82, /* SCSI target reset in progress */ - in_resetbus = 0x83, /* SCSI bus reset in progress */ - in_tgterror = 0x84, /* Target did something stupid */ -}; - -enum { - /* Zero has special meaning, see skipahead[12]. */ -/*0*/ do_never, - -/*1*/ do_phase_determine, -/*2*/ do_reset_bus, -/*3*/ do_reset_complete, -/*4*/ do_work_bus, -/*5*/ do_intr_end -}; - -/* The master ring of all esp hosts we are managing in this driver. */ -static struct NCR_ESP *espchain; -int nesps = 0, esps_in_use = 0, esps_running = 0; -EXPORT_SYMBOL(nesps); -EXPORT_SYMBOL(esps_running); - -irqreturn_t esp_intr(int irq, void *dev_id); - -/* Debugging routines */ -static struct esp_cmdstrings { - unchar cmdchar; - char *text; -} esp_cmd_strings[] = { - /* Miscellaneous */ - { ESP_CMD_NULL, "ESP_NOP", }, - { ESP_CMD_FLUSH, "FIFO_FLUSH", }, - { ESP_CMD_RC, "RSTESP", }, - { ESP_CMD_RS, "RSTSCSI", }, - /* Disconnected State Group */ - { ESP_CMD_RSEL, "RESLCTSEQ", }, - { ESP_CMD_SEL, "SLCTNATN", }, - { ESP_CMD_SELA, "SLCTATN", }, - { ESP_CMD_SELAS, "SLCTATNSTOP", }, - { ESP_CMD_ESEL, "ENSLCTRESEL", }, - { ESP_CMD_DSEL, "DISSELRESEL", }, - { ESP_CMD_SA3, "SLCTATN3", }, - { ESP_CMD_RSEL3, "RESLCTSEQ", }, - /* Target State Group */ - { ESP_CMD_SMSG, "SNDMSG", }, - { ESP_CMD_SSTAT, "SNDSTATUS", }, - { ESP_CMD_SDATA, "SNDDATA", }, - { ESP_CMD_DSEQ, "DISCSEQ", }, - { ESP_CMD_TSEQ, "TERMSEQ", }, - { ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", }, - { ESP_CMD_DCNCT, "DISC", }, - { ESP_CMD_RMSG, "RCVMSG", }, - { ESP_CMD_RCMD, "RCVCMD", }, - { ESP_CMD_RDATA, "RCVDATA", }, - { ESP_CMD_RCSEQ, "RCVCMDSEQ", }, - /* Initiator State Group */ - { ESP_CMD_TI, "TRANSINFO", }, - { ESP_CMD_ICCSEQ, "INICMDSEQCOMP", }, - { ESP_CMD_MOK, "MSGACCEPTED", }, - { ESP_CMD_TPAD, "TPAD", }, - { ESP_CMD_SATN, "SATN", }, - { ESP_CMD_RATN, "RATN", }, -}; -#define NUM_ESP_COMMANDS ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings))) - -/* Print textual representation of an ESP command */ -static inline void esp_print_cmd(unchar espcmd) -{ - unchar dma_bit = espcmd & ESP_CMD_DMA; - int i; - - espcmd &= ~dma_bit; - for(i=0; i<NUM_ESP_COMMANDS; i++) - if(esp_cmd_strings[i].cmdchar == espcmd) - break; - if(i==NUM_ESP_COMMANDS) - printk("ESP_Unknown"); - else - printk("%s%s", esp_cmd_strings[i].text, - ((dma_bit) ? "+DMA" : "")); -} - -/* Print the status register's value */ -static inline void esp_print_statreg(unchar statreg) -{ - unchar phase; - - printk("STATUS<"); - phase = statreg & ESP_STAT_PMASK; - printk("%s,", (phase == ESP_DOP ? "DATA-OUT" : - (phase == ESP_DIP ? "DATA-IN" : - (phase == ESP_CMDP ? "COMMAND" : - (phase == ESP_STATP ? "STATUS" : - (phase == ESP_MOP ? "MSG-OUT" : - (phase == ESP_MIP ? "MSG_IN" : - "unknown"))))))); - if(statreg & ESP_STAT_TDONE) - printk("TRANS_DONE,"); - if(statreg & ESP_STAT_TCNT) - printk("TCOUNT_ZERO,"); - if(statreg & ESP_STAT_PERR) - printk("P_ERROR,"); - if(statreg & ESP_STAT_SPAM) - printk("SPAM,"); - if(statreg & ESP_STAT_INTR) - printk("IRQ,"); - printk(">"); -} - -/* Print the interrupt register's value */ -static inline void esp_print_ireg(unchar intreg) -{ - printk("INTREG< "); - if(intreg & ESP_INTR_S) - printk("SLCT_NATN "); - if(intreg & ESP_INTR_SATN) - printk("SLCT_ATN "); - if(intreg & ESP_INTR_RSEL) - printk("RSLCT "); - if(intreg & ESP_INTR_FDONE) - printk("FDONE "); - if(intreg & ESP_INTR_BSERV) - printk("BSERV "); - if(intreg & ESP_INTR_DC) - printk("DISCNCT "); - if(intreg & ESP_INTR_IC) - printk("ILL_CMD "); - if(intreg & ESP_INTR_SR) - printk("SCSI_BUS_RESET "); - printk(">"); -} - -/* Print the sequence step registers contents */ -static inline void esp_print_seqreg(unchar stepreg) -{ - stepreg &= ESP_STEP_VBITS; - printk("STEP<%s>", - (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" : - (stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" : - (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" : - (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" : - (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" : - "UNKNOWN")))))); -} - -static char *phase_string(int phase) -{ - switch(phase) { - case not_issued: - return "UNISSUED"; - case in_slct_norm: - return "SLCTNORM"; - case in_slct_stop: - return "SLCTSTOP"; - case in_slct_msg: - return "SLCTMSG"; - case in_slct_tag: - return "SLCTTAG"; - case in_slct_sneg: - return "SLCTSNEG"; - case in_datain: - return "DATAIN"; - case in_dataout: - return "DATAOUT"; - case in_data_done: - return "DATADONE"; - case in_msgin: - return "MSGIN"; - case in_msgincont: - return "MSGINCONT"; - case in_msgindone: - return "MSGINDONE"; - case in_msgout: - return "MSGOUT"; - case in_msgoutdone: - return "MSGOUTDONE"; - case in_cmdbegin: - return "CMDBEGIN"; - case in_cmdend: - return "CMDEND"; - case in_status: - return "STATUS"; - case in_freeing: - return "FREEING"; - case in_the_dark: - return "CLUELESS"; - case in_abortone: - return "ABORTONE"; - case in_abortall: - return "ABORTALL"; - case in_resetdev: - return "RESETDEV"; - case in_resetbus: - return "RESETBUS"; - case in_tgterror: - return "TGTERROR"; - default: - return "UNKNOWN"; - }; -} - -#ifdef DEBUG_STATE_MACHINE -static inline void esp_advance_phase(Scsi_Cmnd *s, int newphase) -{ - ESPLOG(("<%s>", phase_string(newphase))); - s->SCp.sent_command = s->SCp.phase; - s->SCp.phase = newphase; -} -#else -#define esp_advance_phase(__s, __newphase) \ - (__s)->SCp.sent_command = (__s)->SCp.phase; \ - (__s)->SCp.phase = (__newphase); -#endif - -#ifdef DEBUG_ESP_CMDS -static inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs, - unchar cmd) -{ - esp->espcmdlog[esp->espcmdent] = cmd; - esp->espcmdent = (esp->espcmdent + 1) & 31; - esp_write(eregs->esp_cmnd, cmd); -} -#else -#define esp_cmd(__esp, __eregs, __cmd) esp_write((__eregs)->esp_cmnd, (__cmd)) -#endif - -/* How we use the various Linux SCSI data structures for operation. - * - * struct scsi_cmnd: - * - * We keep track of the syncronous capabilities of a target - * in the device member, using sync_min_period and - * sync_max_offset. These are the values we directly write - * into the ESP registers while running a command. If offset - * is zero the ESP will use asynchronous transfers. - * If the borken flag is set we assume we shouldn't even bother - * trying to negotiate for synchronous transfer as this target - * is really stupid. If we notice the target is dropping the - * bus, and we have been allowing it to disconnect, we clear - * the disconnect flag. - */ - -/* Manipulation of the ESP command queues. Thanks to the aha152x driver - * and its author, Juergen E. Fischer, for the methods used here. - * Note that these are per-ESP queues, not global queues like - * the aha152x driver uses. - */ -static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC) -{ - Scsi_Cmnd *end; - - new_SC->host_scribble = (unsigned char *) NULL; - if(!*SC) - *SC = new_SC; - else { - for(end=*SC;end->host_scribble;end=(Scsi_Cmnd *)end->host_scribble) - ; - end->host_scribble = (unsigned char *) new_SC; - } -} - -static inline void prepend_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC) -{ - new_SC->host_scribble = (unsigned char *) *SC; - *SC = new_SC; -} - -static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC) -{ - Scsi_Cmnd *ptr; - - ptr = *SC; - if(ptr) - *SC = (Scsi_Cmnd *) (*SC)->host_scribble; - return ptr; -} - -static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun) -{ - Scsi_Cmnd *ptr, *prev; - - for(ptr = *SC, prev = NULL; - ptr && ((ptr->device->id != target) || (ptr->device->lun != lun)); - prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble) - ; - if(ptr) { - if(prev) - prev->host_scribble=ptr->host_scribble; - else - *SC=(Scsi_Cmnd *)ptr->host_scribble; - } - return ptr; -} - -/* Resetting various pieces of the ESP scsi driver chipset */ - -/* Reset the ESP chip, _not_ the SCSI bus. */ -static void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - int family_code, version, i; - volatile int trash; - - /* Now reset the ESP chip */ - esp_cmd(esp, eregs, ESP_CMD_RC); - esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA); - if(esp->erev == fast) - esp_write(eregs->esp_cfg2, ESP_CONFIG2_FENAB); - esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA); - - /* This is the only point at which it is reliable to read - * the ID-code for a fast ESP chip variant. - */ - esp->max_period = ((35 * esp->ccycle) / 1000); - if(esp->erev == fast) { - char *erev2string[] = { - "Emulex FAS236", - "Emulex FPESP100A", - "fast", - "QLogic FAS366", - "Emulex FAS216", - "Symbios Logic 53CF9x-2", - "unknown!" - }; - - version = esp_read(eregs->esp_uid); - family_code = (version & 0xf8) >> 3; - if(family_code == 0x02) { - if ((version & 7) == 2) - esp->erev = fas216; - else - esp->erev = fas236; - } else if(family_code == 0x0a) - esp->erev = fas366; /* Version is usually '5'. */ - else if(family_code == 0x00) { - if ((version & 7) == 2) - esp->erev = fas100a; /* NCR53C9X */ - else - esp->erev = espunknown; - } else if(family_code == 0x14) { - if ((version & 7) == 2) - esp->erev = fsc; - else - esp->erev = espunknown; - } else if(family_code == 0x00) { - if ((version & 7) == 2) - esp->erev = fas100a; /* NCR53C9X */ - else - esp->erev = espunknown; - } else - esp->erev = espunknown; - ESPLOG(("esp%d: FAST chip is %s (family=%d, version=%d)\n", - esp->esp_id, erev2string[esp->erev - fas236], - family_code, (version & 7))); - - esp->min_period = ((4 * esp->ccycle) / 1000); - } else { - esp->min_period = ((5 * esp->ccycle) / 1000); - } - - /* Reload the configuration registers */ - esp_write(eregs->esp_cfact, esp->cfact); - esp->prev_stp = 0; - esp_write(eregs->esp_stp, 0); - esp->prev_soff = 0; - esp_write(eregs->esp_soff, 0); - esp_write(eregs->esp_timeo, esp->neg_defp); - esp->max_period = (esp->max_period + 3)>>2; - esp->min_period = (esp->min_period + 3)>>2; - - esp_write(eregs->esp_cfg1, esp->config1); - switch(esp->erev) { - case esp100: - /* nothing to do */ - break; - case esp100a: - esp_write(eregs->esp_cfg2, esp->config2); - break; - case esp236: - /* Slow 236 */ - esp_write(eregs->esp_cfg2, esp->config2); - esp->prev_cfg3 = esp->config3[0]; - esp_write(eregs->esp_cfg3, esp->prev_cfg3); - break; - case fas366: - panic("esp: FAS366 support not present, please notify " - "jongk@cs.utwente.nl"); - break; - case fas216: - case fas236: - case fsc: - /* Fast ESP variants */ - esp_write(eregs->esp_cfg2, esp->config2); - for(i=0; i<8; i++) - esp->config3[i] |= ESP_CONFIG3_FCLK; - esp->prev_cfg3 = esp->config3[0]; - esp_write(eregs->esp_cfg3, esp->prev_cfg3); - if(esp->diff) - esp->radelay = 0; - else - esp->radelay = 16; - /* Different timeout constant for these chips */ - esp->neg_defp = - FSC_NEG_DEFP(esp->cfreq, - (esp->cfact == ESP_CCF_F0 ? - ESP_CCF_F7 + 1 : esp->cfact)); - esp_write(eregs->esp_timeo, esp->neg_defp); - /* Enable Active Negotiation if possible */ - if((esp->erev == fsc) && !esp->diff) - esp_write(eregs->esp_cfg4, ESP_CONFIG4_EAN); - break; - case fas100a: - /* Fast 100a */ - esp_write(eregs->esp_cfg2, esp->config2); - for(i=0; i<8; i++) - esp->config3[i] |= ESP_CONFIG3_FCLOCK; - esp->prev_cfg3 = esp->config3[0]; - esp_write(eregs->esp_cfg3, esp->prev_cfg3); - esp->radelay = 32; - break; - default: - panic("esp: what could it be... I wonder..."); - break; - }; - - /* Eat any bitrot in the chip */ - trash = esp_read(eregs->esp_intrpt); - udelay(100); -} - -/* This places the ESP into a known state at boot time. */ -void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - volatile unchar trash; - - /* Reset the DMA */ - if(esp->dma_reset) - esp->dma_reset(esp); - - /* Reset the ESP */ - esp_reset_esp(esp, eregs); - - /* Reset the SCSI bus, but tell ESP not to generate an irq */ - esp_write(eregs->esp_cfg1, (esp_read(eregs->esp_cfg1) | ESP_CONFIG1_SRRDISAB)); - esp_cmd(esp, eregs, ESP_CMD_RS); - udelay(400); - esp_write(eregs->esp_cfg1, esp->config1); - - /* Eat any bitrot in the chip and we are done... */ - trash = esp_read(eregs->esp_intrpt); -} -EXPORT_SYMBOL(esp_bootup_reset); - -/* Allocate structure and insert basic data such as SCSI chip frequency - * data and a pointer to the device - */ -struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev, - int hotplug) -{ - struct NCR_ESP *esp, *elink; - struct Scsi_Host *esp_host; - - if (hotplug) - esp_host = scsi_host_alloc(tpnt, sizeof(struct NCR_ESP)); - else - esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP)); - if(!esp_host) - panic("Cannot register ESP SCSI host"); - esp = (struct NCR_ESP *) esp_host->hostdata; - if(!esp) - panic("No esp in hostdata"); - esp->ehost = esp_host; - esp->edev = esp_dev; - esp->esp_id = nesps++; - - /* Set bitshift value (only used on Amiga with multiple ESPs) */ - esp->shift = 2; - - /* Put into the chain of esp chips detected */ - if(espchain) { - elink = espchain; - while(elink->next) elink = elink->next; - elink->next = esp; - } else { - espchain = esp; - } - esp->next = NULL; - - return esp; -} - -void esp_deallocate(struct NCR_ESP *esp) -{ - struct NCR_ESP *elink; - - if(espchain == esp) { - espchain = NULL; - } else { - for(elink = espchain; elink && (elink->next != esp); elink = elink->next); - if(elink) - elink->next = esp->next; - } - nesps--; -} - -/* Complete initialization of ESP structure and device - * Caller must have initialized appropriate parts of the ESP structure - * between the call to esp_allocate and this function. - */ -void esp_initialize(struct NCR_ESP *esp) -{ - struct ESP_regs *eregs = esp->eregs; - unsigned int fmhz; - unchar ccf; - int i; - - /* Check out the clock properties of the chip. */ - - /* This is getting messy but it has to be done - * correctly or else you get weird behavior all - * over the place. We are trying to basically - * figure out three pieces of information. - * - * a) Clock Conversion Factor - * - * This is a representation of the input - * crystal clock frequency going into the - * ESP on this machine. Any operation whose - * timing is longer than 400ns depends on this - * value being correct. For example, you'll - * get blips for arbitration/selection during - * high load or with multiple targets if this - * is not set correctly. - * - * b) Selection Time-Out - * - * The ESP isn't very bright and will arbitrate - * for the bus and try to select a target - * forever if you let it. This value tells - * the ESP when it has taken too long to - * negotiate and that it should interrupt - * the CPU so we can see what happened. - * The value is computed as follows (from - * NCR/Symbios chip docs). - * - * (Time Out Period) * (Input Clock) - * STO = ---------------------------------- - * (8192) * (Clock Conversion Factor) - * - * You usually want the time out period to be - * around 250ms, I think we'll set it a little - * bit higher to account for fully loaded SCSI - * bus's and slow devices that don't respond so - * quickly to selection attempts. (yeah, I know - * this is out of spec. but there is a lot of - * buggy pieces of firmware out there so bite me) - * - * c) Imperical constants for synchronous offset - * and transfer period register values - * - * This entails the smallest and largest sync - * period we could ever handle on this ESP. - */ - - fmhz = esp->cfreq; - - if(fmhz <= (5000000)) - ccf = 0; - else - ccf = (((5000000 - 1) + (fmhz))/(5000000)); - if(!ccf || ccf > 8) { - /* If we can't find anything reasonable, - * just assume 20MHZ. This is the clock - * frequency of the older sun4c's where I've - * been unable to find the clock-frequency - * PROM property. All other machines provide - * useful values it seems. - */ - ccf = ESP_CCF_F4; - fmhz = (20000000); - } - if(ccf==(ESP_CCF_F7+1)) - esp->cfact = ESP_CCF_F0; - else if(ccf == ESP_CCF_NEVER) - esp->cfact = ESP_CCF_F2; - else - esp->cfact = ccf; - esp->cfreq = fmhz; - esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz); - esp->ctick = ESP_TICK(ccf, esp->ccycle); - esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf); - esp->sync_defp = SYNC_DEFP_SLOW; - - printk("SCSI ID %d Clk %dMHz CCF=%d TOut %d ", - esp->scsi_id, (esp->cfreq / 1000000), - ccf, (int) esp->neg_defp); - - /* Fill in ehost data */ - esp->ehost->base = (unsigned long)eregs; - esp->ehost->this_id = esp->scsi_id; - esp->ehost->irq = esp->irq; - - /* SCSI id mask */ - esp->scsi_id_mask = (1 << esp->scsi_id); - - /* Probe the revision of this esp */ - esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7)); - esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY); - esp_write(eregs->esp_cfg2, esp->config2); - if((esp_read(eregs->esp_cfg2) & ~(ESP_CONFIG2_MAGIC)) != - (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) { - printk("NCR53C90(esp100)\n"); - esp->erev = esp100; - } else { - esp->config2 = 0; - esp_write(eregs->esp_cfg2, 0); - esp_write(eregs->esp_cfg3, 5); - if(esp_read(eregs->esp_cfg3) != 5) { - printk("NCR53C90A(esp100a)\n"); - esp->erev = esp100a; - } else { - int target; - - for(target=0; target<8; target++) - esp->config3[target] = 0; - esp->prev_cfg3 = 0; - esp_write(eregs->esp_cfg3, 0); - if(ccf > ESP_CCF_F5) { - printk("NCR53C9XF(espfast)\n"); - esp->erev = fast; - esp->sync_defp = SYNC_DEFP_FAST; - } else { - printk("NCR53C9x(esp236)\n"); - esp->erev = esp236; - } - } - } - - /* Initialize the command queues */ - esp->current_SC = NULL; - esp->disconnected_SC = NULL; - esp->issue_SC = NULL; - - /* Clear the state machines. */ - esp->targets_present = 0; - esp->resetting_bus = 0; - esp->snip = 0; - - init_waitqueue_head(&esp->reset_queue); - - esp->fas_premature_intr_workaround = 0; - for(i = 0; i < 32; i++) - esp->espcmdlog[i] = 0; - esp->espcmdent = 0; - for(i = 0; i < 16; i++) { - esp->cur_msgout[i] = 0; - esp->cur_msgin[i] = 0; - } - esp->prevmsgout = esp->prevmsgin = 0; - esp->msgout_len = esp->msgin_len = 0; - - /* Clear the one behind caches to hold unmatchable values. */ - esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff; - - /* Reset the thing before we try anything... */ - esp_bootup_reset(esp, eregs); - - esps_in_use++; -} - -/* The info function will return whatever useful - * information the developer sees fit. If not provided, then - * the name field will be used instead. - */ -const char *esp_info(struct Scsi_Host *host) -{ - struct NCR_ESP *esp; - - esp = (struct NCR_ESP *) host->hostdata; - switch(esp->erev) { - case esp100: - return "ESP100 (NCR53C90)"; - case esp100a: - return "ESP100A (NCR53C90A)"; - case esp236: - return "ESP236 (NCR53C9x)"; - case fas216: - return "Emulex FAS216"; - case fas236: - return "Emulex FAS236"; - case fas366: - return "QLogic FAS366"; - case fas100a: - return "FPESP100A"; - case fsc: - return "Symbios Logic 53CF9x-2"; - default: - panic("Bogon ESP revision"); - }; -} -EXPORT_SYMBOL(esp_info); - -/* From Wolfgang Stanglmeier's NCR scsi driver. */ -struct info_str -{ - char *buffer; - int length; - int offset; - int pos; -}; - -static void copy_mem_info(struct info_str *info, char *data, int len) -{ - if (info->pos + len > info->length) - len = info->length - info->pos; - - if (info->pos + len < info->offset) { - info->pos += len; - return; - } - if (info->pos < info->offset) { - data += (info->offset - info->pos); - len -= (info->offset - info->pos); - } - - if (len > 0) { - memcpy(info->buffer + info->pos, data, len); - info->pos += len; - } -} - -static int copy_info(struct info_str *info, char *fmt, ...) -{ - va_list args; - char buf[81]; - int len; - - va_start(args, fmt); - len = vsprintf(buf, fmt, args); - va_end(args); - - copy_mem_info(info, buf, len); - return len; -} - -static int esp_host_info(struct NCR_ESP *esp, char *ptr, off_t offset, int len) -{ - struct scsi_device *sdev; - struct info_str info; - int i; - - info.buffer = ptr; - info.length = len; - info.offset = offset; - info.pos = 0; - - copy_info(&info, "ESP Host Adapter:\n"); - copy_info(&info, "\tESP Model\t\t"); - switch(esp->erev) { - case esp100: - copy_info(&info, "ESP100 (NCR53C90)\n"); - break; - case esp100a: - copy_info(&info, "ESP100A (NCR53C90A)\n"); - break; - case esp236: - copy_info(&info, "ESP236 (NCR53C9x)\n"); - break; - case fas216: - copy_info(&info, "Emulex FAS216\n"); - break; - case fas236: - copy_info(&info, "Emulex FAS236\n"); - break; - case fas100a: - copy_info(&info, "FPESP100A\n"); - break; - case fast: - copy_info(&info, "Generic FAST\n"); - break; - case fas366: - copy_info(&info, "QLogic FAS366\n"); - break; - case fsc: - copy_info(&info, "Symbios Logic 53C9x-2\n"); - break; - case espunknown: - default: - copy_info(&info, "Unknown!\n"); - break; - }; - copy_info(&info, "\tLive Targets\t\t[ "); - for(i = 0; i < 15; i++) { - if(esp->targets_present & (1 << i)) - copy_info(&info, "%d ", i); - } - copy_info(&info, "]\n\n"); - - /* Now describe the state of each existing target. */ - copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\n"); - - shost_for_each_device(sdev, esp->ehost) { - struct esp_device *esp_dev = sdev->hostdata; - uint id = sdev->id; - - if (!(esp->targets_present & (1 << id))) - continue; - - copy_info(&info, "%d\t\t", id); - copy_info(&info, "%08lx\t", esp->config3[id]); - copy_info(&info, "[%02lx,%02lx]\t\t\t", - esp_dev->sync_max_offset, - esp_dev->sync_min_period); - copy_info(&info, "%s\n", esp_dev->disconnect ? "yes" : "no"); - } - - return info.pos > info.offset? info.pos - info.offset : 0; -} - -/* ESP proc filesystem code. */ -int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, - int inout) -{ - struct NCR_ESP *esp = (struct NCR_ESP *)shost->hostdata; - - if(inout) - return -EINVAL; /* not yet */ - if(start) - *start = buffer; - return esp_host_info(esp, buffer, offset, length); -} -EXPORT_SYMBOL(esp_proc_info); - -static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - if(sp->use_sg == 0) { - sp->SCp.this_residual = sp->request_bufflen; - sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; - sp->SCp.buffers_residual = 0; - if (esp->dma_mmu_get_scsi_one) - esp->dma_mmu_get_scsi_one(esp, sp); - else - sp->SCp.ptr = - (char *) virt_to_phys(sp->request_buffer); - } else { - sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; - sp->SCp.buffers_residual = sp->use_sg - 1; - sp->SCp.this_residual = sp->SCp.buffer->length; - if (esp->dma_mmu_get_scsi_sgl) - esp->dma_mmu_get_scsi_sgl(esp, sp); - else - sp->SCp.ptr = - (char *) virt_to_phys(sg_virt(sp->SCp.buffer)); - } -} - -static void esp_release_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - if(sp->use_sg == 0) { - if (esp->dma_mmu_release_scsi_one) - esp->dma_mmu_release_scsi_one(esp, sp); - } else { - if (esp->dma_mmu_release_scsi_sgl) - esp->dma_mmu_release_scsi_sgl(esp, sp); - } -} - -static void esp_restore_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - struct esp_pointers *ep = &esp->data_pointers[scmd_id(sp)]; - - sp->SCp.ptr = ep->saved_ptr; - sp->SCp.buffer = ep->saved_buffer; - sp->SCp.this_residual = ep->saved_this_residual; - sp->SCp.buffers_residual = ep->saved_buffers_residual; -} - -static void esp_save_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - struct esp_pointers *ep = &esp->data_pointers[scmd_id(sp)]; - - ep->saved_ptr = sp->SCp.ptr; - ep->saved_buffer = sp->SCp.buffer; - ep->saved_this_residual = sp->SCp.this_residual; - ep->saved_buffers_residual = sp->SCp.buffers_residual; -} - -/* Some rules: - * - * 1) Never ever panic while something is live on the bus. - * If there is to be any chance of syncing the disks this - * rule is to be obeyed. - * - * 2) Any target that causes a foul condition will no longer - * have synchronous transfers done to it, no questions - * asked. - * - * 3) Keep register accesses to a minimum. Think about some - * day when we have Xbus machines this is running on and - * the ESP chip is on the other end of the machine on a - * different board from the cpu where this is running. - */ - -/* Fire off a command. We assume the bus is free and that the only - * case where we could see an interrupt is where we have disconnected - * commands active and they are trying to reselect us. - */ -static inline void esp_check_cmd(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - switch(sp->cmd_len) { - case 6: - case 10: - case 12: - esp->esp_slowcmd = 0; - break; - - default: - esp->esp_slowcmd = 1; - esp->esp_scmdleft = sp->cmd_len; - esp->esp_scmdp = &sp->cmnd[0]; - break; - }; -} - -static inline void build_sync_nego_msg(struct NCR_ESP *esp, int period, int offset) -{ - esp->cur_msgout[0] = EXTENDED_MESSAGE; - esp->cur_msgout[1] = 3; - esp->cur_msgout[2] = EXTENDED_SDTR; - esp->cur_msgout[3] = period; - esp->cur_msgout[4] = offset; - esp->msgout_len = 5; -} - -static void esp_exec_cmd(struct NCR_ESP *esp) -{ - struct ESP_regs *eregs = esp->eregs; - struct esp_device *esp_dev; - Scsi_Cmnd *SCptr; - struct scsi_device *SDptr; - volatile unchar *cmdp = esp->esp_command; - unsigned char the_esp_command; - int lun, target; - int i; - - /* Hold off if we have disconnected commands and - * an IRQ is showing... - */ - if(esp->disconnected_SC && esp->dma_irq_p(esp)) - return; - - /* Grab first member of the issue queue. */ - SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC); - - /* Safe to panic here because current_SC is null. */ - if(!SCptr) - panic("esp: esp_exec_cmd and issue queue is NULL"); - - SDptr = SCptr->device; - esp_dev = SDptr->hostdata; - lun = SCptr->device->lun; - target = SCptr->device->id; - - esp->snip = 0; - esp->msgout_len = 0; - - /* Send it out whole, or piece by piece? The ESP - * only knows how to automatically send out 6, 10, - * and 12 byte commands. I used to think that the - * Linux SCSI code would never throw anything other - * than that to us, but then again there is the - * SCSI generic driver which can send us anything. - */ - esp_check_cmd(esp, SCptr); - - /* If arbitration/selection is successful, the ESP will leave - * ATN asserted, causing the target to go into message out - * phase. The ESP will feed the target the identify and then - * the target can only legally go to one of command, - * datain/out, status, or message in phase, or stay in message - * out phase (should we be trying to send a sync negotiation - * message after the identify). It is not allowed to drop - * BSY, but some buggy targets do and we check for this - * condition in the selection complete code. Most of the time - * we'll make the command bytes available to the ESP and it - * will not interrupt us until it finishes command phase, we - * cannot do this for command sizes the ESP does not - * understand and in this case we'll get interrupted right - * when the target goes into command phase. - * - * It is absolutely _illegal_ in the presence of SCSI-2 devices - * to use the ESP select w/o ATN command. When SCSI-2 devices are - * present on the bus we _must_ always go straight to message out - * phase with an identify message for the target. Being that - * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2 - * selections should not confuse SCSI-1 we hope. - */ - - if(esp_dev->sync) { - /* this targets sync is known */ -#ifdef CONFIG_SCSI_MAC_ESP -do_sync_known: -#endif - if(esp_dev->disconnect) - *cmdp++ = IDENTIFY(1, lun); - else - *cmdp++ = IDENTIFY(0, lun); - - if(esp->esp_slowcmd) { - the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA); - esp_advance_phase(SCptr, in_slct_stop); - } else { - the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA); - esp_advance_phase(SCptr, in_slct_norm); - } - } else if(!(esp->targets_present & (1<<target)) || !(esp_dev->disconnect)) { - /* After the bootup SCSI code sends both the - * TEST_UNIT_READY and INQUIRY commands we want - * to at least attempt allowing the device to - * disconnect. - */ - ESPMISC(("esp: Selecting device for first time. target=%d " - "lun=%d\n", target, SCptr->device->lun)); - if(!SDptr->borken && !esp_dev->disconnect) - esp_dev->disconnect = 1; - - *cmdp++ = IDENTIFY(0, lun); - esp->prevmsgout = NOP; - esp_advance_phase(SCptr, in_slct_norm); - the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA); - - /* Take no chances... */ - esp_dev->sync_max_offset = 0; - esp_dev->sync_min_period = 0; - } else { - int toshiba_cdrom_hwbug_wkaround = 0; - -#ifdef CONFIG_SCSI_MAC_ESP - /* Never allow synchronous transfers (disconnect OK) on - * Macintosh. Well, maybe later when we figured out how to - * do DMA on the machines that support it ... - */ - esp_dev->disconnect = 1; - esp_dev->sync_max_offset = 0; - esp_dev->sync_min_period = 0; - esp_dev->sync = 1; - esp->snip = 0; - goto do_sync_known; -#endif - /* We've talked to this guy before, - * but never negotiated. Let's try - * sync negotiation. - */ - if(!SDptr->borken) { - if((SDptr->type == TYPE_ROM) && - (!strncmp(SDptr->vendor, "TOSHIBA", 7))) { - /* Nice try sucker... */ - ESPMISC(("esp%d: Disabling sync for buggy " - "Toshiba CDROM.\n", esp->esp_id)); - toshiba_cdrom_hwbug_wkaround = 1; - build_sync_nego_msg(esp, 0, 0); - } else { - build_sync_nego_msg(esp, esp->sync_defp, 15); - } - } else { - build_sync_nego_msg(esp, 0, 0); - } - esp_dev->sync = 1; - esp->snip = 1; - - /* A fix for broken SCSI1 targets, when they disconnect - * they lock up the bus and confuse ESP. So disallow - * disconnects for SCSI1 targets for now until we - * find a better fix. - * - * Addendum: This is funny, I figured out what was going - * on. The blotzed SCSI1 target would disconnect, - * one of the other SCSI2 targets or both would be - * disconnected as well. The SCSI1 target would - * stay disconnected long enough that we start - * up a command on one of the SCSI2 targets. As - * the ESP is arbitrating for the bus the SCSI1 - * target begins to arbitrate as well to reselect - * the ESP. The SCSI1 target refuses to drop it's - * ID bit on the data bus even though the ESP is - * at ID 7 and is the obvious winner for any - * arbitration. The ESP is a poor sport and refuses - * to lose arbitration, it will continue indefinitely - * trying to arbitrate for the bus and can only be - * stopped via a chip reset or SCSI bus reset. - * Therefore _no_ disconnects for SCSI1 targets - * thank you very much. ;-) - */ - if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) || - toshiba_cdrom_hwbug_wkaround || SDptr->borken) { - ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d " - "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun)); - esp_dev->disconnect = 0; - *cmdp++ = IDENTIFY(0, lun); - } else { - *cmdp++ = IDENTIFY(1, lun); - } - - /* ESP fifo is only so big... - * Make this look like a slow command. - */ - esp->esp_slowcmd = 1; - esp->esp_scmdleft = SCptr->cmd_len; - esp->esp_scmdp = &SCptr->cmnd[0]; - - the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA); - esp_advance_phase(SCptr, in_slct_msg); - } - - if(!esp->esp_slowcmd) - for(i = 0; i < SCptr->cmd_len; i++) - *cmdp++ = SCptr->cmnd[i]; - - esp_write(eregs->esp_busid, (target & 7)); - if (esp->prev_soff != esp_dev->sync_max_offset || - esp->prev_stp != esp_dev->sync_min_period || - (esp->erev > esp100a && - esp->prev_cfg3 != esp->config3[target])) { - esp->prev_soff = esp_dev->sync_max_offset; - esp_write(eregs->esp_soff, esp->prev_soff); - esp->prev_stp = esp_dev->sync_min_period; - esp_write(eregs->esp_stp, esp->prev_stp); - if(esp->erev > esp100a) { - esp->prev_cfg3 = esp->config3[target]; - esp_write(eregs->esp_cfg3, esp->prev_cfg3); - } - } - i = (cmdp - esp->esp_command); - - /* Set up the DMA and ESP counters */ - if(esp->do_pio_cmds){ - int j = 0; - - /* - * XXX MSch: - * - * It seems this is required, at least to clean up - * after failed commands when using PIO mode ... - */ - esp_cmd(esp, eregs, ESP_CMD_FLUSH); - - for(;j<i;j++) - esp_write(eregs->esp_fdata, esp->esp_command[j]); - the_esp_command &= ~ESP_CMD_DMA; - - /* Tell ESP to "go". */ - esp_cmd(esp, eregs, the_esp_command); - } else { - /* Set up the ESP counters */ - esp_write(eregs->esp_tclow, i); - esp_write(eregs->esp_tcmed, 0); - esp->dma_init_write(esp, esp->esp_command_dvma, i); - - /* Tell ESP to "go". */ - esp_cmd(esp, eregs, the_esp_command); - } -} - -/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */ -int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) -{ - struct NCR_ESP *esp; - - /* Set up func ptr and initial driver cmd-phase. */ - SCpnt->scsi_done = done; - SCpnt->SCp.phase = not_issued; - - esp = (struct NCR_ESP *) SCpnt->device->host->hostdata; - - if(esp->dma_led_on) - esp->dma_led_on(esp); - - /* We use the scratch area. */ - ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->lun)); - ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->lun)); - - esp_get_dmabufs(esp, SCpnt); - esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */ - - SCpnt->SCp.Status = CHECK_CONDITION; - SCpnt->SCp.Message = 0xff; - SCpnt->SCp.sent_command = 0; - - /* Place into our queue. */ - if(SCpnt->cmnd[0] == REQUEST_SENSE) { - ESPQUEUE(("RQSENSE\n")); - prepend_SC(&esp->issue_SC, SCpnt); - } else { - ESPQUEUE(("\n")); - append_SC(&esp->issue_SC, SCpnt); - } - - /* Run it now if we can. */ - if(!esp->current_SC && !esp->resetting_bus) - esp_exec_cmd(esp); - - return 0; -} - -/* Dump driver state. */ -static void esp_dump_cmd(Scsi_Cmnd *SCptr) -{ - ESPLOG(("[tgt<%02x> lun<%02x> " - "pphase<%s> cphase<%s>]", - SCptr->device->id, SCptr->device->lun, - phase_string(SCptr->SCp.sent_command), - phase_string(SCptr->SCp.phase))); -} - -static void esp_dump_state(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - Scsi_Cmnd *SCptr = esp->current_SC; -#ifdef DEBUG_ESP_CMDS - int i; -#endif - - ESPLOG(("esp%d: dumping state\n", esp->esp_id)); - - /* Print DMA status */ - esp->dma_dump_state(esp); - - ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n", - esp->esp_id, esp->sreg, esp->seqreg, esp->ireg)); - ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n", - esp->esp_id, esp_read(eregs->esp_status), esp_read(eregs->esp_sstep), - esp_read(eregs->esp_intrpt))); -#ifdef DEBUG_ESP_CMDS - printk("esp%d: last ESP cmds [", esp->esp_id); - i = (esp->espcmdent - 1) & 31; - printk("<"); - esp_print_cmd(esp->espcmdlog[i]); - printk(">"); - i = (i - 1) & 31; - printk("<"); - esp_print_cmd(esp->espcmdlog[i]); - printk(">"); - i = (i - 1) & 31; - printk("<"); - esp_print_cmd(esp->espcmdlog[i]); - printk(">"); - i = (i - 1) & 31; - printk("<"); - esp_print_cmd(esp->espcmdlog[i]); - printk(">"); - printk("]\n"); -#endif /* (DEBUG_ESP_CMDS) */ - - if(SCptr) { - ESPLOG(("esp%d: current command ", esp->esp_id)); - esp_dump_cmd(SCptr); - } - ESPLOG(("\n")); - SCptr = esp->disconnected_SC; - ESPLOG(("esp%d: disconnected ", esp->esp_id)); - while(SCptr) { - esp_dump_cmd(SCptr); - SCptr = (Scsi_Cmnd *) SCptr->host_scribble; - } - ESPLOG(("\n")); -} - -/* Abort a command. The host_lock is acquired by caller. */ -int esp_abort(Scsi_Cmnd *SCptr) -{ - struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->device->host->hostdata; - struct ESP_regs *eregs = esp->eregs; - int don; - - ESPLOG(("esp%d: Aborting command\n", esp->esp_id)); - esp_dump_state(esp, eregs); - - /* Wheee, if this is the current command on the bus, the - * best we can do is assert ATN and wait for msgout phase. - * This should even fix a hung SCSI bus when we lose state - * in the driver and timeout because the eventual phase change - * will cause the ESP to (eventually) give an interrupt. - */ - if(esp->current_SC == SCptr) { - esp->cur_msgout[0] = ABORT; - esp->msgout_len = 1; - esp->msgout_ctr = 0; - esp_cmd(esp, eregs, ESP_CMD_SATN); - return SUCCESS; - } - - /* If it is still in the issue queue then we can safely - * call the completion routine and report abort success. - */ - don = esp->dma_ports_p(esp); - if(don) { - esp->dma_ints_off(esp); - synchronize_irq(esp->irq); - } - if(esp->issue_SC) { - Scsi_Cmnd **prev, *this; - for(prev = (&esp->issue_SC), this = esp->issue_SC; - this; - prev = (Scsi_Cmnd **) &(this->host_scribble), - this = (Scsi_Cmnd *) this->host_scribble) { - if(this == SCptr) { - *prev = (Scsi_Cmnd *) this->host_scribble; - this->host_scribble = NULL; - esp_release_dmabufs(esp, this); - this->result = DID_ABORT << 16; - this->scsi_done(this); - if(don) - esp->dma_ints_on(esp); - return SUCCESS; - } - } - } - - /* Yuck, the command to abort is disconnected, it is not - * worth trying to abort it now if something else is live - * on the bus at this time. So, we let the SCSI code wait - * a little bit and try again later. - */ - if(esp->current_SC) { - if(don) - esp->dma_ints_on(esp); - return FAILED; - } - - /* It's disconnected, we have to reconnect to re-establish - * the nexus and tell the device to abort. However, we really - * cannot 'reconnect' per se. Don't try to be fancy, just - * indicate failure, which causes our caller to reset the whole - * bus. - */ - - if(don) - esp->dma_ints_on(esp); - return FAILED; -} - -/* We've sent ESP_CMD_RS to the ESP, the interrupt had just - * arrived indicating the end of the SCSI bus reset. Our job - * is to clean out the command queues and begin re-execution - * of SCSI commands once more. - */ -static int esp_finish_reset(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - Scsi_Cmnd *sp = esp->current_SC; - - /* Clean up currently executing command, if any. */ - if (sp != NULL) { - esp_release_dmabufs(esp, sp); - sp->result = (DID_RESET << 16); - sp->scsi_done(sp); - esp->current_SC = NULL; - } - - /* Clean up disconnected queue, they have been invalidated - * by the bus reset. - */ - if (esp->disconnected_SC) { - while((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) { - esp_release_dmabufs(esp, sp); - sp->result = (DID_RESET << 16); - sp->scsi_done(sp); - } - } - - /* SCSI bus reset is complete. */ - esp->resetting_bus = 0; - wake_up(&esp->reset_queue); - - /* Ok, now it is safe to get commands going once more. */ - if(esp->issue_SC) - esp_exec_cmd(esp); - - return do_intr_end; -} - -static int esp_do_resetbus(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id)); - esp->resetting_bus = 1; - esp_cmd(esp, eregs, ESP_CMD_RS); - - return do_intr_end; -} - -/* Reset ESP chip, reset hanging bus, then kill active and - * disconnected commands for targets without soft reset. - * - * The host_lock is acquired by caller. - */ -int esp_reset(Scsi_Cmnd *SCptr) -{ - struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->device->host->hostdata; - - spin_lock_irq(esp->ehost->host_lock); - (void) esp_do_resetbus(esp, esp->eregs); - spin_unlock_irq(esp->ehost->host_lock); - - wait_event(esp->reset_queue, (esp->resetting_bus == 0)); - - return SUCCESS; -} - -/* Internal ESP done function. */ -static void esp_done(struct NCR_ESP *esp, int error) -{ - Scsi_Cmnd *done_SC; - - if(esp->current_SC) { - done_SC = esp->current_SC; - esp->current_SC = NULL; - esp_release_dmabufs(esp, done_SC); - done_SC->result = error; - done_SC->scsi_done(done_SC); - - /* Bus is free, issue any commands in the queue. */ - if(esp->issue_SC && !esp->current_SC) - esp_exec_cmd(esp); - } else { - /* Panic is safe as current_SC is null so we may still - * be able to accept more commands to sync disk buffers. - */ - ESPLOG(("panicing\n")); - panic("esp: done() called with NULL esp->current_SC"); - } -} - -/* Wheee, ESP interrupt engine. */ - -/* Forward declarations. */ -static int esp_do_phase_determine(struct NCR_ESP *esp, - struct ESP_regs *eregs); -static int esp_do_data_finale(struct NCR_ESP *esp, struct ESP_regs *eregs); -static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs); -static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs); -static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs); -static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs); -static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs); -static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs); - -#define sreg_datainp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DIP) -#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP) - -/* We try to avoid some interrupts by jumping ahead and see if the ESP - * has gotten far enough yet. Hence the following. - */ -static inline int skipahead1(struct NCR_ESP *esp, struct ESP_regs *eregs, - Scsi_Cmnd *scp, int prev_phase, int new_phase) -{ - if(scp->SCp.sent_command != prev_phase) - return 0; - - if(esp->dma_irq_p(esp)) { - /* Yes, we are able to save an interrupt. */ - esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR)); - esp->ireg = esp_read(eregs->esp_intrpt); - if(!(esp->ireg & ESP_INTR_SR)) - return 0; - else - return do_reset_complete; - } - /* Ho hum, target is taking forever... */ - scp->SCp.sent_command = new_phase; /* so we don't recurse... */ - return do_intr_end; -} - -static inline int skipahead2(struct NCR_ESP *esp, - struct ESP_regs *eregs, - Scsi_Cmnd *scp, int prev_phase1, int prev_phase2, - int new_phase) -{ - if(scp->SCp.sent_command != prev_phase1 && - scp->SCp.sent_command != prev_phase2) - return 0; - if(esp->dma_irq_p(esp)) { - /* Yes, we are able to save an interrupt. */ - esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR)); - esp->ireg = esp_read(eregs->esp_intrpt); - if(!(esp->ireg & ESP_INTR_SR)) - return 0; - else - return do_reset_complete; - } - /* Ho hum, target is taking forever... */ - scp->SCp.sent_command = new_phase; /* so we don't recurse... */ - return do_intr_end; -} - -/* Misc. esp helper macros. */ -#define esp_setcount(__eregs, __cnt) \ - esp_write((__eregs)->esp_tclow, ((__cnt) & 0xff)); \ - esp_write((__eregs)->esp_tcmed, (((__cnt) >> 8) & 0xff)) - -#define esp_getcount(__eregs) \ - ((esp_read((__eregs)->esp_tclow)&0xff) | \ - ((esp_read((__eregs)->esp_tcmed)&0xff) << 8)) - -#define fcount(__esp, __eregs) \ - (esp_read((__eregs)->esp_fflags) & ESP_FF_FBYTES) - -#define fnzero(__esp, __eregs) \ - (esp_read((__eregs)->esp_fflags) & ESP_FF_ONOTZERO) - -/* XXX speculative nops unnecessary when continuing amidst a data phase - * XXX even on esp100!!! another case of flooding the bus with I/O reg - * XXX writes... - */ -#define esp_maybe_nop(__esp, __eregs) \ - if((__esp)->erev == esp100) \ - esp_cmd((__esp), (__eregs), ESP_CMD_NULL) - -#define sreg_to_dataphase(__sreg) \ - ((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain) - -/* The ESP100 when in synchronous data phase, can mistake a long final - * REQ pulse from the target as an extra byte, it places whatever is on - * the data lines into the fifo. For now, we will assume when this - * happens that the target is a bit quirky and we don't want to - * be talking synchronously to it anyways. Regardless, we need to - * tell the ESP to eat the extraneous byte so that we can proceed - * to the next phase. - */ -static inline int esp100_sync_hwbug(struct NCR_ESP *esp, struct ESP_regs *eregs, - Scsi_Cmnd *sp, int fifocnt) -{ - /* Do not touch this piece of code. */ - if((!(esp->erev == esp100)) || - (!(sreg_datainp((esp->sreg = esp_read(eregs->esp_status))) && !fifocnt) && - !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) { - if(sp->SCp.phase == in_dataout) - esp_cmd(esp, eregs, ESP_CMD_FLUSH); - return 0; - } else { - /* Async mode for this guy. */ - build_sync_nego_msg(esp, 0, 0); - - /* Ack the bogus byte, but set ATN first. */ - esp_cmd(esp, eregs, ESP_CMD_SATN); - esp_cmd(esp, eregs, ESP_CMD_MOK); - return 1; - } -} - -/* This closes the window during a selection with a reselect pending, because - * we use DMA for the selection process the FIFO should hold the correct - * contents if we get reselected during this process. So we just need to - * ack the possible illegal cmd interrupt pending on the esp100. - */ -static inline int esp100_reconnect_hwbug(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - volatile unchar junk; - - if(esp->erev != esp100) - return 0; - junk = esp_read(eregs->esp_intrpt); - - if(junk & ESP_INTR_SR) - return 1; - return 0; -} - -/* This verifies the BUSID bits during a reselection so that we know which - * target is talking to us. - */ -static inline int reconnect_target(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - int it, me = esp->scsi_id_mask, targ = 0; - - if(2 != fcount(esp, eregs)) - return -1; - it = esp_read(eregs->esp_fdata); - if(!(it & me)) - return -1; - it &= ~me; - if(it & (it - 1)) - return -1; - while(!(it & 1)) - targ++, it >>= 1; - return targ; -} - -/* This verifies the identify from the target so that we know which lun is - * being reconnected. - */ -static inline int reconnect_lun(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - int lun; - - if((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) - return -1; - lun = esp_read(eregs->esp_fdata); - - /* Yes, you read this correctly. We report lun of zero - * if we see parity error. ESP reports parity error for - * the lun byte, and this is the only way to hope to recover - * because the target is connected. - */ - if(esp->sreg & ESP_STAT_PERR) - return 0; - - /* Check for illegal bits being set in the lun. */ - if((lun & 0x40) || !(lun & 0x80)) - return -1; - - return lun & 7; -} - -/* This puts the driver in a state where it can revitalize a command that - * is being continued due to reselection. - */ -static inline void esp_connect(struct NCR_ESP *esp, struct ESP_regs *eregs, - Scsi_Cmnd *sp) -{ - struct scsi_device *dp = sp->device; - struct esp_device *esp_dev = dp->hostdata; - - if(esp->prev_soff != esp_dev->sync_max_offset || - esp->prev_stp != esp_dev->sync_min_period || - (esp->erev > esp100a && - esp->prev_cfg3 != esp->config3[scmd_id(sp)])) { - esp->prev_soff = esp_dev->sync_max_offset; - esp_write(eregs->esp_soff, esp->prev_soff); - esp->prev_stp = esp_dev->sync_min_period; - esp_write(eregs->esp_stp, esp->prev_stp); - if(esp->erev > esp100a) { - esp->prev_cfg3 = esp->config3[scmd_id(sp)]; - esp_write(eregs->esp_cfg3, esp->prev_cfg3); - } - } - esp->current_SC = sp; -} - -/* This will place the current working command back into the issue queue - * if we are to receive a reselection amidst a selection attempt. - */ -static inline void esp_reconnect(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - if(!esp->disconnected_SC) - ESPLOG(("esp%d: Weird, being reselected but disconnected " - "command queue is empty.\n", esp->esp_id)); - esp->snip = 0; - esp->current_SC = NULL; - sp->SCp.phase = not_issued; - append_SC(&esp->issue_SC, sp); -} - -/* Begin message in phase. */ -static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - esp_cmd(esp, eregs, ESP_CMD_FLUSH); - esp_maybe_nop(esp, eregs); - esp_cmd(esp, eregs, ESP_CMD_TI); - esp->msgin_len = 1; - esp->msgin_ctr = 0; - esp_advance_phase(esp->current_SC, in_msgindone); - return do_work_bus; -} - -static inline void advance_sg(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - ++sp->SCp.buffer; - --sp->SCp.buffers_residual; - sp->SCp.this_residual = sp->SCp.buffer->length; - if (esp->dma_advance_sg) - esp->dma_advance_sg (sp); - else - sp->SCp.ptr = (char *) virt_to_phys(sg_virt(sp->SCp.buffer)); - -} - -/* Please note that the way I've coded these routines is that I _always_ - * check for a disconnect during any and all information transfer - * phases. The SCSI standard states that the target _can_ cause a BUS - * FREE condition by dropping all MSG/CD/IO/BSY signals. Also note - * that during information transfer phases the target controls every - * change in phase, the only thing the initiator can do is "ask" for - * a message out phase by driving ATN true. The target can, and sometimes - * will, completely ignore this request so we cannot assume anything when - * we try to force a message out phase to abort/reset a target. Most of - * the time the target will eventually be nice and go to message out, so - * we may have to hold on to our state about what we want to tell the target - * for some period of time. - */ - -/* I think I have things working here correctly. Even partial transfers - * within a buffer or sub-buffer should not upset us at all no matter - * how bad the target and/or ESP fucks things up. - */ -static int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - Scsi_Cmnd *SCptr = esp->current_SC; - int thisphase, hmuch; - - ESPDATA(("esp_do_data: ")); - esp_maybe_nop(esp, eregs); - thisphase = sreg_to_dataphase(esp->sreg); - esp_advance_phase(SCptr, thisphase); - ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT")); - hmuch = esp->dma_can_transfer(esp, SCptr); - - /* - * XXX MSch: cater for PIO transfer here; PIO used if hmuch == 0 - */ - if (hmuch) { /* DMA */ - /* - * DMA - */ - ESPDATA(("hmuch<%d> ", hmuch)); - esp->current_transfer_size = hmuch; - esp_setcount(eregs, (esp->fas_premature_intr_workaround ? - (hmuch + 0x40) : hmuch)); - esp->dma_setup(esp, (__u32)((unsigned long)SCptr->SCp.ptr), - hmuch, (thisphase == in_datain)); - ESPDATA(("DMA|TI --> do_intr_end\n")); - esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); - return do_intr_end; - /* - * end DMA - */ - } else { - /* - * PIO - */ - int oldphase, i = 0; /* or where we left off last time ?? esp->current_data ?? */ - int fifocnt = 0; - unsigned char *p = phys_to_virt((unsigned long)SCptr->SCp.ptr); - - oldphase = esp_read(eregs->esp_status) & ESP_STAT_PMASK; - - /* - * polled transfer; ugly, can we make this happen in a DRQ - * interrupt handler ?? - * requires keeping track of state information in host or - * command struct! - * Problem: I've never seen a DRQ happen on Mac, not even - * with ESP_CMD_DMA ... - */ - - /* figure out how much needs to be transferred */ - hmuch = SCptr->SCp.this_residual; - ESPDATA(("hmuch<%d> pio ", hmuch)); - esp->current_transfer_size = hmuch; - - /* tell the ESP ... */ - esp_setcount(eregs, hmuch); - - /* loop */ - while (hmuch) { - int j, fifo_stuck = 0, newphase; - unsigned long timeout; -#if 0 - unsigned long flags; -#endif -#if 0 - if ( i % 10 ) - ESPDATA(("\r")); - else - ESPDATA(( /*"\n"*/ "\r")); -#endif -#if 0 - local_irq_save(flags); -#endif - if(thisphase == in_datain) { - /* 'go' ... */ - esp_cmd(esp, eregs, ESP_CMD_TI); - - /* wait for data */ - timeout = 1000000; - while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout) - udelay(2); - if (timeout == 0) - printk("DRQ datain timeout! \n"); - - newphase = esp->sreg & ESP_STAT_PMASK; - - /* see how much we got ... */ - fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES); - - if (!fifocnt) - fifo_stuck++; - else - fifo_stuck = 0; - - ESPDATA(("\rgot %d st %x ph %x", fifocnt, esp->sreg, newphase)); - - /* read fifo */ - for(j=0;j<fifocnt;j++) - p[i++] = esp_read(eregs->esp_fdata); - - ESPDATA(("(%d) ", i)); - - /* how many to go ?? */ - hmuch -= fifocnt; - - /* break if status phase !! */ - if(newphase == ESP_STATP) { - /* clear int. */ - esp->ireg = esp_read(eregs->esp_intrpt); - break; - } - } else { -#define MAX_FIFO 8 - /* how much will fit ? */ - int this_count = MAX_FIFO - fifocnt; - if (this_count > hmuch) - this_count = hmuch; - - /* fill fifo */ - for(j=0;j<this_count;j++) - esp_write(eregs->esp_fdata, p[i++]); - - /* how many left if this goes out ?? */ - hmuch -= this_count; - - /* 'go' ... */ - esp_cmd(esp, eregs, ESP_CMD_TI); - - /* wait for 'got it' */ - timeout = 1000000; - while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout) - udelay(2); - if (timeout == 0) - printk("DRQ dataout timeout! \n"); - - newphase = esp->sreg & ESP_STAT_PMASK; - - /* need to check how much was sent ?? */ - fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES); - - ESPDATA(("\rsent %d st %x ph %x", this_count - fifocnt, esp->sreg, newphase)); - - ESPDATA(("(%d) ", i)); - - /* break if status phase !! */ - if(newphase == ESP_STATP) { - /* clear int. */ - esp->ireg = esp_read(eregs->esp_intrpt); - break; - } - - } - - /* clear int. */ - esp->ireg = esp_read(eregs->esp_intrpt); - - ESPDATA(("ir %x ... ", esp->ireg)); - - if (hmuch == 0) - ESPDATA(("done! \n")); - -#if 0 - local_irq_restore(flags); -#endif - - /* check new bus phase */ - if (newphase != oldphase && i < esp->current_transfer_size) { - /* something happened; disconnect ?? */ - ESPDATA(("phase change, dropped out with %d done ... ", i)); - break; - } - - /* check int. status */ - if (esp->ireg & ESP_INTR_DC) { - /* disconnect */ - ESPDATA(("disconnect; %d transferred ... ", i)); - break; - } else if (esp->ireg & ESP_INTR_FDONE) { - /* function done */ - ESPDATA(("function done; %d transferred ... ", i)); - break; - } - - /* XXX fixme: bail out on stall */ - if (fifo_stuck > 10) { - /* we're stuck */ - ESPDATA(("fifo stall; %d transferred ... ", i)); - break; - } - } - - ESPDATA(("\n")); - /* check successful completion ?? */ - - if (thisphase == in_dataout) - hmuch += fifocnt; /* stuck?? adjust data pointer ...*/ - - /* tell do_data_finale how much was transferred */ - esp->current_transfer_size -= hmuch; - - /* still not completely sure on this one ... */ - return /*do_intr_end*/ do_work_bus /*do_phase_determine*/ ; - - /* - * end PIO - */ - } - return do_intr_end; -} - -/* See how successful the data transfer was. */ -static int esp_do_data_finale(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - Scsi_Cmnd *SCptr = esp->current_SC; - struct esp_device *esp_dev = SCptr->device->hostdata; - int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0; - - if(esp->dma_led_off) - esp->dma_led_off(esp); - - ESPDATA(("esp_do_data_finale: ")); - - if(SCptr->SCp.phase == in_datain) { - if(esp->sreg & ESP_STAT_PERR) { - /* Yuck, parity error. The ESP asserts ATN - * so that we can go to message out phase - * immediately and inform the target that - * something bad happened. - */ - ESPLOG(("esp%d: data bad parity detected.\n", - esp->esp_id)); - esp->cur_msgout[0] = INITIATOR_ERROR; - esp->msgout_len = 1; - } - if(esp->dma_drain) - esp->dma_drain(esp); - } - if(esp->dma_invalidate) - esp->dma_invalidate(esp); - - /* This could happen for the above parity error case. */ - if(!(esp->ireg == ESP_INTR_BSERV)) { - /* Please go to msgout phase, please please please... */ - ESPLOG(("esp%d: !BSERV after data, probably to msgout\n", - esp->esp_id)); - return esp_do_phase_determine(esp, eregs); - } - - /* Check for partial transfers and other horrible events. */ - fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES); - ecount = esp_getcount(eregs); - if(esp->fas_premature_intr_workaround) - ecount -= 0x40; - bytes_sent = esp->current_transfer_size; - - ESPDATA(("trans_sz=%d, ", bytes_sent)); - if(!(esp->sreg & ESP_STAT_TCNT)) - bytes_sent -= ecount; - if(SCptr->SCp.phase == in_dataout) - bytes_sent -= fifocnt; - - ESPDATA(("bytes_sent=%d (ecount=%d, fifocnt=%d), ", bytes_sent, - ecount, fifocnt)); - - /* If we were in synchronous mode, check for peculiarities. */ - if(esp_dev->sync_max_offset) - bogus_data = esp100_sync_hwbug(esp, eregs, SCptr, fifocnt); - else - esp_cmd(esp, eregs, ESP_CMD_FLUSH); - - /* Until we are sure of what has happened, we are certainly - * in the dark. - */ - esp_advance_phase(SCptr, in_the_dark); - - /* Check for premature interrupt condition. Can happen on FAS2x6 - * chips. QLogic recommends a workaround by overprogramming the - * transfer counters, but this makes doing scatter-gather impossible. - * Until there is a way to disable scatter-gather for a single target, - * and not only for the entire host adapter as it is now, the workaround - * is way to expensive performance wise. - * Instead, it turns out that when this happens the target has disconnected - * already but it doesn't show in the interrupt register. Compensate for - * that here to try and avoid a SCSI bus reset. - */ - if(!esp->fas_premature_intr_workaround && (fifocnt == 1) && - sreg_dataoutp(esp->sreg)) { - ESPLOG(("esp%d: Premature interrupt, enabling workaround\n", - esp->esp_id)); -#if 0 - /* Disable scatter-gather operations, they are not possible - * when using this workaround. - */ - esp->ehost->sg_tablesize = 0; - esp->ehost->use_clustering = ENABLE_CLUSTERING; - esp->fas_premature_intr_workaround = 1; - bytes_sent = 0; - if(SCptr->use_sg) { - ESPLOG(("esp%d: Aborting scatter-gather operation\n", - esp->esp_id)); - esp->cur_msgout[0] = ABORT; - esp->msgout_len = 1; - esp->msgout_ctr = 0; - esp_cmd(esp, eregs, ESP_CMD_SATN); - esp_setcount(eregs, 0xffff); - esp_cmd(esp, eregs, ESP_CMD_NULL); - esp_cmd(esp, eregs, ESP_CMD_TPAD | ESP_CMD_DMA); - return do_intr_end; - } -#else - /* Just set the disconnected bit. That's what appears to - * happen anyway. The state machine will pick it up when - * we return. - */ - esp->ireg |= ESP_INTR_DC; -#endif - } - - if(bytes_sent < 0) { - /* I've seen this happen due to lost state in this - * driver. No idea why it happened, but allowing - * this value to be negative caused things to - * lock up. This allows greater chance of recovery. - * In fact every time I've seen this, it has been - * a driver bug without question. - */ - ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id)); - ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n", - esp->esp_id, - esp->current_transfer_size, fifocnt, ecount)); - ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n", - esp->esp_id, - SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual)); - ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id, - SCptr->device->id)); - SCptr->device->borken = 1; - esp_dev->sync = 0; - bytes_sent = 0; - } - - /* Update the state of our transfer. */ - SCptr->SCp.ptr += bytes_sent; - SCptr->SCp.this_residual -= bytes_sent; - if(SCptr->SCp.this_residual < 0) { - /* shit */ - ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id)); - SCptr->SCp.this_residual = 0; - } - - /* Maybe continue. */ - if(!bogus_data) { - ESPDATA(("!bogus_data, ")); - /* NO MATTER WHAT, we advance the scatterlist, - * if the target should decide to disconnect - * in between scatter chunks (which is common) - * we could die horribly! I used to have the sg - * advance occur only if we are going back into - * (or are staying in) a data phase, you can - * imagine the hell I went through trying to - * figure this out. - */ - if(!SCptr->SCp.this_residual && SCptr->SCp.buffers_residual) - advance_sg(esp, SCptr); -#ifdef DEBUG_ESP_DATA - if(sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) { - ESPDATA(("to more data\n")); - } else { - ESPDATA(("to new phase\n")); - } -#endif - return esp_do_phase_determine(esp, eregs); - } - /* Bogus data, just wait for next interrupt. */ - ESPLOG(("esp%d: bogus_data during end of data phase\n", - esp->esp_id)); - return do_intr_end; -} - -/* We received a non-good status return at the end of - * running a SCSI command. This is used to decide if - * we should clear our synchronous transfer state for - * such a device when that happens. - * - * The idea is that when spinning up a disk or rewinding - * a tape, we don't want to go into a loop re-negotiating - * synchronous capabilities over and over. - */ -static int esp_should_clear_sync(Scsi_Cmnd *sp) -{ - unchar cmd = sp->cmnd[0]; - - /* These cases are for spinning up a disk and - * waiting for that spinup to complete. - */ - if(cmd == START_STOP) - return 0; - - if(cmd == TEST_UNIT_READY) - return 0; - - /* One more special case for SCSI tape drives, - * this is what is used to probe the device for - * completion of a rewind or tape load operation. - */ - if(sp->device->type == TYPE_TAPE && cmd == MODE_SENSE) - return 0; - - return 1; -} - -/* Either a command is completing or a target is dropping off the bus - * to continue the command in the background so we can do other work. - */ -static int esp_do_freebus(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - Scsi_Cmnd *SCptr = esp->current_SC; - int rval; - - rval = skipahead2(esp, eregs, SCptr, in_status, in_msgindone, in_freeing); - if(rval) - return rval; - - if(esp->ireg != ESP_INTR_DC) { - ESPLOG(("esp%d: Target will not disconnect\n", esp->esp_id)); - return do_reset_bus; /* target will not drop BSY... */ - } - esp->msgout_len = 0; - esp->prevmsgout = NOP; - if(esp->prevmsgin == COMMAND_COMPLETE) { - struct esp_device *esp_dev = SCptr->device->hostdata; - /* Normal end of nexus. */ - if(esp->disconnected_SC) - esp_cmd(esp, eregs, ESP_CMD_ESEL); - - if(SCptr->SCp.Status != GOOD && - SCptr->SCp.Status != CONDITION_GOOD && - ((1<<scmd_id(SCptr)) & esp->targets_present) && - esp_dev->sync && esp_dev->sync_max_offset) { - /* SCSI standard says that the synchronous capabilities - * should be renegotiated at this point. Most likely - * we are about to request sense from this target - * in which case we want to avoid using sync - * transfers until we are sure of the current target - * state. - */ - ESPMISC(("esp: Status <%d> for target %d lun %d\n", - SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun)); - - /* But don't do this when spinning up a disk at - * boot time while we poll for completion as it - * fills up the console with messages. Also, tapes - * can report not ready many times right after - * loading up a tape. - */ - if(esp_should_clear_sync(SCptr) != 0) - esp_dev->sync = 0; - } - ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun)); - esp_done(esp, ((SCptr->SCp.Status & 0xff) | - ((SCptr->SCp.Message & 0xff)<<8) | - (DID_OK << 16))); - } else if(esp->prevmsgin == DISCONNECT) { - /* Normal disconnect. */ - esp_cmd(esp, eregs, ESP_CMD_ESEL); - ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun)); - append_SC(&esp->disconnected_SC, SCptr); - esp->current_SC = NULL; - if(esp->issue_SC) - esp_exec_cmd(esp); - } else { - /* Driver bug, we do not expect a disconnect here - * and should not have advanced the state engine - * to in_freeing. - */ - ESPLOG(("esp%d: last msg not disc and not cmd cmplt.\n", - esp->esp_id)); - return do_reset_bus; - } - return do_intr_end; -} - -/* When a reselect occurs, and we cannot find the command to - * reconnect to in our queues, we do this. - */ -static int esp_bad_reconnect(struct NCR_ESP *esp) -{ - Scsi_Cmnd *sp; - - ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n", - esp->esp_id)); - ESPLOG(("QUEUE DUMP\n")); - sp = esp->issue_SC; - ESPLOG(("esp%d: issue_SC[", esp->esp_id)); - while(sp) { - ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); - sp = (Scsi_Cmnd *) sp->host_scribble; - } - ESPLOG(("]\n")); - sp = esp->current_SC; - ESPLOG(("esp%d: current_SC[", esp->esp_id)); - while(sp) { - ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); - sp = (Scsi_Cmnd *) sp->host_scribble; - } - ESPLOG(("]\n")); - sp = esp->disconnected_SC; - ESPLOG(("esp%d: disconnected_SC[", esp->esp_id)); - while(sp) { - ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun)); - sp = (Scsi_Cmnd *) sp->host_scribble; - } - ESPLOG(("]\n")); - return do_reset_bus; -} - -/* Do the needy when a target tries to reconnect to us. */ -static int esp_do_reconnect(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - int lun, target; - Scsi_Cmnd *SCptr; - - /* Check for all bogus conditions first. */ - target = reconnect_target(esp, eregs); - if(target < 0) { - ESPDISC(("bad bus bits\n")); - return do_reset_bus; - } - lun = reconnect_lun(esp, eregs); - if(lun < 0) { - ESPDISC(("target=%2x, bad identify msg\n", target)); - return do_reset_bus; - } - - /* Things look ok... */ - ESPDISC(("R<%02x,%02x>", target, lun)); - - esp_cmd(esp, eregs, ESP_CMD_FLUSH); - if(esp100_reconnect_hwbug(esp, eregs)) - return do_reset_bus; - esp_cmd(esp, eregs, ESP_CMD_NULL); - - SCptr = remove_SC(&esp->disconnected_SC, (unchar) target, (unchar) lun); - if(!SCptr) - return esp_bad_reconnect(esp); - - esp_connect(esp, eregs, SCptr); - esp_cmd(esp, eregs, ESP_CMD_MOK); - - /* Reconnect implies a restore pointers operation. */ - esp_restore_pointers(esp, SCptr); - - esp->snip = 0; - esp_advance_phase(SCptr, in_the_dark); - return do_intr_end; -} - -/* End of NEXUS (hopefully), pick up status + message byte then leave if - * all goes well. - */ -static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - Scsi_Cmnd *SCptr = esp->current_SC; - int intr, rval; - - rval = skipahead1(esp, eregs, SCptr, in_the_dark, in_status); - if(rval) - return rval; - - intr = esp->ireg; - ESPSTAT(("esp_do_status: ")); - if(intr != ESP_INTR_DC) { - int message_out = 0; /* for parity problems */ - - /* Ack the message. */ - ESPSTAT(("ack msg, ")); - esp_cmd(esp, eregs, ESP_CMD_MOK); - - if(esp->dma_poll) - esp->dma_poll(esp, (unsigned char *) esp->esp_command); - - ESPSTAT(("got something, ")); - /* ESP chimes in with one of - * - * 1) function done interrupt: - * both status and message in bytes - * are available - * - * 2) bus service interrupt: - * only status byte was acquired - * - * 3) Anything else: - * can't happen, but we test for it - * anyways - * - * ALSO: If bad parity was detected on either - * the status _or_ the message byte then - * the ESP has asserted ATN on the bus - * and we must therefore wait for the - * next phase change. - */ - if(intr & ESP_INTR_FDONE) { - /* We got it all, hallejulia. */ - ESPSTAT(("got both, ")); - SCptr->SCp.Status = esp->esp_command[0]; - SCptr->SCp.Message = esp->esp_command[1]; - esp->prevmsgin = SCptr->SCp.Message; - esp->cur_msgin[0] = SCptr->SCp.Message; - if(esp->sreg & ESP_STAT_PERR) { - /* There was bad parity for the - * message byte, the status byte - * was ok. - */ - message_out = MSG_PARITY_ERROR; - } - } else if(intr == ESP_INTR_BSERV) { - /* Only got status byte. */ - ESPLOG(("esp%d: got status only, ", esp->esp_id)); - if(!(esp->sreg & ESP_STAT_PERR)) { - SCptr->SCp.Status = esp->esp_command[0]; - SCptr->SCp.Message = 0xff; - } else { - /* The status byte had bad parity. - * we leave the scsi_pointer Status - * field alone as we set it to a default - * of CHECK_CONDITION in esp_queue. - */ - message_out = INITIATOR_ERROR; - } - } else { - /* This shouldn't happen ever. */ - ESPSTAT(("got bolixed\n")); - esp_advance_phase(SCptr, in_the_dark); - return esp_do_phase_determine(esp, eregs); - } - - if(!message_out) { - ESPSTAT(("status=%2x msg=%2x, ", SCptr->SCp.Status, - SCptr->SCp.Message)); - if(SCptr->SCp.Message == COMMAND_COMPLETE) { - ESPSTAT(("and was COMMAND_COMPLETE\n")); - esp_advance_phase(SCptr, in_freeing); - return esp_do_freebus(esp, eregs); - } else { - ESPLOG(("esp%d: and _not_ COMMAND_COMPLETE\n", - esp->esp_id)); - esp->msgin_len = esp->msgin_ctr = 1; - esp_advance_phase(SCptr, in_msgindone); - return esp_do_msgindone(esp, eregs); - } - } else { - /* With luck we'll be able to let the target - * know that bad parity happened, it will know - * which byte caused the problems and send it - * again. For the case where the status byte - * receives bad parity, I do not believe most - * targets recover very well. We'll see. - */ - ESPLOG(("esp%d: bad parity somewhere mout=%2x\n", - esp->esp_id, message_out)); - esp->cur_msgout[0] = message_out; - esp->msgout_len = esp->msgout_ctr = 1; - esp_advance_phase(SCptr, in_the_dark); - return esp_do_phase_determine(esp, eregs); - } - } else { - /* If we disconnect now, all hell breaks loose. */ - ESPLOG(("esp%d: whoops, disconnect\n", esp->esp_id)); - esp_advance_phase(SCptr, in_the_dark); - return esp_do_phase_determine(esp, eregs); - } -} - -static int esp_enter_status(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - unchar thecmd = ESP_CMD_ICCSEQ; - - esp_cmd(esp, eregs, ESP_CMD_FLUSH); - - if(esp->do_pio_cmds) { - esp_advance_phase(esp->current_SC, in_status); - esp_cmd(esp, eregs, thecmd); - while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR)); - esp->esp_command[0] = esp_read(eregs->esp_fdata); - while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR)); - esp->esp_command[1] = esp_read(eregs->esp_fdata); - } else { - esp->esp_command[0] = esp->esp_command[1] = 0xff; - esp_write(eregs->esp_tclow, 2); - esp_write(eregs->esp_tcmed, 0); - esp->dma_init_read(esp, esp->esp_command_dvma, 2); - thecmd |= ESP_CMD_DMA; - esp_cmd(esp, eregs, thecmd); - esp_advance_phase(esp->current_SC, in_status); - } - - return esp_do_status(esp, eregs); -} - -static int esp_disconnect_amidst_phases(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - Scsi_Cmnd *sp = esp->current_SC; - struct esp_device *esp_dev = sp->device->hostdata; - - /* This means real problems if we see this - * here. Unless we were actually trying - * to force the device to abort/reset. - */ - ESPLOG(("esp%d: Disconnect amidst phases, ", esp->esp_id)); - ESPLOG(("pphase<%s> cphase<%s>, ", - phase_string(sp->SCp.phase), - phase_string(sp->SCp.sent_command))); - - if(esp->disconnected_SC) - esp_cmd(esp, eregs, ESP_CMD_ESEL); - - switch(esp->cur_msgout[0]) { - default: - /* We didn't expect this to happen at all. */ - ESPLOG(("device is bolixed\n")); - esp_advance_phase(sp, in_tgterror); - esp_done(esp, (DID_ERROR << 16)); - break; - - case BUS_DEVICE_RESET: - ESPLOG(("device reset successful\n")); - esp_dev->sync_max_offset = 0; - esp_dev->sync_min_period = 0; - esp_dev->sync = 0; - esp_advance_phase(sp, in_resetdev); - esp_done(esp, (DID_RESET << 16)); - break; - - case ABORT: - ESPLOG(("device abort successful\n")); - esp_advance_phase(sp, in_abortone); - esp_done(esp, (DID_ABORT << 16)); - break; - - }; - return do_intr_end; -} - -static int esp_enter_msgout(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - esp_advance_phase(esp->current_SC, in_msgout); - return esp_do_msgout(esp, eregs); -} - -static int esp_enter_msgin(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - esp_advance_phase(esp->current_SC, in_msgin); - return esp_do_msgin(esp, eregs); -} - -static int esp_enter_cmd(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - esp_advance_phase(esp->current_SC, in_cmdbegin); - return esp_do_cmdbegin(esp, eregs); -} - -static int esp_enter_badphase(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id, - esp->sreg & ESP_STAT_PMASK)); - return do_reset_bus; -} - -typedef int (*espfunc_t)(struct NCR_ESP *, - struct ESP_regs *); - -static espfunc_t phase_vector[] = { - esp_do_data, /* ESP_DOP */ - esp_do_data, /* ESP_DIP */ - esp_enter_cmd, /* ESP_CMDP */ - esp_enter_status, /* ESP_STATP */ - esp_enter_badphase, /* ESP_STAT_PMSG */ - esp_enter_badphase, /* ESP_STAT_PMSG | ESP_STAT_PIO */ - esp_enter_msgout, /* ESP_MOP */ - esp_enter_msgin, /* ESP_MIP */ -}; - -/* The target has control of the bus and we have to see where it has - * taken us. - */ -static int esp_do_phase_determine(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - if ((esp->ireg & ESP_INTR_DC) != 0) - return esp_disconnect_amidst_phases(esp, eregs); - return phase_vector[esp->sreg & ESP_STAT_PMASK](esp, eregs); -} - -/* First interrupt after exec'ing a cmd comes here. */ -static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - Scsi_Cmnd *SCptr = esp->current_SC; - struct esp_device *esp_dev = SCptr->device->hostdata; - int cmd_bytes_sent, fcnt; - - fcnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES); - cmd_bytes_sent = esp->dma_bytes_sent(esp, fcnt); - if(esp->dma_invalidate) - esp->dma_invalidate(esp); - - /* Let's check to see if a reselect happened - * while we we're trying to select. This must - * be checked first. - */ - if(esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) { - esp_reconnect(esp, SCptr); - return esp_do_reconnect(esp, eregs); - } - - /* Looks like things worked, we should see a bus service & - * a function complete interrupt at this point. Note we - * are doing a direct comparison because we don't want to - * be fooled into thinking selection was successful if - * ESP_INTR_DC is set, see below. - */ - if(esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) { - /* target speaks... */ - esp->targets_present |= (1<<scmd_id(SCptr)); - - /* What if the target ignores the sdtr? */ - if(esp->snip) - esp_dev->sync = 1; - - /* See how far, if at all, we got in getting - * the information out to the target. - */ - switch(esp->seqreg) { - default: - - case ESP_STEP_ASEL: - /* Arbitration won, target selected, but - * we are in some phase which is not command - * phase nor is it message out phase. - * - * XXX We've confused the target, obviously. - * XXX So clear it's state, but we also end - * XXX up clearing everyone elses. That isn't - * XXX so nice. I'd like to just reset this - * XXX target, but if I cannot even get it's - * XXX attention and finish selection to talk - * XXX to it, there is not much more I can do. - * XXX If we have a loaded bus we're going to - * XXX spend the next second or so renegotiating - * XXX for synchronous transfers. - */ - ESPLOG(("esp%d: STEP_ASEL for tgt %d\n", - esp->esp_id, SCptr->device->id)); - - case ESP_STEP_SID: - /* Arbitration won, target selected, went - * to message out phase, sent one message - * byte, then we stopped. ATN is asserted - * on the SCSI bus and the target is still - * there hanging on. This is a legal - * sequence step if we gave the ESP a select - * and stop command. - * - * XXX See above, I could set the borken flag - * XXX in the device struct and retry the - * XXX command. But would that help for - * XXX tagged capable targets? - */ - - case ESP_STEP_NCMD: - /* Arbitration won, target selected, maybe - * sent the one message byte in message out - * phase, but we did not go to command phase - * in the end. Actually, we could have sent - * only some of the message bytes if we tried - * to send out the entire identify and tag - * message using ESP_CMD_SA3. - */ - cmd_bytes_sent = 0; - break; - - case ESP_STEP_PPC: - /* No, not the powerPC pinhead. Arbitration - * won, all message bytes sent if we went to - * message out phase, went to command phase - * but only part of the command was sent. - * - * XXX I've seen this, but usually in conjunction - * XXX with a gross error which appears to have - * XXX occurred between the time I told the - * XXX ESP to arbitrate and when I got the - * XXX interrupt. Could I have misloaded the - * XXX command bytes into the fifo? Actually, - * XXX I most likely missed a phase, and therefore - * XXX went into never never land and didn't even - * XXX know it. That was the old driver though. - * XXX What is even more peculiar is that the ESP - * XXX showed the proper function complete and - * XXX bus service bits in the interrupt register. - */ - - case ESP_STEP_FINI4: - case ESP_STEP_FINI5: - case ESP_STEP_FINI6: - case ESP_STEP_FINI7: - /* Account for the identify message */ - if(SCptr->SCp.phase == in_slct_norm) - cmd_bytes_sent -= 1; - }; - esp_cmd(esp, eregs, ESP_CMD_NULL); - - /* Be careful, we could really get fucked during synchronous - * data transfers if we try to flush the fifo now. - */ - if(!fcnt && /* Fifo is empty and... */ - /* either we are not doing synchronous transfers or... */ - (!esp_dev->sync_max_offset || - /* We are not going into data in phase. */ - ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP))) - esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* flush is safe */ - - /* See how far we got if this is not a slow command. */ - if(!esp->esp_slowcmd) { - if(cmd_bytes_sent < 0) - cmd_bytes_sent = 0; - if(cmd_bytes_sent != SCptr->cmd_len) { - /* Crapola, mark it as a slowcmd - * so that we have some chance of - * keeping the command alive with - * good luck. - * - * XXX Actually, if we didn't send it all - * XXX this means either we didn't set things - * XXX up properly (driver bug) or the target - * XXX or the ESP detected parity on one of - * XXX the command bytes. This makes much - * XXX more sense, and therefore this code - * XXX should be changed to send out a - * XXX parity error message or if the status - * XXX register shows no parity error then - * XXX just expect the target to bring the - * XXX bus into message in phase so that it - * XXX can send us the parity error message. - * XXX SCSI sucks... - */ - esp->esp_slowcmd = 1; - esp->esp_scmdp = &(SCptr->cmnd[cmd_bytes_sent]); - esp->esp_scmdleft = (SCptr->cmd_len - cmd_bytes_sent); - } - } - - /* Now figure out where we went. */ - esp_advance_phase(SCptr, in_the_dark); - return esp_do_phase_determine(esp, eregs); - } - - /* Did the target even make it? */ - if(esp->ireg == ESP_INTR_DC) { - /* wheee... nobody there or they didn't like - * what we told it to do, clean up. - */ - - /* If anyone is off the bus, but working on - * a command in the background for us, tell - * the ESP to listen for them. - */ - if(esp->disconnected_SC) - esp_cmd(esp, eregs, ESP_CMD_ESEL); - - if(((1<<SCptr->device->id) & esp->targets_present) && - esp->seqreg && esp->cur_msgout[0] == EXTENDED_MESSAGE && - (SCptr->SCp.phase == in_slct_msg || - SCptr->SCp.phase == in_slct_stop)) { - /* shit */ - esp->snip = 0; - ESPLOG(("esp%d: Failed synchronous negotiation for target %d " - "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun)); - esp_dev->sync_max_offset = 0; - esp_dev->sync_min_period = 0; - esp_dev->sync = 1; /* so we don't negotiate again */ - - /* Run the command again, this time though we - * won't try to negotiate for synchronous transfers. - * - * XXX I'd like to do something like send an - * XXX INITIATOR_ERROR or ABORT message to the - * XXX target to tell it, "Sorry I confused you, - * XXX please come back and I will be nicer next - * XXX time". But that requires having the target - * XXX on the bus, and it has dropped BSY on us. - */ - esp->current_SC = NULL; - esp_advance_phase(SCptr, not_issued); - prepend_SC(&esp->issue_SC, SCptr); - esp_exec_cmd(esp); - return do_intr_end; - } - - /* Ok, this is normal, this is what we see during boot - * or whenever when we are scanning the bus for targets. - * But first make sure that is really what is happening. - */ - if(((1<<SCptr->device->id) & esp->targets_present)) { - ESPLOG(("esp%d: Warning, live target %d not responding to " - "selection.\n", esp->esp_id, SCptr->device->id)); - - /* This _CAN_ happen. The SCSI standard states that - * the target is to _not_ respond to selection if - * _it_ detects bad parity on the bus for any reason. - * Therefore, we assume that if we've talked successfully - * to this target before, bad parity is the problem. - */ - esp_done(esp, (DID_PARITY << 16)); - } else { - /* Else, there really isn't anyone there. */ - ESPMISC(("esp: selection failure, maybe nobody there?\n")); - ESPMISC(("esp: target %d lun %d\n", - SCptr->device->id, SCptr->device->lun)); - esp_done(esp, (DID_BAD_TARGET << 16)); - } - return do_intr_end; - } - - - ESPLOG(("esp%d: Selection failure.\n", esp->esp_id)); - printk("esp%d: Currently -- ", esp->esp_id); - esp_print_ireg(esp->ireg); - printk(" "); - esp_print_statreg(esp->sreg); - printk(" "); - esp_print_seqreg(esp->seqreg); - printk("\n"); - printk("esp%d: New -- ", esp->esp_id); - esp->sreg = esp_read(eregs->esp_status); - esp->seqreg = esp_read(eregs->esp_sstep); - esp->ireg = esp_read(eregs->esp_intrpt); - esp_print_ireg(esp->ireg); - printk(" "); - esp_print_statreg(esp->sreg); - printk(" "); - esp_print_seqreg(esp->seqreg); - printk("\n"); - ESPLOG(("esp%d: resetting bus\n", esp->esp_id)); - return do_reset_bus; /* ugh... */ -} - -/* Continue reading bytes for msgin phase. */ -static int esp_do_msgincont(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - if(esp->ireg & ESP_INTR_BSERV) { - /* in the right phase too? */ - if((esp->sreg & ESP_STAT_PMASK) == ESP_MIP) { - /* phew... */ - esp_cmd(esp, eregs, ESP_CMD_TI); - esp_advance_phase(esp->current_SC, in_msgindone); - return do_intr_end; - } - - /* We changed phase but ESP shows bus service, - * in this case it is most likely that we, the - * hacker who has been up for 20hrs straight - * staring at the screen, drowned in coffee - * smelling like retched cigarette ashes - * have miscoded something..... so, try to - * recover as best we can. - */ - ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id)); - } - esp_advance_phase(esp->current_SC, in_the_dark); - return do_phase_determine; -} - -static int check_singlebyte_msg(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - esp->prevmsgin = esp->cur_msgin[0]; - if(esp->cur_msgin[0] & 0x80) { - /* wheee... */ - ESPLOG(("esp%d: target sends identify amidst phases\n", - esp->esp_id)); - esp_advance_phase(esp->current_SC, in_the_dark); - return 0; - } else if(((esp->cur_msgin[0] & 0xf0) == 0x20) || - (esp->cur_msgin[0] == EXTENDED_MESSAGE)) { - esp->msgin_len = 2; - esp_advance_phase(esp->current_SC, in_msgincont); - return 0; - } - esp_advance_phase(esp->current_SC, in_the_dark); - switch(esp->cur_msgin[0]) { - default: - /* We don't want to hear about it. */ - ESPLOG(("esp%d: msg %02x which we don't know about\n", esp->esp_id, - esp->cur_msgin[0])); - return MESSAGE_REJECT; - - case NOP: - ESPLOG(("esp%d: target %d sends a nop\n", esp->esp_id, - esp->current_SC->device->id)); - return 0; - - case RESTORE_POINTERS: - /* In this case we might also have to backup the - * "slow command" pointer. It is rare to get such - * a save/restore pointer sequence so early in the - * bus transition sequences, but cover it. - */ - if(esp->esp_slowcmd) { - esp->esp_scmdleft = esp->current_SC->cmd_len; - esp->esp_scmdp = &esp->current_SC->cmnd[0]; - } - esp_restore_pointers(esp, esp->current_SC); - return 0; - - case SAVE_POINTERS: - esp_save_pointers(esp, esp->current_SC); - return 0; - - case COMMAND_COMPLETE: - case DISCONNECT: - /* Freeing the bus, let it go. */ - esp->current_SC->SCp.phase = in_freeing; - return 0; - - case MESSAGE_REJECT: - ESPMISC(("msg reject, ")); - if(esp->prevmsgout == EXTENDED_MESSAGE) { - struct esp_device *esp_dev = esp->current_SC->device->hostdata; - - /* Doesn't look like this target can - * do synchronous or WIDE transfers. - */ - ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n")); - esp_dev->sync = 1; - esp_dev->wide = 1; - esp_dev->sync_min_period = 0; - esp_dev->sync_max_offset = 0; - return 0; - } else { - ESPMISC(("not sync nego, sending ABORT\n")); - return ABORT; - } - }; -} - -/* Target negotiates for synchronous transfers before we do, this - * is legal although very strange. What is even funnier is that - * the SCSI2 standard specifically recommends against targets doing - * this because so many initiators cannot cope with this occurring. - */ -static int target_with_ants_in_pants(struct NCR_ESP *esp, - Scsi_Cmnd *SCptr, - struct esp_device *esp_dev) -{ - if(esp_dev->sync || SCptr->device->borken) { - /* sorry, no can do */ - ESPSDTR(("forcing to async, ")); - build_sync_nego_msg(esp, 0, 0); - esp_dev->sync = 1; - esp->snip = 1; - ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id)); - esp_advance_phase(SCptr, in_the_dark); - return EXTENDED_MESSAGE; - } - - /* Ok, we'll check them out... */ - return 0; -} - -static void sync_report(struct NCR_ESP *esp) -{ - int msg3, msg4; - char *type; - - msg3 = esp->cur_msgin[3]; - msg4 = esp->cur_msgin[4]; - if(msg4) { - int hz = 1000000000 / (msg3 * 4); - int integer = hz / 1000000; - int fraction = (hz - (integer * 1000000)) / 10000; - if((msg3 * 4) < 200) { - type = "FAST"; - } else { - type = "synchronous"; - } - - /* Do not transform this back into one big printk - * again, it triggers a bug in our sparc64-gcc272 - * sibling call optimization. -DaveM - */ - ESPLOG((KERN_INFO "esp%d: target %d ", - esp->esp_id, esp->current_SC->device->id)); - ESPLOG(("[period %dns offset %d %d.%02dMHz ", - (int) msg3 * 4, (int) msg4, - integer, fraction)); - ESPLOG(("%s SCSI%s]\n", type, - (((msg3 * 4) < 200) ? "-II" : ""))); - } else { - ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n", - esp->esp_id, esp->current_SC->device->id)); - } -} - -static int check_multibyte_msg(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - Scsi_Cmnd *SCptr = esp->current_SC; - struct esp_device *esp_dev = SCptr->device->hostdata; - unchar regval = 0; - int message_out = 0; - - ESPSDTR(("chk multibyte msg: ")); - if(esp->cur_msgin[2] == EXTENDED_SDTR) { - int period = esp->cur_msgin[3]; - int offset = esp->cur_msgin[4]; - - ESPSDTR(("is sync nego response, ")); - if(!esp->snip) { - int rval; - - /* Target negotiates first! */ - ESPSDTR(("target jumps the gun, ")); - message_out = EXTENDED_MESSAGE; /* we must respond */ - rval = target_with_ants_in_pants(esp, SCptr, esp_dev); - if(rval) - return rval; - } - - ESPSDTR(("examining sdtr, ")); - - /* Offset cannot be larger than ESP fifo size. */ - if(offset > 15) { - ESPSDTR(("offset too big %2x, ", offset)); - offset = 15; - ESPSDTR(("sending back new offset\n")); - build_sync_nego_msg(esp, period, offset); - return EXTENDED_MESSAGE; - } - - if(offset && period > esp->max_period) { - /* Yeee, async for this slow device. */ - ESPSDTR(("period too long %2x, ", period)); - build_sync_nego_msg(esp, 0, 0); - ESPSDTR(("hoping for msgout\n")); - esp_advance_phase(esp->current_SC, in_the_dark); - return EXTENDED_MESSAGE; - } else if (offset && period < esp->min_period) { - ESPSDTR(("period too short %2x, ", period)); - period = esp->min_period; - if(esp->erev > esp236) - regval = 4; - else - regval = 5; - } else if(offset) { - int tmp; - - ESPSDTR(("period is ok, ")); - tmp = esp->ccycle / 1000; - regval = (((period << 2) + tmp - 1) / tmp); - if(regval && (esp->erev > esp236)) { - if(period >= 50) - regval--; - } - } - - if(offset) { - unchar bit; - - esp_dev->sync_min_period = (regval & 0x1f); - esp_dev->sync_max_offset = (offset | esp->radelay); - if(esp->erev > esp236) { - if(esp->erev == fas100a) - bit = ESP_CONFIG3_FAST; - else - bit = ESP_CONFIG3_FSCSI; - if(period < 50) - esp->config3[SCptr->device->id] |= bit; - else - esp->config3[SCptr->device->id] &= ~bit; - esp->prev_cfg3 = esp->config3[SCptr->device->id]; - esp_write(eregs->esp_cfg3, esp->prev_cfg3); - } - esp->prev_soff = esp_dev->sync_min_period; - esp_write(eregs->esp_soff, esp->prev_soff); - esp->prev_stp = esp_dev->sync_max_offset; - esp_write(eregs->esp_stp, esp->prev_stp); - - ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n", - esp_dev->sync_max_offset, - esp_dev->sync_min_period, - esp->config3[scmd_id(SCptr)])); - - esp->snip = 0; - } else if(esp_dev->sync_max_offset) { - unchar bit; - - /* back to async mode */ - ESPSDTR(("unaccaptable sync nego, forcing async\n")); - esp_dev->sync_max_offset = 0; - esp_dev->sync_min_period = 0; - esp->prev_soff = 0; - esp_write(eregs->esp_soff, 0); - esp->prev_stp = 0; - esp_write(eregs->esp_stp, 0); - if(esp->erev > esp236) { - if(esp->erev == fas100a) - bit = ESP_CONFIG3_FAST; - else - bit = ESP_CONFIG3_FSCSI; - esp->config3[SCptr->device->id] &= ~bit; - esp->prev_cfg3 = esp->config3[SCptr->device->id]; - esp_write(eregs->esp_cfg3, esp->prev_cfg3); - } - } - - sync_report(esp); - - ESPSDTR(("chk multibyte msg: sync is known, ")); - esp_dev->sync = 1; - - if(message_out) { - ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n", - esp->esp_id)); - build_sync_nego_msg(esp, period, offset); - esp_advance_phase(SCptr, in_the_dark); - return EXTENDED_MESSAGE; - } - - ESPSDTR(("returning zero\n")); - esp_advance_phase(SCptr, in_the_dark); /* ...or else! */ - return 0; - } else if(esp->cur_msgin[2] == EXTENDED_WDTR) { - ESPLOG(("esp%d: AIEEE wide msg received\n", esp->esp_id)); - message_out = MESSAGE_REJECT; - } else if(esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) { - ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id)); - message_out = MESSAGE_REJECT; - } - esp_advance_phase(SCptr, in_the_dark); - return message_out; -} - -static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - Scsi_Cmnd *SCptr = esp->current_SC; - int message_out = 0, it = 0, rval; - - rval = skipahead1(esp, eregs, SCptr, in_msgin, in_msgindone); - if(rval) - return rval; - if(SCptr->SCp.sent_command != in_status) { - if(!(esp->ireg & ESP_INTR_DC)) { - if(esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) { - message_out = MSG_PARITY_ERROR; - esp_cmd(esp, eregs, ESP_CMD_FLUSH); - } else if((it = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES))!=1) { - /* We certainly dropped the ball somewhere. */ - message_out = INITIATOR_ERROR; - esp_cmd(esp, eregs, ESP_CMD_FLUSH); - } else if(!esp->msgin_len) { - it = esp_read(eregs->esp_fdata); - esp_advance_phase(SCptr, in_msgincont); - } else { - /* it is ok and we want it */ - it = esp->cur_msgin[esp->msgin_ctr] = - esp_read(eregs->esp_fdata); - esp->msgin_ctr++; - } - } else { - esp_advance_phase(SCptr, in_the_dark); - return do_work_bus; - } - } else { - it = esp->cur_msgin[0]; - } - if(!message_out && esp->msgin_len) { - if(esp->msgin_ctr < esp->msgin_len) { - esp_advance_phase(SCptr, in_msgincont); - } else if(esp->msgin_len == 1) { - message_out = check_singlebyte_msg(esp, eregs); - } else if(esp->msgin_len == 2) { - if(esp->cur_msgin[0] == EXTENDED_MESSAGE) { - if((it+2) >= 15) { - message_out = MESSAGE_REJECT; - } else { - esp->msgin_len = (it + 2); - esp_advance_phase(SCptr, in_msgincont); - } - } else { - message_out = MESSAGE_REJECT; /* foo on you */ - } - } else { - message_out = check_multibyte_msg(esp, eregs); - } - } - if(message_out < 0) { - return -message_out; - } else if(message_out) { - if(((message_out != 1) && - ((message_out < 0x20) || (message_out & 0x80)))) - esp->msgout_len = 1; - esp->cur_msgout[0] = message_out; - esp_cmd(esp, eregs, ESP_CMD_SATN); - esp_advance_phase(SCptr, in_the_dark); - esp->msgin_len = 0; - } - esp->sreg = esp_read(eregs->esp_status); - esp->sreg &= ~(ESP_STAT_INTR); - if((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD)) - esp_cmd(esp, eregs, ESP_CMD_MOK); - if((SCptr->SCp.sent_command == in_msgindone) && - (SCptr->SCp.phase == in_freeing)) - return esp_do_freebus(esp, eregs); - return do_intr_end; -} - -static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - unsigned char tmp; - Scsi_Cmnd *SCptr = esp->current_SC; - - esp_advance_phase(SCptr, in_cmdend); - esp_cmd(esp, eregs, ESP_CMD_FLUSH); - tmp = *esp->esp_scmdp++; - esp->esp_scmdleft--; - esp_write(eregs->esp_fdata, tmp); - esp_cmd(esp, eregs, ESP_CMD_TI); - return do_intr_end; -} - -static int esp_do_cmddone(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - esp_cmd(esp, eregs, ESP_CMD_NULL); - if(esp->ireg & ESP_INTR_BSERV) { - esp_advance_phase(esp->current_SC, in_the_dark); - return esp_do_phase_determine(esp, eregs); - } - ESPLOG(("esp%d: in do_cmddone() but didn't get BSERV interrupt.\n", - esp->esp_id)); - return do_reset_bus; -} - -static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - esp_cmd(esp, eregs, ESP_CMD_FLUSH); - switch(esp->msgout_len) { - case 1: - esp_write(eregs->esp_fdata, esp->cur_msgout[0]); - esp_cmd(esp, eregs, ESP_CMD_TI); - break; - - case 2: - if(esp->do_pio_cmds){ - esp_write(eregs->esp_fdata, esp->cur_msgout[0]); - esp_write(eregs->esp_fdata, esp->cur_msgout[1]); - esp_cmd(esp, eregs, ESP_CMD_TI); - } else { - esp->esp_command[0] = esp->cur_msgout[0]; - esp->esp_command[1] = esp->cur_msgout[1]; - esp->dma_setup(esp, esp->esp_command_dvma, 2, 0); - esp_setcount(eregs, 2); - esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); - } - break; - - case 4: - esp->snip = 1; - if(esp->do_pio_cmds){ - esp_write(eregs->esp_fdata, esp->cur_msgout[0]); - esp_write(eregs->esp_fdata, esp->cur_msgout[1]); - esp_write(eregs->esp_fdata, esp->cur_msgout[2]); - esp_write(eregs->esp_fdata, esp->cur_msgout[3]); - esp_cmd(esp, eregs, ESP_CMD_TI); - } else { - esp->esp_command[0] = esp->cur_msgout[0]; - esp->esp_command[1] = esp->cur_msgout[1]; - esp->esp_command[2] = esp->cur_msgout[2]; - esp->esp_command[3] = esp->cur_msgout[3]; - esp->dma_setup(esp, esp->esp_command_dvma, 4, 0); - esp_setcount(eregs, 4); - esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); - } - break; - - case 5: - esp->snip = 1; - if(esp->do_pio_cmds){ - esp_write(eregs->esp_fdata, esp->cur_msgout[0]); - esp_write(eregs->esp_fdata, esp->cur_msgout[1]); - esp_write(eregs->esp_fdata, esp->cur_msgout[2]); - esp_write(eregs->esp_fdata, esp->cur_msgout[3]); - esp_write(eregs->esp_fdata, esp->cur_msgout[4]); - esp_cmd(esp, eregs, ESP_CMD_TI); - } else { - esp->esp_command[0] = esp->cur_msgout[0]; - esp->esp_command[1] = esp->cur_msgout[1]; - esp->esp_command[2] = esp->cur_msgout[2]; - esp->esp_command[3] = esp->cur_msgout[3]; - esp->esp_command[4] = esp->cur_msgout[4]; - esp->dma_setup(esp, esp->esp_command_dvma, 5, 0); - esp_setcount(eregs, 5); - esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI); - } - break; - - default: - /* whoops */ - ESPMISC(("bogus msgout sending NOP\n")); - esp->cur_msgout[0] = NOP; - esp_write(eregs->esp_fdata, esp->cur_msgout[0]); - esp->msgout_len = 1; - esp_cmd(esp, eregs, ESP_CMD_TI); - break; - } - esp_advance_phase(esp->current_SC, in_msgoutdone); - return do_intr_end; -} - -static int esp_do_msgoutdone(struct NCR_ESP *esp, - struct ESP_regs *eregs) -{ - if((esp->msgout_len > 1) && esp->dma_barrier) - esp->dma_barrier(esp); - - if(!(esp->ireg & ESP_INTR_DC)) { - esp_cmd(esp, eregs, ESP_CMD_NULL); - switch(esp->sreg & ESP_STAT_PMASK) { - case ESP_MOP: - /* whoops, parity error */ - ESPLOG(("esp%d: still in msgout, parity error assumed\n", - esp->esp_id)); - if(esp->msgout_len > 1) - esp_cmd(esp, eregs, ESP_CMD_SATN); - esp_advance_phase(esp->current_SC, in_msgout); - return do_work_bus; - - case ESP_DIP: - break; - - default: - if(!fcount(esp, eregs) && - !(((struct esp_device *)esp->current_SC->device->hostdata)->sync_max_offset)) - esp_cmd(esp, eregs, ESP_CMD_FLUSH); - break; - - }; - } - - /* If we sent out a synchronous negotiation message, update - * our state. - */ - if(esp->cur_msgout[2] == EXTENDED_MESSAGE && - esp->cur_msgout[4] == EXTENDED_SDTR) { - esp->snip = 1; /* anal retentiveness... */ - } - - esp->prevmsgout = esp->cur_msgout[0]; - esp->msgout_len = 0; - esp_advance_phase(esp->current_SC, in_the_dark); - return esp_do_phase_determine(esp, eregs); -} - -static int esp_bus_unexpected(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - ESPLOG(("esp%d: command in weird state %2x\n", - esp->esp_id, esp->current_SC->SCp.phase)); - return do_reset_bus; -} - -static espfunc_t bus_vector[] = { - esp_do_data_finale, - esp_do_data_finale, - esp_bus_unexpected, - esp_do_msgin, - esp_do_msgincont, - esp_do_msgindone, - esp_do_msgout, - esp_do_msgoutdone, - esp_do_cmdbegin, - esp_do_cmddone, - esp_do_status, - esp_do_freebus, - esp_do_phase_determine, - esp_bus_unexpected, - esp_bus_unexpected, - esp_bus_unexpected, -}; - -/* This is the second tier in our dual-level SCSI state machine. */ -static int esp_work_bus(struct NCR_ESP *esp, struct ESP_regs *eregs) -{ - Scsi_Cmnd *SCptr = esp->current_SC; - unsigned int phase; - - ESPBUS(("esp_work_bus: ")); - if(!SCptr) { - ESPBUS(("reconnect\n")); - return esp_do_reconnect(esp, eregs); - } - phase = SCptr->SCp.phase; - if ((phase & 0xf0) == in_phases_mask) - return bus_vector[(phase & 0x0f)](esp, eregs); - else if((phase & 0xf0) == in_slct_mask) - return esp_select_complete(esp, eregs); - else - return esp_bus_unexpected(esp, eregs); -} - -static espfunc_t isvc_vector[] = { - NULL, - esp_do_phase_determine, - esp_do_resetbus, - esp_finish_reset, - esp_work_bus -}; - -/* Main interrupt handler for an esp adapter. */ -void esp_handle(struct NCR_ESP *esp) -{ - struct ESP_regs *eregs; - Scsi_Cmnd *SCptr; - int what_next = do_intr_end; - eregs = esp->eregs; - SCptr = esp->current_SC; - - if(esp->dma_irq_entry) - esp->dma_irq_entry(esp); - - /* Check for errors. */ - esp->sreg = esp_read(eregs->esp_status); - esp->sreg &= (~ESP_STAT_INTR); - esp->seqreg = (esp_read(eregs->esp_sstep) & ESP_STEP_VBITS); - esp->ireg = esp_read(eregs->esp_intrpt); /* Unlatch intr and stat regs */ - ESPIRQ(("handle_irq: [sreg<%02x> sstep<%02x> ireg<%02x>]\n", - esp->sreg, esp->seqreg, esp->ireg)); - if(esp->sreg & (ESP_STAT_SPAM)) { - /* Gross error, could be due to one of: - * - * - top of fifo overwritten, could be because - * we tried to do a synchronous transfer with - * an offset greater than ESP fifo size - * - * - top of command register overwritten - * - * - DMA setup to go in one direction, SCSI - * bus points in the other, whoops - * - * - weird phase change during asynchronous - * data phase while we are initiator - */ - ESPLOG(("esp%d: Gross error sreg=%2x\n", esp->esp_id, esp->sreg)); - - /* If a command is live on the bus we cannot safely - * reset the bus, so we'll just let the pieces fall - * where they may. Here we are hoping that the - * target will be able to cleanly go away soon - * so we can safely reset things. - */ - if(!SCptr) { - ESPLOG(("esp%d: No current cmd during gross error, " - "resetting bus\n", esp->esp_id)); - what_next = do_reset_bus; - goto state_machine; - } - } - - /* No current cmd is only valid at this point when there are - * commands off the bus or we are trying a reset. - */ - if(!SCptr && !esp->disconnected_SC && !(esp->ireg & ESP_INTR_SR)) { - /* Panic is safe, since current_SC is null. */ - ESPLOG(("esp%d: no command in esp_handle()\n", esp->esp_id)); - panic("esp_handle: current_SC == penguin within interrupt!"); - } - - if(esp->ireg & (ESP_INTR_IC)) { - /* Illegal command fed to ESP. Outside of obvious - * software bugs that could cause this, there is - * a condition with ESP100 where we can confuse the - * ESP into an erroneous illegal command interrupt - * because it does not scrape the FIFO properly - * for reselection. See esp100_reconnect_hwbug() - * to see how we try very hard to avoid this. - */ - ESPLOG(("esp%d: invalid command\n", esp->esp_id)); - - esp_dump_state(esp, eregs); - - if(SCptr) { - /* Devices with very buggy firmware can drop BSY - * during a scatter list interrupt when using sync - * mode transfers. We continue the transfer as - * expected, the target drops the bus, the ESP - * gets confused, and we get a illegal command - * interrupt because the bus is in the disconnected - * state now and ESP_CMD_TI is only allowed when - * a nexus is alive on the bus. - */ - ESPLOG(("esp%d: Forcing async and disabling disconnect for " - "target %d\n", esp->esp_id, SCptr->device->id)); - SCptr->device->borken = 1; /* foo on you */ - } - - what_next = do_reset_bus; - } else if(!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) { - int phase; - - if(SCptr) { - phase = SCptr->SCp.phase; - if(phase & in_phases_mask) { - what_next = esp_work_bus(esp, eregs); - } else if(phase & in_slct_mask) { - what_next = esp_select_complete(esp, eregs); - } else { - ESPLOG(("esp%d: interrupt for no good reason...\n", - esp->esp_id)); - what_next = do_intr_end; - } - } else { - ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n", - esp->esp_id)); - what_next = do_reset_bus; - } - } else if(esp->ireg & ESP_INTR_SR) { - ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id)); - what_next = do_reset_complete; - } else if(esp->ireg & (ESP_INTR_S | ESP_INTR_SATN)) { - ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n", - esp->esp_id)); - what_next = do_reset_bus; - } else if(esp->ireg & ESP_INTR_RSEL) { - if(!SCptr) { - /* This is ok. */ - what_next = esp_do_reconnect(esp, eregs); - } else if(SCptr->SCp.phase & in_slct_mask) { - /* Only selection code knows how to clean - * up properly. - */ - ESPDISC(("Reselected during selection attempt\n")); - what_next = esp_select_complete(esp, eregs); - } else { - ESPLOG(("esp%d: Reselected while bus is busy\n", - esp->esp_id)); - what_next = do_reset_bus; - } - } - - /* This is tier-one in our dual level SCSI state machine. */ -state_machine: - while(what_next != do_intr_end) { - if (what_next >= do_phase_determine && - what_next < do_intr_end) - what_next = isvc_vector[what_next](esp, eregs); - else { - /* state is completely lost ;-( */ - ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n", - esp->esp_id)); - what_next = do_reset_bus; - } - } - if(esp->dma_irq_exit) - esp->dma_irq_exit(esp); -} -EXPORT_SYMBOL(esp_handle); - -#ifndef CONFIG_SMP -irqreturn_t esp_intr(int irq, void *dev_id) -{ - struct NCR_ESP *esp; - unsigned long flags; - int again; - struct Scsi_Host *dev = dev_id; - - /* Handle all ESP interrupts showing at this IRQ level. */ - spin_lock_irqsave(dev->host_lock, flags); -repeat: - again = 0; - for_each_esp(esp) { -#ifndef __mips__ - if(((esp)->irq & 0xff) == irq) { -#endif - if(esp->dma_irq_p(esp)) { - again = 1; - - esp->dma_ints_off(esp); - - ESPIRQ(("I%d(", esp->esp_id)); - esp_handle(esp); - ESPIRQ((")")); - - esp->dma_ints_on(esp); - } -#ifndef __mips__ - } -#endif - } - if(again) - goto repeat; - spin_unlock_irqrestore(dev->host_lock, flags); - return IRQ_HANDLED; -} -#else -/* For SMP we only service one ESP on the list list at our IRQ level! */ -irqreturn_t esp_intr(int irq, void *dev_id) -{ - struct NCR_ESP *esp; - unsigned long flags; - struct Scsi_Host *dev = dev_id; - - /* Handle all ESP interrupts showing at this IRQ level. */ - spin_lock_irqsave(dev->host_lock, flags); - for_each_esp(esp) { - if(((esp)->irq & 0xf) == irq) { - if(esp->dma_irq_p(esp)) { - esp->dma_ints_off(esp); - - ESPIRQ(("I[%d:%d](", - smp_processor_id(), esp->esp_id)); - esp_handle(esp); - ESPIRQ((")")); - - esp->dma_ints_on(esp); - goto out; - } - } - } -out: - spin_unlock_irqrestore(dev->host_lock, flags); - return IRQ_HANDLED; -} -#endif - -int esp_slave_alloc(struct scsi_device *SDptr) -{ - struct esp_device *esp_dev = - kzalloc(sizeof(struct esp_device), GFP_ATOMIC); - - if (!esp_dev) - return -ENOMEM; - SDptr->hostdata = esp_dev; - return 0; -} - -void esp_slave_destroy(struct scsi_device *SDptr) -{ - struct NCR_ESP *esp = (struct NCR_ESP *) SDptr->host->hostdata; - - esp->targets_present &= ~(1 << sdev_id(SDptr)); - kfree(SDptr->hostdata); - SDptr->hostdata = NULL; -} - -#ifdef MODULE -int init_module(void) { return 0; } -void cleanup_module(void) {} -void esp_release(void) -{ - esps_in_use--; - esps_running = esps_in_use; -} -EXPORT_SYMBOL(esp_release); -#endif - -EXPORT_SYMBOL(esp_abort); -EXPORT_SYMBOL(esp_allocate); -EXPORT_SYMBOL(esp_deallocate); -EXPORT_SYMBOL(esp_initialize); -EXPORT_SYMBOL(esp_intr); -EXPORT_SYMBOL(esp_queue); -EXPORT_SYMBOL(esp_reset); -EXPORT_SYMBOL(esp_slave_alloc); -EXPORT_SYMBOL(esp_slave_destroy); -EXPORT_SYMBOL(esps_in_use); - -MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h deleted file mode 100644 index 00a0ba040dba..000000000000 --- a/drivers/scsi/NCR53C9x.h +++ /dev/null @@ -1,668 +0,0 @@ -/* NCR53C9x.c: Defines and structures for the NCR53C9x generic driver. - * - * Originally esp.h: Defines and structures for the Sparc ESP - * (Enhanced SCSI Processor) driver under Linux. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * - * Generalization by Jesper Skov (jskov@cygnus.co.uk) - * - * More generalization (for i386 stuff) by Tymm Twillman (tymm@computer.org) - */ - -#ifndef NCR53C9X_H -#define NCR53C9X_H - -#include <linux/interrupt.h> - -/* djweis for mac driver */ -#if defined(CONFIG_MAC) -#define PAD_SIZE 15 -#else -#define PAD_SIZE 3 -#endif - -/* Handle multiple hostadapters on Amiga - * generally PAD_SIZE = 3 - * but there is one exception: Oktagon (PAD_SIZE = 1) */ -#if defined(CONFIG_OKTAGON_SCSI) || defined(CONFIG_OKTAGON_SCSI_MODULE) -#undef PAD_SIZE -#if defined(CONFIG_BLZ1230_SCSI) || defined(CONFIG_BLZ1230_SCSI_MODULE) || \ - defined(CONFIG_BLZ2060_SCSI) || defined(CONFIG_BLZ2060_SCSI_MODULE) || \ - defined(CONFIG_CYBERSTORM_SCSI) || defined(CONFIG_CYBERSTORM_SCSI_MODULE) || \ - defined(CONFIG_CYBERSTORMII_SCSI) || defined(CONFIG_CYBERSTORMII_SCSI_MODULE) || \ - defined(CONFIG_FASTLANE_SCSI) || defined(CONFIG_FASTLANE_SCSI_MODULE) -#define MULTIPLE_PAD_SIZES -#else -#define PAD_SIZE 1 -#endif -#endif - -/* Macros for debugging messages */ - -#define DEBUG_ESP -/* #define DEBUG_ESP_DATA */ -/* #define DEBUG_ESP_QUEUE */ -/* #define DEBUG_ESP_DISCONNECT */ -/* #define DEBUG_ESP_STATUS */ -/* #define DEBUG_ESP_PHASES */ -/* #define DEBUG_ESP_WORKBUS */ -/* #define DEBUG_STATE_MACHINE */ -/* #define DEBUG_ESP_CMDS */ -/* #define DEBUG_ESP_IRQS */ -/* #define DEBUG_SDTR */ -/* #define DEBUG_ESP_SG */ - -/* Use the following to sprinkle debugging messages in a way which - * suits you if combinations of the above become too verbose when - * trying to track down a specific problem. - */ -/* #define DEBUG_ESP_MISC */ - -#if defined(DEBUG_ESP) -#define ESPLOG(foo) printk foo -#else -#define ESPLOG(foo) -#endif /* (DEBUG_ESP) */ - -#if defined(DEBUG_ESP_DATA) -#define ESPDATA(foo) printk foo -#else -#define ESPDATA(foo) -#endif - -#if defined(DEBUG_ESP_QUEUE) -#define ESPQUEUE(foo) printk foo -#else -#define ESPQUEUE(foo) -#endif - -#if defined(DEBUG_ESP_DISCONNECT) -#define ESPDISC(foo) printk foo -#else -#define ESPDISC(foo) -#endif - -#if defined(DEBUG_ESP_STATUS) -#define ESPSTAT(foo) printk foo -#else -#define ESPSTAT(foo) -#endif - -#if defined(DEBUG_ESP_PHASES) -#define ESPPHASE(foo) printk foo -#else -#define ESPPHASE(foo) -#endif - -#if defined(DEBUG_ESP_WORKBUS) -#define ESPBUS(foo) printk foo -#else -#define ESPBUS(foo) -#endif - -#if defined(DEBUG_ESP_IRQS) -#define ESPIRQ(foo) printk foo -#else -#define ESPIRQ(foo) -#endif - -#if defined(DEBUG_SDTR) -#define ESPSDTR(foo) printk foo -#else -#define ESPSDTR(foo) -#endif - -#if defined(DEBUG_ESP_MISC) -#define ESPMISC(foo) printk foo -#else -#define ESPMISC(foo) -#endif - -/* - * padding for register structure - */ -#ifdef CONFIG_JAZZ_ESP -#define EREGS_PAD(n) -#else -#ifndef MULTIPLE_PAD_SIZES -#define EREGS_PAD(n) unchar n[PAD_SIZE]; -#endif -#endif - -/* The ESP SCSI controllers have their register sets in three - * "classes": - * - * 1) Registers which are both read and write. - * 2) Registers which are read only. - * 3) Registers which are write only. - * - * Yet, they all live within the same IO space. - */ - -#if !defined(__i386__) && !defined(__x86_64__) - -#ifndef MULTIPLE_PAD_SIZES - -#ifdef CONFIG_CPU_HAS_WB -#include <asm/wbflush.h> -#define esp_write(__reg, __val) do{(__reg) = (__val); wbflush();} while(0) -#else -#define esp_write(__reg, __val) ((__reg) = (__val)) -#endif -#define esp_read(__reg) (__reg) - -struct ESP_regs { - /* Access Description Offset */ - volatile unchar esp_tclow; /* rw Low bits of the transfer count 0x00 */ - EREGS_PAD(tlpad1); - volatile unchar esp_tcmed; /* rw Mid bits of the transfer count 0x04 */ - EREGS_PAD(fdpad); - volatile unchar esp_fdata; /* rw FIFO data bits 0x08 */ - EREGS_PAD(cbpad); - volatile unchar esp_cmnd; /* rw SCSI command bits 0x0c */ - EREGS_PAD(stpad); - volatile unchar esp_status; /* ro ESP status register 0x10 */ -#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */ - EREGS_PAD(irqpd); - volatile unchar esp_intrpt; /* ro Kind of interrupt 0x14 */ -#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */ - EREGS_PAD(sspad); - volatile unchar esp_sstep; /* ro Sequence step register 0x18 */ -#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */ - EREGS_PAD(ffpad); - volatile unchar esp_fflags; /* ro Bits of current FIFO info 0x1c */ -#define esp_soff esp_fflags /* wo Sync offset 0x1c */ - EREGS_PAD(cf1pd); - volatile unchar esp_cfg1; /* rw First configuration register 0x20 */ - EREGS_PAD(cfpad); - volatile unchar esp_cfact; /* wo Clock conversion factor 0x24 */ - EREGS_PAD(ctpad); - volatile unchar esp_ctest; /* wo Chip test register 0x28 */ - EREGS_PAD(cf2pd); - volatile unchar esp_cfg2; /* rw Second configuration register 0x2c */ - EREGS_PAD(cf3pd); - - /* The following is only found on the 53C9X series SCSI chips */ - volatile unchar esp_cfg3; /* rw Third configuration register 0x30 */ - EREGS_PAD(cf4pd); - volatile unchar esp_cfg4; /* rw Fourth configuration register 0x34 */ - EREGS_PAD(thpd); - /* The following is found on all chips except the NCR53C90 (ESP100) */ - volatile unchar esp_tchi; /* rw High bits of transfer count 0x38 */ -#define esp_uid esp_tchi /* ro Unique ID code 0x38 */ - EREGS_PAD(fgpad); - volatile unchar esp_fgrnd; /* rw Data base for fifo 0x3c */ -}; - -#else /* MULTIPLE_PAD_SIZES */ - -#define esp_write(__reg, __val) (*(__reg) = (__val)) -#define esp_read(__reg) (*(__reg)) - -struct ESP_regs { - unsigned char io_addr[64]; /* dummy */ - /* Access Description Offset */ -#define esp_tclow io_addr /* rw Low bits of the transfer count 0x00 */ -#define esp_tcmed io_addr + (1<<(esp->shift)) /* rw Mid bits of the transfer count 0x04 */ -#define esp_fdata io_addr + (2<<(esp->shift)) /* rw FIFO data bits 0x08 */ -#define esp_cmnd io_addr + (3<<(esp->shift)) /* rw SCSI command bits 0x0c */ -#define esp_status io_addr + (4<<(esp->shift)) /* ro ESP status register 0x10 */ -#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */ -#define esp_intrpt io_addr + (5<<(esp->shift)) /* ro Kind of interrupt 0x14 */ -#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */ -#define esp_sstep io_addr + (6<<(esp->shift)) /* ro Sequence step register 0x18 */ -#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */ -#define esp_fflags io_addr + (7<<(esp->shift)) /* ro Bits of current FIFO info 0x1c */ -#define esp_soff esp_fflags /* wo Sync offset 0x1c */ -#define esp_cfg1 io_addr + (8<<(esp->shift)) /* rw First configuration register 0x20 */ -#define esp_cfact io_addr + (9<<(esp->shift)) /* wo Clock conversion factor 0x24 */ -#define esp_ctest io_addr + (10<<(esp->shift)) /* wo Chip test register 0x28 */ -#define esp_cfg2 io_addr + (11<<(esp->shift)) /* rw Second configuration register 0x2c */ - - /* The following is only found on the 53C9X series SCSI chips */ -#define esp_cfg3 io_addr + (12<<(esp->shift)) /* rw Third configuration register 0x30 */ -#define esp_cfg4 io_addr + (13<<(esp->shift)) /* rw Fourth configuration register 0x34 */ - - /* The following is found on all chips except the NCR53C90 (ESP100) */ -#define esp_tchi io_addr + (14<<(esp->shift)) /* rw High bits of transfer count 0x38 */ -#define esp_uid esp_tchi /* ro Unique ID code 0x38 */ -#define esp_fgrnd io_addr + (15<<(esp->shift)) /* rw Data base for fifo 0x3c */ -}; - -#endif - -#else /* !defined(__i386__) && !defined(__x86_64__) */ - -#define esp_write(__reg, __val) outb((__val), (__reg)) -#define esp_read(__reg) inb((__reg)) - -struct ESP_regs { - unsigned int io_addr; - /* Access Description Offset */ -#define esp_tclow io_addr /* rw Low bits of the transfer count 0x00 */ -#define esp_tcmed io_addr + 1 /* rw Mid bits of the transfer count 0x04 */ -#define esp_fdata io_addr + 2 /* rw FIFO data bits 0x08 */ -#define esp_cmnd io_addr + 3 /* rw SCSI command bits 0x0c */ -#define esp_status io_addr + 4 /* ro ESP status register 0x10 */ -#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */ -#define esp_intrpt io_addr + 5 /* ro Kind of interrupt 0x14 */ -#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */ -#define esp_sstep io_addr + 6 /* ro Sequence step register 0x18 */ -#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */ -#define esp_fflags io_addr + 7 /* ro Bits of current FIFO info 0x1c */ -#define esp_soff esp_fflags /* wo Sync offset 0x1c */ -#define esp_cfg1 io_addr + 8 /* rw First configuration register 0x20 */ -#define esp_cfact io_addr + 9 /* wo Clock conversion factor 0x24 */ -#define esp_ctest io_addr + 10 /* wo Chip test register 0x28 */ -#define esp_cfg2 io_addr + 11 /* rw Second configuration register 0x2c */ - - /* The following is only found on the 53C9X series SCSI chips */ -#define esp_cfg3 io_addr + 12 /* rw Third configuration register 0x30 */ -#define esp_cfg4 io_addr + 13 /* rw Fourth configuration register 0x34 */ - - /* The following is found on all chips except the NCR53C90 (ESP100) */ -#define esp_tchi io_addr + 14 /* rw High bits of transfer count 0x38 */ -#define esp_uid esp_tchi /* ro Unique ID code 0x38 */ -#define esp_fgrnd io_addr + 15 /* rw Data base for fifo 0x3c */ -}; - -#endif /* !defined(__i386__) && !defined(__x86_64__) */ - -/* Various revisions of the ESP board. */ -enum esp_rev { - esp100 = 0x00, /* NCR53C90 - very broken */ - esp100a = 0x01, /* NCR53C90A */ - esp236 = 0x02, - fas236 = 0x03, - fas100a = 0x04, - fast = 0x05, - fas366 = 0x06, - fas216 = 0x07, - fsc = 0x08, /* SYM53C94-2 */ - espunknown = 0x09 -}; - -/* We allocate one of these for each scsi device and attach it to - * SDptr->hostdata for use in the driver - */ -struct esp_device { - unsigned char sync_min_period; - unsigned char sync_max_offset; - unsigned sync:1; - unsigned wide:1; - unsigned disconnect:1; -}; - -/* We get one of these for each ESP probed. */ -struct NCR_ESP { - struct NCR_ESP *next; /* Next ESP on probed or NULL */ - struct ESP_regs *eregs; /* All esp registers */ - int dma; /* Who I do transfers with. */ - void *dregs; /* And his registers. */ - struct Scsi_Host *ehost; /* Backpointer to SCSI Host */ - - void *edev; /* Pointer to controller base/SBus */ - int esp_id; /* Unique per-ESP ID number */ - - /* ESP Configuration Registers */ - unsigned char config1; /* Copy of the 1st config register */ - unsigned char config2; /* Copy of the 2nd config register */ - unsigned char config3[16]; /* Copy of the 3rd config register */ - - /* The current command we are sending to the ESP chip. This esp_command - * ptr needs to be mapped in DVMA area so we can send commands and read - * from the ESP fifo without burning precious CPU cycles. Programmed I/O - * sucks when we have the DVMA to do it for us. The ESP is stupid and will - * only send out 6, 10, and 12 byte SCSI commands, others we need to send - * one byte at a time. esp_slowcmd being set says that we are doing one - * of the command types ESP doesn't understand, esp_scmdp keeps track of - * which byte we are sending, esp_scmdleft says how many bytes to go. - */ - volatile unchar *esp_command; /* Location of command (CPU view) */ - __u32 esp_command_dvma; /* Location of command (DVMA view) */ - unsigned char esp_clen; /* Length of this command */ - unsigned char esp_slowcmd; - unsigned char *esp_scmdp; - unsigned char esp_scmdleft; - - /* The following are used to determine the cause of an IRQ. Upon every - * IRQ entry we synchronize these with the hardware registers. - */ - unchar ireg; /* Copy of ESP interrupt register */ - unchar sreg; /* Same for ESP status register */ - unchar seqreg; /* The ESP sequence register */ - - /* The following is set when a premature interrupt condition is detected - * in some FAS revisions. - */ - unchar fas_premature_intr_workaround; - - /* To save register writes to the ESP, which can be expensive, we - * keep track of the previous value that various registers had for - * the last target we connected to. If they are the same for the - * current target, we skip the register writes as they are not needed. - */ - unchar prev_soff, prev_stp, prev_cfg3; - - /* For each target we keep track of save/restore data - * pointer information. This needs to be updated majorly - * when we add support for tagged queueing. -DaveM - */ - struct esp_pointers { - char *saved_ptr; - struct scatterlist *saved_buffer; - int saved_this_residual; - int saved_buffers_residual; - } data_pointers[16] /*XXX [MAX_TAGS_PER_TARGET]*/; - - /* Clock periods, frequencies, synchronization, etc. */ - unsigned int cfreq; /* Clock frequency in HZ */ - unsigned int cfact; /* Clock conversion factor */ - unsigned int ccycle; /* One ESP clock cycle */ - unsigned int ctick; /* One ESP clock time */ - unsigned int radelay; /* FAST chip req/ack delay */ - unsigned int neg_defp; /* Default negotiation period */ - unsigned int sync_defp; /* Default sync transfer period */ - unsigned int max_period; /* longest our period can be */ - unsigned int min_period; /* shortest period we can withstand */ - /* For slow to medium speed input clock rates we shoot for 5mb/s, - * but for high input clock rates we try to do 10mb/s although I - * don't think a transfer can even run that fast with an ESP even - * with DMA2 scatter gather pipelining. - */ -#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */ -#define SYNC_DEFP_FAST 0x19 /* 10mb/s */ - - unsigned int snip; /* Sync. negotiation in progress */ - unsigned int wnip; /* WIDE negotiation in progress */ - unsigned int targets_present; /* targets spoken to before */ - - int current_transfer_size; /* Set at beginning of data dma */ - - unchar espcmdlog[32]; /* Log of current esp cmds sent. */ - unchar espcmdent; /* Current entry in esp cmd log. */ - - /* Misc. info about this ESP */ - enum esp_rev erev; /* ESP revision */ - int irq; /* IRQ for this ESP */ - int scsi_id; /* Who am I as initiator? */ - int scsi_id_mask; /* Bitmask of 'me'. */ - int diff; /* Differential SCSI bus? */ - int slot; /* Slot the adapter occupies */ - - /* Our command queues, only one cmd lives in the current_SC queue. */ - Scsi_Cmnd *issue_SC; /* Commands to be issued */ - Scsi_Cmnd *current_SC; /* Who is currently working the bus */ - Scsi_Cmnd *disconnected_SC; /* Commands disconnected from the bus */ - - /* Message goo */ - unchar cur_msgout[16]; - unchar cur_msgin[16]; - unchar prevmsgout, prevmsgin; - unchar msgout_len, msgin_len; - unchar msgout_ctr, msgin_ctr; - - /* States that we cannot keep in the per cmd structure because they - * cannot be assosciated with any specific command. - */ - unchar resetting_bus; - wait_queue_head_t reset_queue; - - unchar do_pio_cmds; /* Do command transfer with pio */ - - /* How much bits do we have to shift the registers */ - unsigned char shift; - - /* Functions handling DMA - */ - /* Required functions */ - int (*dma_bytes_sent)(struct NCR_ESP *, int); - int (*dma_can_transfer)(struct NCR_ESP *, Scsi_Cmnd *); - void (*dma_dump_state)(struct NCR_ESP *); - void (*dma_init_read)(struct NCR_ESP *, __u32, int); - void (*dma_init_write)(struct NCR_ESP *, __u32, int); - void (*dma_ints_off)(struct NCR_ESP *); - void (*dma_ints_on)(struct NCR_ESP *); - int (*dma_irq_p)(struct NCR_ESP *); - int (*dma_ports_p)(struct NCR_ESP *); - void (*dma_setup)(struct NCR_ESP *, __u32, int, int); - - /* Optional functions (i.e. may be initialized to 0) */ - void (*dma_barrier)(struct NCR_ESP *); - void (*dma_drain)(struct NCR_ESP *); - void (*dma_invalidate)(struct NCR_ESP *); - void (*dma_irq_entry)(struct NCR_ESP *); - void (*dma_irq_exit)(struct NCR_ESP *); - void (*dma_led_off)(struct NCR_ESP *); - void (*dma_led_on)(struct NCR_ESP *); - void (*dma_poll)(struct NCR_ESP *, unsigned char *); - void (*dma_reset)(struct NCR_ESP *); - - /* Optional virtual DMA functions */ - void (*dma_mmu_get_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *); - void (*dma_mmu_get_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *); - void (*dma_mmu_release_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *); - void (*dma_mmu_release_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *); - void (*dma_advance_sg)(Scsi_Cmnd *); -}; - -/* Bitfield meanings for the above registers. */ - -/* ESP config reg 1, read-write, found on all ESP chips */ -#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */ -#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */ -#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */ -#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */ -#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */ -#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */ - -/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236+fsc chips */ -#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236,fsc) */ -#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236,fsc) */ -#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */ -#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tmode only) */ -#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */ -#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */ -#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236,fsc) */ -#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,esp216,fsc) */ -#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (esp236) */ -#define ESP_CONFIG2_RFB 0x80 /* Reserve FIFO byte (fsc) */ -#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */ - -/* ESP config register 3 read-write, found only esp236+fas236+fas100a+fsc chips */ -#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/fas366) */ -#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236/fsc) */ -#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a) */ -#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236/fsc) */ -#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a) */ -#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236/fsc) */ -#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a) */ -#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236/fsc) */ -#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a) */ -#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236/fsc) */ -#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236/fsc) */ -#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236/fsc) */ -#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236/fsc) */ - -/* ESP config register 4 read-write, found only on fsc chips */ -#define ESP_CONFIG4_BBTE 0x01 /* Back-to-Back transfer enable */ -#define ESP_CONFIG4_TEST 0x02 /* Transfer counter test mode */ -#define ESP_CONFIG4_EAN 0x04 /* Enable Active Negotiation */ - -/* ESP command register read-write */ -/* Group 1 commands: These may be sent at any point in time to the ESP - * chip. None of them can generate interrupts 'cept - * the "SCSI bus reset" command if you have not disabled - * SCSI reset interrupts in the config1 ESP register. - */ -#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */ -#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */ -#define ESP_CMD_RC 0x02 /* Chip reset */ -#define ESP_CMD_RS 0x03 /* SCSI bus reset */ - -/* Group 2 commands: ESP must be an initiator and connected to a target - * for these commands to work. - */ -#define ESP_CMD_TI 0x10 /* Transfer Information */ -#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */ -#define ESP_CMD_MOK 0x12 /* Message okie-dokie */ -#define ESP_CMD_TPAD 0x18 /* Transfer Pad */ -#define ESP_CMD_SATN 0x1a /* Set ATN */ -#define ESP_CMD_RATN 0x1b /* De-assert ATN */ - -/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected - * to a target as the initiator for these commands to work. - */ -#define ESP_CMD_SMSG 0x20 /* Send message */ -#define ESP_CMD_SSTAT 0x21 /* Send status */ -#define ESP_CMD_SDATA 0x22 /* Send data */ -#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */ -#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */ -#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */ -#define ESP_CMD_DCNCT 0x27 /* Disconnect */ -#define ESP_CMD_RMSG 0x28 /* Receive Message */ -#define ESP_CMD_RCMD 0x29 /* Receive Command */ -#define ESP_CMD_RDATA 0x2a /* Receive Data */ -#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */ - -/* Group 4 commands: The ESP must be in the disconnected state and must - * not be connected to any targets as initiator for - * these commands to work. - */ -#define ESP_CMD_RSEL 0x40 /* Reselect */ -#define ESP_CMD_SEL 0x41 /* Select w/o ATN */ -#define ESP_CMD_SELA 0x42 /* Select w/ATN */ -#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */ -#define ESP_CMD_ESEL 0x44 /* Enable selection */ -#define ESP_CMD_DSEL 0x45 /* Disable selections */ -#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */ -#define ESP_CMD_RSEL3 0x47 /* Reselect3 */ - -/* This bit enables the ESP's DMA */ -#define ESP_CMD_DMA 0x80 /* Do DMA? */ - -/* ESP status register read-only */ -#define ESP_STAT_PIO 0x01 /* IO phase bit */ -#define ESP_STAT_PCD 0x02 /* CD phase bit */ -#define ESP_STAT_PMSG 0x04 /* MSG phase bit */ -#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */ -#define ESP_STAT_TDONE 0x08 /* Transfer Completed */ -#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */ -#define ESP_STAT_PERR 0x20 /* Parity error */ -#define ESP_STAT_SPAM 0x40 /* Real bad error */ -/* This indicates the 'interrupt pending' condition, it is a reserved - * bit on old revs of the ESP (ESP100, ESP100A, FAS100A). - */ -#define ESP_STAT_INTR 0x80 /* Interrupt */ - -/* The status register can be masked with ESP_STAT_PMASK and compared - * with the following values to determine the current phase the ESP - * (at least thinks it) is in. For our purposes we also add our own - * software 'done' bit for our phase management engine. - */ -#define ESP_DOP (0) /* Data Out */ -#define ESP_DIP (ESP_STAT_PIO) /* Data In */ -#define ESP_CMDP (ESP_STAT_PCD) /* Command */ -#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */ -#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */ -#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */ - -/* ESP interrupt register read-only */ -#define ESP_INTR_S 0x01 /* Select w/o ATN */ -#define ESP_INTR_SATN 0x02 /* Select w/ATN */ -#define ESP_INTR_RSEL 0x04 /* Reselected */ -#define ESP_INTR_FDONE 0x08 /* Function done */ -#define ESP_INTR_BSERV 0x10 /* Bus service */ -#define ESP_INTR_DC 0x20 /* Disconnect */ -#define ESP_INTR_IC 0x40 /* Illegal command given */ -#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */ - -/* Interrupt status macros */ -#define ESP_SRESET_IRQ(esp) ((esp)->intreg & (ESP_INTR_SR)) -#define ESP_ILLCMD_IRQ(esp) ((esp)->intreg & (ESP_INTR_IC)) -#define ESP_SELECT_WITH_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_SATN)) -#define ESP_SELECT_WITHOUT_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_S)) -#define ESP_SELECTION_IRQ(esp) ((ESP_SELECT_WITH_ATN_IRQ(esp)) || \ - (ESP_SELECT_WITHOUT_ATN_IRQ(esp))) -#define ESP_RESELECTION_IRQ(esp) ((esp)->intreg & (ESP_INTR_RSEL)) - -/* ESP sequence step register read-only */ -#define ESP_STEP_VBITS 0x07 /* Valid bits */ -#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */ -#define ESP_STEP_SID 0x01 /* One msg byte sent */ -#define ESP_STEP_NCMD 0x02 /* Was not in command phase */ -#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd - * bytes to be lost - */ -#define ESP_STEP_FINI4 0x04 /* Command was sent ok */ - -/* Ho hum, some ESP's set the step register to this as well... */ -#define ESP_STEP_FINI5 0x05 -#define ESP_STEP_FINI6 0x06 -#define ESP_STEP_FINI7 0x07 -#define ESP_STEP_SOM 0x08 /* Synchronous Offset Max */ - -/* ESP chip-test register read-write */ -#define ESP_TEST_TARG 0x01 /* Target test mode */ -#define ESP_TEST_INI 0x02 /* Initiator test mode */ -#define ESP_TEST_TS 0x04 /* Tristate test mode */ - -/* ESP unique ID register read-only, found on fas236+fas100a+fsc only */ -#define ESP_UID_F100A 0x00 /* FAS100A */ -#define ESP_UID_F236 0x02 /* FAS236 */ -#define ESP_UID_FSC 0xa2 /* NCR53CF9x-2 */ -#define ESP_UID_REV 0x07 /* ESP revision */ -#define ESP_UID_FAM 0xf8 /* ESP family */ - -/* ESP fifo flags register read-only */ -/* Note that the following implies a 16 byte FIFO on the ESP. */ -#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */ -#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100,fsc) */ -#define ESP_FF_SSTEP 0xe0 /* Sequence step */ - -/* ESP clock conversion factor register write-only */ -#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */ -#define ESP_CCF_NEVER 0x01 /* Set it to this and die */ -#define ESP_CCF_F2 0x02 /* 10MHz */ -#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */ -#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */ -#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */ -#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */ -#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */ - -#define ESP_BUS_TIMEOUT 275 /* In milli-seconds */ -#define ESP_TIMEO_CONST 8192 -#define FSC_TIMEO_CONST 7668 -#define ESP_NEG_DEFP(mhz, cfact) \ - ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact))) -#define FSC_NEG_DEFP(mhz, cfact) \ - ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (7668 * (cfact))) -#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000)) -#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000)) - - -/* UGLY, UGLY, UGLY! */ -extern int nesps, esps_in_use, esps_running; - -/* For our interrupt engine. */ -#define for_each_esp(esp) \ - for((esp) = espchain; (esp); (esp) = (esp)->next) - - -/* External functions */ -extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs); -extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *, int); -extern void esp_deallocate(struct NCR_ESP *); -extern void esp_release(void); -extern void esp_initialize(struct NCR_ESP *); -extern irqreturn_t esp_intr(int, void *); -extern const char *esp_info(struct Scsi_Host *); -extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -extern int esp_abort(Scsi_Cmnd *); -extern int esp_reset(Scsi_Cmnd *); -extern int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, - int inout); -extern int esp_slave_alloc(struct scsi_device *); -extern void esp_slave_destroy(struct scsi_device *); -#endif /* !(NCR53C9X_H) */ diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index d7235f42cf5f..bfd0e64964ac 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -859,44 +859,31 @@ static int setinqserial(struct aac_dev *dev, void *data, int cid) le32_to_cpu(dev->adapter_info.serial[0]), cid); } -static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code, - u8 a_sense_code, u8 incorrect_length, - u8 bit_pointer, u16 field_pointer, - u32 residue) +static inline void set_sense(struct sense_data *sense_data, u8 sense_key, + u8 sense_code, u8 a_sense_code, u8 bit_pointer, u16 field_pointer) { - sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */ + u8 *sense_buf = (u8 *)sense_data; + /* Sense data valid, err code 70h */ + sense_buf[0] = 0x70; /* No info field */ sense_buf[1] = 0; /* Segment number, always zero */ - if (incorrect_length) { - sense_buf[2] = sense_key | 0x20;/* Set ILI bit | sense key */ - sense_buf[3] = BYTE3(residue); - sense_buf[4] = BYTE2(residue); - sense_buf[5] = BYTE1(residue); - sense_buf[6] = BYTE0(residue); - } else - sense_buf[2] = sense_key; /* Sense key */ - - if (sense_key == ILLEGAL_REQUEST) - sense_buf[7] = 10; /* Additional sense length */ - else - sense_buf[7] = 6; /* Additional sense length */ + sense_buf[2] = sense_key; /* Sense key */ sense_buf[12] = sense_code; /* Additional sense code */ sense_buf[13] = a_sense_code; /* Additional sense code qualifier */ + if (sense_key == ILLEGAL_REQUEST) { - sense_buf[15] = 0; + sense_buf[7] = 10; /* Additional sense length */ - if (sense_code == SENCODE_INVALID_PARAM_FIELD) - sense_buf[15] = 0x80;/* Std sense key specific field */ + sense_buf[15] = bit_pointer; /* Illegal parameter is in the parameter block */ - if (sense_code == SENCODE_INVALID_CDB_FIELD) - sense_buf[15] = 0xc0;/* Std sense key specific field */ + sense_buf[15] |= 0xc0;/* Std sense key specific field */ /* Illegal parameter is in the CDB block */ - sense_buf[15] |= bit_pointer; sense_buf[16] = field_pointer >> 8; /* MSB */ sense_buf[17] = field_pointer; /* LSB */ - } + } else + sense_buf[7] = 6; /* Additional sense length */ } static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) @@ -906,11 +893,9 @@ static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense((u8 *) &dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, - SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, - 0, 0); + set_sense(&dev->fsa_dev[cid].sense_data, + HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); @@ -1520,11 +1505,9 @@ static void io_callback(void *context, struct fib * fibptr) le32_to_cpu(readreply->status)); #endif scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense((u8 *) &dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, - SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, - 0, 0); + set_sense(&dev->fsa_dev[cid].sense_data, + HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); @@ -1733,11 +1716,9 @@ static void synchronize_callback(void *context, struct fib *fibptr) le32_to_cpu(synchronizereply->status)); cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense((u8 *)&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, - SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, - 0, 0); + set_sense(&dev->fsa_dev[cid].sense_data, + HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, + ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); @@ -1945,10 +1926,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) { dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0])); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense((u8 *) &dev->fsa_dev[cid].sense_data, - ILLEGAL_REQUEST, - SENCODE_INVALID_COMMAND, - ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); + set_sense(&dev->fsa_dev[cid].sense_data, + ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, + ASENCODE_INVALID_COMMAND, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); @@ -1995,10 +1975,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense((u8 *) &dev->fsa_dev[cid].sense_data, - ILLEGAL_REQUEST, - SENCODE_INVALID_CDB_FIELD, - ASENCODE_NO_SENSE, 0, 7, 2, 0); + set_sense(&dev->fsa_dev[cid].sense_data, + ILLEGAL_REQUEST, SENCODE_INVALID_CDB_FIELD, + ASENCODE_NO_SENSE, 7, 2); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, @@ -2254,9 +2233,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) */ dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0])); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense((u8 *) &dev->fsa_dev[cid].sense_data, - ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, - ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); + set_sense(&dev->fsa_dev[cid].sense_data, + ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, + ASENCODE_INVALID_COMMAND, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index f8afa358b6b6..abef05146d75 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -243,6 +243,7 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) * Search the list of AdapterFibContext addresses on the adapter * to be sure this is a valid address */ + spin_lock_irqsave(&dev->fib_lock, flags); entry = dev->fib_list.next; fibctx = NULL; @@ -251,24 +252,25 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) /* * Extract the AdapterFibContext from the Input parameters. */ - if (fibctx->unique == f.fibctx) { /* We found a winner */ + if (fibctx->unique == f.fibctx) { /* We found a winner */ break; } entry = entry->next; fibctx = NULL; } if (!fibctx) { + spin_unlock_irqrestore(&dev->fib_lock, flags); dprintk ((KERN_INFO "Fib Context not found\n")); return -EINVAL; } if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || (fibctx->size != sizeof(struct aac_fib_context))) { + spin_unlock_irqrestore(&dev->fib_lock, flags); dprintk ((KERN_INFO "Fib Context corrupt?\n")); return -EINVAL; } status = 0; - spin_lock_irqsave(&dev->fib_lock, flags); /* * If there are no fibs to send back, then either wait or return * -EAGAIN @@ -414,8 +416,8 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) * @arg: ioctl arguments * * This routine returns the driver version. - * Under Linux, there have been no version incompatibilities, so this is - * simple! + * Under Linux, there have been no version incompatibilities, so this is + * simple! */ static int check_revision(struct aac_dev *dev, void __user *arg) @@ -463,7 +465,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) u32 data_dir; void __user *sg_user[32]; void *sg_list[32]; - u32 sg_indx = 0; + u32 sg_indx = 0; u32 byte_count = 0; u32 actual_fibsize64, actual_fibsize = 0; int i; @@ -517,11 +519,11 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) // Fix up srb for endian and force some values srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this - srbcmd->channel = cpu_to_le32(user_srbcmd->channel); + srbcmd->channel = cpu_to_le32(user_srbcmd->channel); srbcmd->id = cpu_to_le32(user_srbcmd->id); - srbcmd->lun = cpu_to_le32(user_srbcmd->lun); - srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); - srbcmd->flags = cpu_to_le32(flags); + srbcmd->lun = cpu_to_le32(user_srbcmd->lun); + srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); + srbcmd->flags = cpu_to_le32(flags); srbcmd->retry_limit = 0; // Obsolete parameter srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size); memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb)); @@ -786,9 +788,9 @@ static int aac_get_pci_info(struct aac_dev* dev, void __user *arg) pci_info.bus = dev->pdev->bus->number; pci_info.slot = PCI_SLOT(dev->pdev->devfn); - if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { - dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); - return -EFAULT; + if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { + dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); + return -EFAULT; } return 0; } diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index fb0886140dd7..e80d2a0c46af 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1130,31 +1130,29 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, if (error < 0) goto out_deinit; - if (!(aac->adapter_info.options & AAC_OPT_NEW_COMM)) { - error = pci_set_dma_max_seg_size(pdev, 65536); - if (error) - goto out_deinit; - } - /* * Lets override negotiations and drop the maximum SG limit to 34 */ if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) && - (aac->scsi_host_ptr->sg_tablesize > 34)) { - aac->scsi_host_ptr->sg_tablesize = 34; - aac->scsi_host_ptr->max_sectors - = (aac->scsi_host_ptr->sg_tablesize * 8) + 112; + (shost->sg_tablesize > 34)) { + shost->sg_tablesize = 34; + shost->max_sectors = (shost->sg_tablesize * 8) + 112; } if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) && - (aac->scsi_host_ptr->sg_tablesize > 17)) { - aac->scsi_host_ptr->sg_tablesize = 17; - aac->scsi_host_ptr->max_sectors - = (aac->scsi_host_ptr->sg_tablesize * 8) + 112; + (shost->sg_tablesize > 17)) { + shost->sg_tablesize = 17; + shost->max_sectors = (shost->sg_tablesize * 8) + 112; } + error = pci_set_dma_max_seg_size(pdev, + (aac->adapter_info.options & AAC_OPT_NEW_COMM) ? + (shost->max_sectors << 9) : 65536); + if (error) + goto out_deinit; + /* - * Firware printf works only with older firmware. + * Firmware printf works only with older firmware. */ if (aac_drivers[index].quirks & AAC_QUIRK_34SG) aac->printf_enabled = 1; diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 374ed025dc5a..ccef891d642f 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -12261,7 +12261,7 @@ static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr) /* * Write the EEPROM from 'cfg_buf'. */ -void __devinit +static void __devinit AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) { ushort *wbuf; @@ -12328,7 +12328,7 @@ AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) /* * Write the EEPROM from 'cfg_buf'. */ -void __devinit +static void __devinit AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) { ushort *wbuf; @@ -12395,7 +12395,7 @@ AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) /* * Write the EEPROM from 'cfg_buf'. */ -void __devinit +static void __devinit AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf) { ushort *wbuf; diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index a67e29f83ae5..57786502e3ec 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -48,7 +48,7 @@ struct class_device_attribute; /*The limit of outstanding scsi command that firmware can handle*/ #define ARCMSR_MAX_OUTSTANDING_CMD 256 #define ARCMSR_MAX_FREECCB_NUM 320 -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/08/30" +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/12/24" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 @@ -248,6 +248,7 @@ struct FIRMWARE_INFO #define ARCMSR_MESSAGE_START_BGRB 0x00060008 #define ARCMSR_MESSAGE_START_DRIVER_MODE 0x000E0008 #define ARCMSR_MESSAGE_SET_POST_WINDOW 0x000F0008 +#define ARCMSR_MESSAGE_ACTIVE_EOI_MODE 0x00100008 /* ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK */ #define ARCMSR_MESSAGE_FIRMWARE_OK 0x80000000 /* ioctl transfer */ @@ -256,6 +257,7 @@ struct FIRMWARE_INFO #define ARCMSR_DRV2IOP_DATA_READ_OK 0x00000002 #define ARCMSR_DRV2IOP_CDB_POSTED 0x00000004 #define ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED 0x00000008 +#define ARCMSR_DRV2IOP_END_OF_INTERRUPT 0x00000010 /* data tunnel buffer between user space program and its firmware */ /* user space data to iop 128bytes */ diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index f4a202e8df26..4f9ff32cfed0 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -315,9 +315,6 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); } - reg = (struct MessageUnit_B *)(dma_coherent + - ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock)); - dma_addr = dma_coherent_handle; ccb_tmp = (struct CommandControlBlock *)dma_coherent; for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { @@ -371,8 +368,8 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) out: dma_free_coherent(&acb->pdev->dev, - ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20, - acb->dma_coherent, acb->dma_coherent_handle); + (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 + + sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle); return -ENOMEM; } @@ -509,6 +506,7 @@ static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN , reg->iop2drv_doorbell_reg); + writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg); return 0x00; } msleep(10); @@ -748,6 +746,7 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t fla , ccb->startdone , atomic_read(&acb->ccboutstandingcount)); } + else arcmsr_report_ccb_state(acb, ccb, flag_ccb); } @@ -886,7 +885,7 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \ } } -static void arcmsr_build_ccb(struct AdapterControlBlock *acb, +static int arcmsr_build_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd) { struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; @@ -906,6 +905,8 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb, memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len); nseg = scsi_dma_map(pcmd); + if (nseg > ARCMSR_MAX_SG_ENTRIES) + return FAILED; BUG_ON(nseg < 0); if (nseg) { @@ -946,6 +947,7 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb, arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE; ccb->ccb_flags |= CCB_FLAG_WRITE; } + return SUCCESS; } static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) @@ -1036,18 +1038,22 @@ static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { iounmap(acb->pmuA); + dma_free_coherent(&acb->pdev->dev, + ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, + acb->dma_coherent, + acb->dma_coherent_handle); break; } case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; iounmap(reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL); iounmap(reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER); + dma_free_coherent(&acb->pdev->dev, + (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 + + sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle); } } - dma_free_coherent(&acb->pdev->dev, - ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, - acb->dma_coherent, - acb->dma_coherent_handle); + } void arcmsr_iop_message_read(struct AdapterControlBlock *acb) @@ -1273,7 +1279,9 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) return 1; writel(~outbound_doorbell, reg->iop2drv_doorbell_reg); - + /*in case the last action of doorbell interrupt clearance is cached, this action can push HW to write down the clear bit*/ + readl(reg->iop2drv_doorbell_reg); + writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg); if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { arcmsr_iop2drv_data_wrote_handle(acb); } @@ -1380,12 +1388,13 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \ case ARCMSR_MESSAGE_READ_RQBUFFER: { unsigned long *ver_addr; - dma_addr_t buf_handle; uint8_t *pQbuffer, *ptmpQbuffer; int32_t allxfer_len = 0; + void *tmp; - ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); - if (!ver_addr) { + tmp = kmalloc(1032, GFP_KERNEL|GFP_DMA); + ver_addr = (unsigned long *)tmp; + if (!tmp) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } @@ -1421,18 +1430,19 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \ memcpy(pcmdmessagefld->messagedatabuffer, (uint8_t *)ver_addr, allxfer_len); pcmdmessagefld->cmdmessage.Length = allxfer_len; pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; - pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); + kfree(tmp); } break; case ARCMSR_MESSAGE_WRITE_WQBUFFER: { unsigned long *ver_addr; - dma_addr_t buf_handle; int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; uint8_t *pQbuffer, *ptmpuserbuffer; + void *tmp; - ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); - if (!ver_addr) { + tmp = kmalloc(1032, GFP_KERNEL|GFP_DMA); + ver_addr = (unsigned long *)tmp; + if (!tmp) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } @@ -1482,7 +1492,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \ retvalue = ARCMSR_MESSAGE_FAIL; } } - pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); + kfree(tmp); } break; @@ -1682,8 +1692,11 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd, ccb = arcmsr_get_freeccb(acb); if (!ccb) return SCSI_MLQUEUE_HOST_BUSY; - - arcmsr_build_ccb(acb, ccb, cmd); + if ( arcmsr_build_ccb( acb, ccb, cmd ) == FAILED ) { + cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1); + cmd->scsi_done(cmd); + return 0; + } arcmsr_post_ccb(acb, ccb); return 0; } @@ -1844,7 +1857,7 @@ static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, } } -static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, \ +static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) { struct MessageUnit_B *reg = acb->pmuB; @@ -1878,7 +1891,7 @@ static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, \ (acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ poll_ccb_done = (ccb == poll_ccb) ? 1:0; if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { - if (ccb->startdone == ARCMSR_CCB_ABORTED) { + if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { printk(KERN_NOTICE "arcmsr%d: \ scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n" ,acb->host->host_no @@ -1901,7 +1914,7 @@ static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, \ } /*drain reply FIFO*/ } -static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, \ +static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) { switch (acb->adapter_type) { @@ -2026,6 +2039,7 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) do { firmware_state = readl(reg->iop2drv_doorbell_reg); } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0); + writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg); } break; } @@ -2090,19 +2104,39 @@ static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb) } } +static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: + return; + case ACB_ADAPTER_TYPE_B: + { + struct MessageUnit_B *reg = acb->pmuB; + writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell_reg); + if(arcmsr_hbb_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT"); + return; + } + } + break; + } + return; +} + static void arcmsr_iop_init(struct AdapterControlBlock *acb) { uint32_t intmask_org; - arcmsr_wait_firmware_ready(acb); - arcmsr_iop_confirm(acb); /* disable all outbound interrupt */ intmask_org = arcmsr_disable_outbound_ints(acb); + arcmsr_wait_firmware_ready(acb); + arcmsr_iop_confirm(acb); arcmsr_get_firmware_spec(acb); /*start background rebuild*/ arcmsr_start_adapter_bgrb(acb); /* empty doorbell Qbuffer if door bell ringed */ arcmsr_clear_doorbell_queue_buffer(acb); + arcmsr_enable_eoi_mode(acb); /* enable outbound Post Queue,outbound doorbell Interrupt */ arcmsr_enable_outbound_ints(acb, intmask_org); acb->acb_flags |= ACB_F_IOP_INITED; @@ -2275,6 +2309,7 @@ static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev) arcmsr_start_adapter_bgrb(acb); /* empty doorbell Qbuffer if door bell ringed */ arcmsr_clear_doorbell_queue_buffer(acb); + arcmsr_enable_eoi_mode(acb); /* enable outbound Post Queue,outbound doorbell Interrupt */ arcmsr_enable_outbound_ints(acb, intmask_org); acb->acb_flags |= ACB_F_IOP_INITED; diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index eceacf6d49ea..3bedf2466bd1 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -1790,7 +1790,7 @@ int acornscsi_starttransfer(AS_Host *host) return 0; } - residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred; + residual = scsi_bufflen(host->SCpnt) - host->scsi.SCp.scsi_xferred; sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer); sbic_arm_writenext(host->scsi.io_port, residual >> 16); @@ -2270,7 +2270,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4b: /* -> PHASE_STATUSIN */ case 0x8b: /* -> PHASE_STATUSIN */ /* DATA IN -> STATUS */ - host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - + host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_readstatusbyte(host); @@ -2281,7 +2281,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4e: /* -> PHASE_MSGOUT */ case 0x8e: /* -> PHASE_MSGOUT */ /* DATA IN -> MESSAGE OUT */ - host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - + host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_sendmessage(host); @@ -2291,7 +2291,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4f: /* message in */ case 0x8f: /* message in */ /* DATA IN -> MESSAGE IN */ - host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - + host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ @@ -2319,7 +2319,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4b: /* -> PHASE_STATUSIN */ case 0x8b: /* -> PHASE_STATUSIN */ /* DATA OUT -> STATUS */ - host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - + host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_dma_adjust(host); @@ -2331,7 +2331,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4e: /* -> PHASE_MSGOUT */ case 0x8e: /* -> PHASE_MSGOUT */ /* DATA OUT -> MESSAGE OUT */ - host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - + host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_dma_adjust(host); @@ -2342,7 +2342,7 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) case 0x4f: /* message in */ case 0x8f: /* message in */ /* DATA OUT -> MESSAGE IN */ - host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - + host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - acornscsi_sbic_xfcount(host); acornscsi_dma_stop(host); acornscsi_dma_adjust(host); diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h index bb6550e31926..138a521ba1a8 100644 --- a/drivers/scsi/arm/scsi.h +++ b/drivers/scsi/arm/scsi.h @@ -18,17 +18,32 @@ * The scatter-gather list handling. This contains all * the yucky stuff that needs to be fixed properly. */ + +/* + * copy_SCp_to_sg() Assumes contiguous allocation at @sg of at-most @max + * entries of uninitialized memory. SCp is from scsi-ml and has a valid + * (possibly chained) sg-list + */ static inline int copy_SCp_to_sg(struct scatterlist *sg, struct scsi_pointer *SCp, int max) { int bufs = SCp->buffers_residual; + /* FIXME: It should be easy for drivers to loop on copy_SCp_to_sg(). + * and to remove this BUG_ON. Use min() in-its-place + */ BUG_ON(bufs + 1 > max); sg_set_buf(sg, SCp->ptr, SCp->this_residual); - if (bufs) - memcpy(sg + 1, SCp->buffer + 1, - sizeof(struct scatterlist) * bufs); + if (bufs) { + struct scatterlist *src_sg; + unsigned i; + + for_each_sg(sg_next(SCp->buffer), src_sg, bufs, i) + *(++sg) = *src_sg; + sg_mark_end(sg); + } + return bufs + 1; } @@ -36,7 +51,7 @@ static inline int next_SCp(struct scsi_pointer *SCp) { int ret = SCp->buffers_residual; if (ret) { - SCp->buffer++; + SCp->buffer = sg_next(SCp->buffer); SCp->buffers_residual--; SCp->ptr = sg_virt(SCp->buffer); SCp->this_residual = SCp->buffer->length; @@ -68,46 +83,46 @@ static inline void init_SCp(struct scsi_cmnd *SCpnt) { memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer)); - if (SCpnt->use_sg) { + if (scsi_bufflen(SCpnt)) { unsigned long len = 0; - int buf; - SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; - SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + SCpnt->SCp.buffer = scsi_sglist(SCpnt); + SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1; SCpnt->SCp.ptr = sg_virt(SCpnt->SCp.buffer); SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - SCpnt->SCp.phase = SCpnt->request_bufflen; + SCpnt->SCp.phase = scsi_bufflen(SCpnt); #ifdef BELT_AND_BRACES - /* - * Calculate correct buffer length. Some commands - * come in with the wrong request_bufflen. - */ - for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++) - len += SCpnt->SCp.buffer[buf].length; - - if (SCpnt->request_bufflen != len) - printk(KERN_WARNING "scsi%d.%c: bad request buffer " - "length %d, should be %ld\n", SCpnt->device->host->host_no, - '0' + SCpnt->device->id, SCpnt->request_bufflen, len); - SCpnt->request_bufflen = len; + { /* + * Calculate correct buffer length. Some commands + * come in with the wrong scsi_bufflen. + */ + struct scatterlist *sg; + unsigned i, sg_count = scsi_sg_count(SCpnt); + + scsi_for_each_sg(SCpnt, sg, sg_count, i) + len += sg->length; + + if (scsi_bufflen(SCpnt) != len) { + printk(KERN_WARNING + "scsi%d.%c: bad request buffer " + "length %d, should be %ld\n", + SCpnt->device->host->host_no, + '0' + SCpnt->device->id, + scsi_bufflen(SCpnt), len); + /* + * FIXME: Totaly naive fixup. We should abort + * with error + */ + SCpnt->SCp.phase = + min_t(unsigned long, len, + scsi_bufflen(SCpnt)); + } + } #endif } else { - SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer; - SCpnt->SCp.this_residual = SCpnt->request_bufflen; - SCpnt->SCp.phase = SCpnt->request_bufflen; - } - - /* - * If the upper SCSI layers pass a buffer, but zero length, - * we aren't interested in the buffer pointer. - */ - if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.ptr) { -#if 0 //def BELT_AND_BRACES - printk(KERN_WARNING "scsi%d.%c: zero length buffer passed for " - "command ", SCpnt->host->host_no, '0' + SCpnt->target); - __scsi_print_command(SCpnt->cmnd); -#endif SCpnt->SCp.ptr = NULL; + SCpnt->SCp.this_residual = 0; + SCpnt->SCp.phase = 0; } } diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c deleted file mode 100644 index 23f7c24ab809..000000000000 --- a/drivers/scsi/blz1230.c +++ /dev/null @@ -1,353 +0,0 @@ -/* blz1230.c: Driver for Blizzard 1230 SCSI IV Controller. - * - * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) - * - * This driver is based on the CyberStorm driver, hence the occasional - * reference to CyberStorm. - */ - -/* TODO: - * - * 1) Figure out how to make a cleaner merge with the sparc driver with regard - * to the caches and the Sparc MMU mapping. - * 2) Make as few routines required outside the generic driver. A lot of the - * routines in this file used to be inline! - */ - -#include <linux/module.h> - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/blkdev.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/interrupt.h> - -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "NCR53C9x.h" - -#include <linux/zorro.h> -#include <asm/irq.h> -#include <asm/amigaints.h> -#include <asm/amigahw.h> - -#include <asm/pgtable.h> - -#define MKIV 1 - -/* The controller registers can be found in the Z2 config area at these - * offsets: - */ -#define BLZ1230_ESP_ADDR 0x8000 -#define BLZ1230_DMA_ADDR 0x10000 -#define BLZ1230II_ESP_ADDR 0x10000 -#define BLZ1230II_DMA_ADDR 0x10021 - - -/* The Blizzard 1230 DMA interface - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Only two things can be programmed in the Blizzard DMA: - * 1) The data direction is controlled by the status of bit 31 (1 = write) - * 2) The source/dest address (word aligned, shifted one right) in bits 30-0 - * - * Program DMA by first latching the highest byte of the address/direction - * (i.e. bits 31-24 of the long word constructed as described in steps 1+2 - * above). Then write each byte of the address/direction (starting with the - * top byte, working down) to the DMA address register. - * - * Figure out interrupt status by reading the ESP status byte. - */ -struct blz1230_dma_registers { - volatile unsigned char dma_addr; /* DMA address [0x0000] */ - unsigned char dmapad2[0x7fff]; - volatile unsigned char dma_latch; /* DMA latch [0x8000] */ -}; - -struct blz1230II_dma_registers { - volatile unsigned char dma_addr; /* DMA address [0x0000] */ - unsigned char dmapad2[0xf]; - volatile unsigned char dma_latch; /* DMA latch [0x0010] */ -}; - -#define BLZ1230_DMA_WRITE 0x80000000 - -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_dump_state(struct NCR_ESP *esp); -static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); -static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length); -static void dma_ints_off(struct NCR_ESP *esp); -static void dma_ints_on(struct NCR_ESP *esp); -static int dma_irq_p(struct NCR_ESP *esp); -static int dma_ports_p(struct NCR_ESP *esp); -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); - -static volatile unsigned char cmd_buffer[16]; - /* This is where all commands are put - * before they are transferred to the ESP chip - * via PIO. - */ - -/***************************************************************** Detection */ -int __init blz1230_esp_detect(struct scsi_host_template *tpnt) -{ - struct NCR_ESP *esp; - struct zorro_dev *z = NULL; - unsigned long address; - struct ESP_regs *eregs; - unsigned long board; - -#if MKIV -#define REAL_BLZ1230_ID ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260 -#define REAL_BLZ1230_ESP_ADDR BLZ1230_ESP_ADDR -#define REAL_BLZ1230_DMA_ADDR BLZ1230_DMA_ADDR -#else -#define REAL_BLZ1230_ID ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060 -#define REAL_BLZ1230_ESP_ADDR BLZ1230II_ESP_ADDR -#define REAL_BLZ1230_DMA_ADDR BLZ1230II_DMA_ADDR -#endif - - if ((z = zorro_find_device(REAL_BLZ1230_ID, z))) { - board = z->resource.start; - if (request_mem_region(board+REAL_BLZ1230_ESP_ADDR, - sizeof(struct ESP_regs), "NCR53C9x")) { - /* Do some magic to figure out if the blizzard is - * equipped with a SCSI controller - */ - address = ZTWO_VADDR(board); - eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR); - esp = esp_allocate(tpnt, (void *)board + REAL_BLZ1230_ESP_ADDR, - 0); - - esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); - udelay(5); - if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)) - goto err_out; - - /* Do command transfer with programmed I/O */ - esp->do_pio_cmds = 1; - - /* Required functions */ - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = &dma_init_read; - esp->dma_init_write = &dma_init_write; - esp->dma_ints_off = &dma_ints_off; - esp->dma_ints_on = &dma_ints_on; - esp->dma_irq_p = &dma_irq_p; - esp->dma_ports_p = &dma_ports_p; - esp->dma_setup = &dma_setup; - - /* Optional functions */ - esp->dma_barrier = 0; - esp->dma_drain = 0; - esp->dma_invalidate = 0; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = 0; - esp->dma_led_on = 0; - esp->dma_led_off = 0; - esp->dma_poll = 0; - esp->dma_reset = 0; - - /* SCSI chip speed */ - esp->cfreq = 40000000; - - /* The DMA registers on the Blizzard are mapped - * relative to the device (i.e. in the same Zorro - * I/O block). - */ - esp->dregs = (void *)(address + REAL_BLZ1230_DMA_ADDR); - - /* ESP register base */ - esp->eregs = eregs; - - /* Set the command buffer */ - esp->esp_command = cmd_buffer; - esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); - - esp->irq = IRQ_AMIGA_PORTS; - esp->slot = board+REAL_BLZ1230_ESP_ADDR; - if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, - "Blizzard 1230 SCSI IV", esp->ehost)) - goto err_out; - - /* Figure out our scsi ID on the bus */ - esp->scsi_id = 7; - - /* We don't have a differential SCSI-bus. */ - esp->diff = 0; - - esp_initialize(esp); - - printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); - esps_running = esps_in_use; - return esps_in_use; - } - } - return 0; - - err_out: - scsi_unregister(esp->ehost); - esp_deallocate(esp); - release_mem_region(board+REAL_BLZ1230_ESP_ADDR, - sizeof(struct ESP_regs)); - return 0; -} - -/************************************************************* DMA Functions */ -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) -{ - /* Since the Blizzard DMA is fully dedicated to the ESP chip, - * the number of bytes sent (to the ESP chip) equals the number - * of bytes in the FIFO - there is no buffering in the DMA controller. - * XXXX Do I read this right? It is from host to ESP, right? - */ - return fifo_count; -} - -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - /* I don't think there's any limit on the Blizzard DMA. So we use what - * the ESP chip can handle (24 bit). - */ - unsigned long sz = sp->SCp.this_residual; - if(sz > 0x1000000) - sz = 0x1000000; - return sz; -} - -static void dma_dump_state(struct NCR_ESP *esp) -{ - ESPLOG(("intreq:<%04x>, intena:<%04x>\n", - amiga_custom.intreqr, amiga_custom.intenar)); -} - -void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) -{ -#if MKIV - struct blz1230_dma_registers *dregs = - (struct blz1230_dma_registers *) (esp->dregs); -#else - struct blz1230II_dma_registers *dregs = - (struct blz1230II_dma_registers *) (esp->dregs); -#endif - - cache_clear(addr, length); - - addr >>= 1; - addr &= ~(BLZ1230_DMA_WRITE); - - /* First set latch */ - dregs->dma_latch = (addr >> 24) & 0xff; - - /* Then pump the address to the DMA address register */ -#if MKIV - dregs->dma_addr = (addr >> 24) & 0xff; -#endif - dregs->dma_addr = (addr >> 16) & 0xff; - dregs->dma_addr = (addr >> 8) & 0xff; - dregs->dma_addr = (addr ) & 0xff; -} - -void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) -{ -#if MKIV - struct blz1230_dma_registers *dregs = - (struct blz1230_dma_registers *) (esp->dregs); -#else - struct blz1230II_dma_registers *dregs = - (struct blz1230II_dma_registers *) (esp->dregs); -#endif - - cache_push(addr, length); - - addr >>= 1; - addr |= BLZ1230_DMA_WRITE; - - /* First set latch */ - dregs->dma_latch = (addr >> 24) & 0xff; - - /* Then pump the address to the DMA address register */ -#if MKIV - dregs->dma_addr = (addr >> 24) & 0xff; -#endif - dregs->dma_addr = (addr >> 16) & 0xff; - dregs->dma_addr = (addr >> 8) & 0xff; - dregs->dma_addr = (addr ) & 0xff; -} - -static void dma_ints_off(struct NCR_ESP *esp) -{ - disable_irq(esp->irq); -} - -static void dma_ints_on(struct NCR_ESP *esp) -{ - enable_irq(esp->irq); -} - -static int dma_irq_p(struct NCR_ESP *esp) -{ - return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR); -} - -static int dma_ports_p(struct NCR_ESP *esp) -{ - return ((amiga_custom.intenar) & IF_PORTS); -} - -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) -{ - /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" - * so when (write) is true, it actually means READ! - */ - if(write){ - dma_init_read(esp, addr, count); - } else { - dma_init_write(esp, addr, count); - } -} - -#define HOSTS_C - -int blz1230_esp_release(struct Scsi_Host *instance) -{ -#ifdef MODULE - unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; - esp_deallocate((struct NCR_ESP *)instance->hostdata); - esp_release(); - release_mem_region(address, sizeof(struct ESP_regs)); - free_irq(IRQ_AMIGA_PORTS, esp_intr); -#endif - return 1; -} - - -static struct scsi_host_template driver_template = { - .proc_name = "esp-blz1230", - .proc_info = esp_proc_info, - .name = "Blizzard1230 SCSI IV", - .detect = blz1230_esp_detect, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .release = blz1230_esp_release, - .queuecommand = esp_queue, - .eh_abort_handler = esp_abort, - .eh_bus_reset_handler = esp_reset, - .can_queue = 7, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING -}; - - -#include "scsi_module.c" - -MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c deleted file mode 100644 index b6203ec00961..000000000000 --- a/drivers/scsi/blz2060.c +++ /dev/null @@ -1,306 +0,0 @@ -/* blz2060.c: Driver for Blizzard 2060 SCSI Controller. - * - * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) - * - * This driver is based on the CyberStorm driver, hence the occasional - * reference to CyberStorm. - */ - -/* TODO: - * - * 1) Figure out how to make a cleaner merge with the sparc driver with regard - * to the caches and the Sparc MMU mapping. - * 2) Make as few routines required outside the generic driver. A lot of the - * routines in this file used to be inline! - */ - -#include <linux/module.h> - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/blkdev.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/interrupt.h> - -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "NCR53C9x.h" - -#include <linux/zorro.h> -#include <asm/irq.h> -#include <asm/amigaints.h> -#include <asm/amigahw.h> - -#include <asm/pgtable.h> - -/* The controller registers can be found in the Z2 config area at these - * offsets: - */ -#define BLZ2060_ESP_ADDR 0x1ff00 -#define BLZ2060_DMA_ADDR 0x1ffe0 - - -/* The Blizzard 2060 DMA interface - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Only two things can be programmed in the Blizzard DMA: - * 1) The data direction is controlled by the status of bit 31 (1 = write) - * 2) The source/dest address (word aligned, shifted one right) in bits 30-0 - * - * Figure out interrupt status by reading the ESP status byte. - */ -struct blz2060_dma_registers { - volatile unsigned char dma_led_ctrl; /* DMA led control [0x000] */ - unsigned char dmapad1[0x0f]; - volatile unsigned char dma_addr0; /* DMA address (MSB) [0x010] */ - unsigned char dmapad2[0x03]; - volatile unsigned char dma_addr1; /* DMA address [0x014] */ - unsigned char dmapad3[0x03]; - volatile unsigned char dma_addr2; /* DMA address [0x018] */ - unsigned char dmapad4[0x03]; - volatile unsigned char dma_addr3; /* DMA address (LSB) [0x01c] */ -}; - -#define BLZ2060_DMA_WRITE 0x80000000 - -/* DMA control bits */ -#define BLZ2060_DMA_LED 0x02 /* HD led control 1 = off */ - -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_dump_state(struct NCR_ESP *esp); -static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); -static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length); -static void dma_ints_off(struct NCR_ESP *esp); -static void dma_ints_on(struct NCR_ESP *esp); -static int dma_irq_p(struct NCR_ESP *esp); -static void dma_led_off(struct NCR_ESP *esp); -static void dma_led_on(struct NCR_ESP *esp); -static int dma_ports_p(struct NCR_ESP *esp); -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); - -static volatile unsigned char cmd_buffer[16]; - /* This is where all commands are put - * before they are transferred to the ESP chip - * via PIO. - */ - -/***************************************************************** Detection */ -int __init blz2060_esp_detect(struct scsi_host_template *tpnt) -{ - struct NCR_ESP *esp; - struct zorro_dev *z = NULL; - unsigned long address; - - if ((z = zorro_find_device(ZORRO_PROD_PHASE5_BLIZZARD_2060, z))) { - unsigned long board = z->resource.start; - if (request_mem_region(board+BLZ2060_ESP_ADDR, - sizeof(struct ESP_regs), "NCR53C9x")) { - esp = esp_allocate(tpnt, (void *)board + BLZ2060_ESP_ADDR, 0); - - /* Do command transfer with programmed I/O */ - esp->do_pio_cmds = 1; - - /* Required functions */ - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = &dma_init_read; - esp->dma_init_write = &dma_init_write; - esp->dma_ints_off = &dma_ints_off; - esp->dma_ints_on = &dma_ints_on; - esp->dma_irq_p = &dma_irq_p; - esp->dma_ports_p = &dma_ports_p; - esp->dma_setup = &dma_setup; - - /* Optional functions */ - esp->dma_barrier = 0; - esp->dma_drain = 0; - esp->dma_invalidate = 0; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = 0; - esp->dma_led_on = &dma_led_on; - esp->dma_led_off = &dma_led_off; - esp->dma_poll = 0; - esp->dma_reset = 0; - - /* SCSI chip speed */ - esp->cfreq = 40000000; - - /* The DMA registers on the Blizzard are mapped - * relative to the device (i.e. in the same Zorro - * I/O block). - */ - address = (unsigned long)ZTWO_VADDR(board); - esp->dregs = (void *)(address + BLZ2060_DMA_ADDR); - - /* ESP register base */ - esp->eregs = (struct ESP_regs *)(address + BLZ2060_ESP_ADDR); - - /* Set the command buffer */ - esp->esp_command = cmd_buffer; - esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); - - esp->irq = IRQ_AMIGA_PORTS; - request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, - "Blizzard 2060 SCSI", esp->ehost); - - /* Figure out our scsi ID on the bus */ - esp->scsi_id = 7; - - /* We don't have a differential SCSI-bus. */ - esp->diff = 0; - - esp_initialize(esp); - - printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); - esps_running = esps_in_use; - return esps_in_use; - } - } - return 0; -} - -/************************************************************* DMA Functions */ -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) -{ - /* Since the Blizzard DMA is fully dedicated to the ESP chip, - * the number of bytes sent (to the ESP chip) equals the number - * of bytes in the FIFO - there is no buffering in the DMA controller. - * XXXX Do I read this right? It is from host to ESP, right? - */ - return fifo_count; -} - -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - /* I don't think there's any limit on the Blizzard DMA. So we use what - * the ESP chip can handle (24 bit). - */ - unsigned long sz = sp->SCp.this_residual; - if(sz > 0x1000000) - sz = 0x1000000; - return sz; -} - -static void dma_dump_state(struct NCR_ESP *esp) -{ - ESPLOG(("intreq:<%04x>, intena:<%04x>\n", - amiga_custom.intreqr, amiga_custom.intenar)); -} - -static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) -{ - struct blz2060_dma_registers *dregs = - (struct blz2060_dma_registers *) (esp->dregs); - - cache_clear(addr, length); - - addr >>= 1; - addr &= ~(BLZ2060_DMA_WRITE); - dregs->dma_addr3 = (addr ) & 0xff; - dregs->dma_addr2 = (addr >> 8) & 0xff; - dregs->dma_addr1 = (addr >> 16) & 0xff; - dregs->dma_addr0 = (addr >> 24) & 0xff; -} - -static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) -{ - struct blz2060_dma_registers *dregs = - (struct blz2060_dma_registers *) (esp->dregs); - - cache_push(addr, length); - - addr >>= 1; - addr |= BLZ2060_DMA_WRITE; - dregs->dma_addr3 = (addr ) & 0xff; - dregs->dma_addr2 = (addr >> 8) & 0xff; - dregs->dma_addr1 = (addr >> 16) & 0xff; - dregs->dma_addr0 = (addr >> 24) & 0xff; -} - -static void dma_ints_off(struct NCR_ESP *esp) -{ - disable_irq(esp->irq); -} - -static void dma_ints_on(struct NCR_ESP *esp) -{ - enable_irq(esp->irq); -} - -static int dma_irq_p(struct NCR_ESP *esp) -{ - return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR); -} - -static void dma_led_off(struct NCR_ESP *esp) -{ - ((struct blz2060_dma_registers *) (esp->dregs))->dma_led_ctrl = - BLZ2060_DMA_LED; -} - -static void dma_led_on(struct NCR_ESP *esp) -{ - ((struct blz2060_dma_registers *) (esp->dregs))->dma_led_ctrl = 0; -} - -static int dma_ports_p(struct NCR_ESP *esp) -{ - return ((amiga_custom.intenar) & IF_PORTS); -} - -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) -{ - /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" - * so when (write) is true, it actually means READ! - */ - if(write){ - dma_init_read(esp, addr, count); - } else { - dma_init_write(esp, addr, count); - } -} - -#define HOSTS_C - -int blz2060_esp_release(struct Scsi_Host *instance) -{ -#ifdef MODULE - unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; - - esp_deallocate((struct NCR_ESP *)instance->hostdata); - esp_release(); - release_mem_region(address, sizeof(struct ESP_regs)); - free_irq(IRQ_AMIGA_PORTS, esp_intr); -#endif - return 1; -} - - -static struct scsi_host_template driver_template = { - .proc_name = "esp-blz2060", - .proc_info = esp_proc_info, - .name = "Blizzard2060 SCSI", - .detect = blz2060_esp_detect, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .release = blz2060_esp_release, - .queuecommand = esp_queue, - .eh_abort_handler = esp_abort, - .eh_bus_reset_handler = esp_reset, - .can_queue = 7, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING -}; - - -#include "scsi_module.c" - -MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c deleted file mode 100644 index c6b98a42e89d..000000000000 --- a/drivers/scsi/cyberstorm.c +++ /dev/null @@ -1,377 +0,0 @@ -/* cyberstorm.c: Driver for CyberStorm SCSI Controller. - * - * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) - * - * The CyberStorm SCSI driver is based on David S. Miller's ESP driver - * for the Sparc computers. - * - * This work was made possible by Phase5 who willingly (and most generously) - * supported me with hardware and all the information I needed. - */ - -/* TODO: - * - * 1) Figure out how to make a cleaner merge with the sparc driver with regard - * to the caches and the Sparc MMU mapping. - * 2) Make as few routines required outside the generic driver. A lot of the - * routines in this file used to be inline! - */ - -#include <linux/module.h> - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/blkdev.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/interrupt.h> - -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "NCR53C9x.h" - -#include <linux/zorro.h> -#include <asm/irq.h> -#include <asm/amigaints.h> -#include <asm/amigahw.h> - -#include <asm/pgtable.h> - -/* The controller registers can be found in the Z2 config area at these - * offsets: - */ -#define CYBER_ESP_ADDR 0xf400 -#define CYBER_DMA_ADDR 0xf800 - - -/* The CyberStorm DMA interface */ -struct cyber_dma_registers { - volatile unsigned char dma_addr0; /* DMA address (MSB) [0x000] */ - unsigned char dmapad1[1]; - volatile unsigned char dma_addr1; /* DMA address [0x002] */ - unsigned char dmapad2[1]; - volatile unsigned char dma_addr2; /* DMA address [0x004] */ - unsigned char dmapad3[1]; - volatile unsigned char dma_addr3; /* DMA address (LSB) [0x006] */ - unsigned char dmapad4[0x3fb]; - volatile unsigned char cond_reg; /* DMA cond (ro) [0x402] */ -#define ctrl_reg cond_reg /* DMA control (wo) [0x402] */ -}; - -/* DMA control bits */ -#define CYBER_DMA_LED 0x80 /* HD led control 1 = on */ -#define CYBER_DMA_WRITE 0x40 /* DMA direction. 1 = write */ -#define CYBER_DMA_Z3 0x20 /* 16 (Z2) or 32 (CHIP/Z3) bit DMA transfer */ - -/* DMA status bits */ -#define CYBER_DMA_HNDL_INTR 0x80 /* DMA IRQ pending? */ - -/* The bits below appears to be Phase5 Debug bits only; they were not - * described by Phase5 so using them may seem a bit stupid... - */ -#define CYBER_HOST_ID 0x02 /* If set, host ID should be 7, otherwise - * it should be 6. - */ -#define CYBER_SLOW_CABLE 0x08 /* If *not* set, assume SLOW_CABLE */ - -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_dump_state(struct NCR_ESP *esp); -static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); -static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length); -static void dma_ints_off(struct NCR_ESP *esp); -static void dma_ints_on(struct NCR_ESP *esp); -static int dma_irq_p(struct NCR_ESP *esp); -static void dma_led_off(struct NCR_ESP *esp); -static void dma_led_on(struct NCR_ESP *esp); -static int dma_ports_p(struct NCR_ESP *esp); -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); - -static unsigned char ctrl_data = 0; /* Keep backup of the stuff written - * to ctrl_reg. Always write a copy - * to this register when writing to - * the hardware register! - */ - -static volatile unsigned char cmd_buffer[16]; - /* This is where all commands are put - * before they are transferred to the ESP chip - * via PIO. - */ - -/***************************************************************** Detection */ -int __init cyber_esp_detect(struct scsi_host_template *tpnt) -{ - struct NCR_ESP *esp; - struct zorro_dev *z = NULL; - unsigned long address; - - while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { - unsigned long board = z->resource.start; - if ((z->id == ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM || - z->id == ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060) && - request_mem_region(board+CYBER_ESP_ADDR, - sizeof(struct ESP_regs), "NCR53C9x")) { - /* Figure out if this is a CyberStorm or really a - * Fastlane/Blizzard Mk II by looking at the board size. - * CyberStorm maps 64kB - * (ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM does anyway) - */ - if(z->resource.end-board != 0xffff) { - release_mem_region(board+CYBER_ESP_ADDR, - sizeof(struct ESP_regs)); - return 0; - } - esp = esp_allocate(tpnt, (void *)board + CYBER_ESP_ADDR, 0); - - /* Do command transfer with programmed I/O */ - esp->do_pio_cmds = 1; - - /* Required functions */ - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = &dma_init_read; - esp->dma_init_write = &dma_init_write; - esp->dma_ints_off = &dma_ints_off; - esp->dma_ints_on = &dma_ints_on; - esp->dma_irq_p = &dma_irq_p; - esp->dma_ports_p = &dma_ports_p; - esp->dma_setup = &dma_setup; - - /* Optional functions */ - esp->dma_barrier = 0; - esp->dma_drain = 0; - esp->dma_invalidate = 0; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = 0; - esp->dma_led_on = &dma_led_on; - esp->dma_led_off = &dma_led_off; - esp->dma_poll = 0; - esp->dma_reset = 0; - - /* SCSI chip speed */ - esp->cfreq = 40000000; - - /* The DMA registers on the CyberStorm are mapped - * relative to the device (i.e. in the same Zorro - * I/O block). - */ - address = (unsigned long)ZTWO_VADDR(board); - esp->dregs = (void *)(address + CYBER_DMA_ADDR); - - /* ESP register base */ - esp->eregs = (struct ESP_regs *)(address + CYBER_ESP_ADDR); - - /* Set the command buffer */ - esp->esp_command = cmd_buffer; - esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); - - esp->irq = IRQ_AMIGA_PORTS; - request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, - "CyberStorm SCSI", esp->ehost); - /* Figure out our scsi ID on the bus */ - /* The DMA cond flag contains a hardcoded jumper bit - * which can be used to select host number 6 or 7. - * However, even though it may change, we use a hardcoded - * value of 7. - */ - esp->scsi_id = 7; - - /* We don't have a differential SCSI-bus. */ - esp->diff = 0; - - esp_initialize(esp); - - printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); - esps_running = esps_in_use; - return esps_in_use; - } - } - return 0; -} - -/************************************************************* DMA Functions */ -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) -{ - /* Since the CyberStorm DMA is fully dedicated to the ESP chip, - * the number of bytes sent (to the ESP chip) equals the number - * of bytes in the FIFO - there is no buffering in the DMA controller. - * XXXX Do I read this right? It is from host to ESP, right? - */ - return fifo_count; -} - -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - /* I don't think there's any limit on the CyberDMA. So we use what - * the ESP chip can handle (24 bit). - */ - unsigned long sz = sp->SCp.this_residual; - if(sz > 0x1000000) - sz = 0x1000000; - return sz; -} - -static void dma_dump_state(struct NCR_ESP *esp) -{ - ESPLOG(("esp%d: dma -- cond_reg<%02x>\n", - esp->esp_id, ((struct cyber_dma_registers *) - (esp->dregs))->cond_reg)); - ESPLOG(("intreq:<%04x>, intena:<%04x>\n", - amiga_custom.intreqr, amiga_custom.intenar)); -} - -static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) -{ - struct cyber_dma_registers *dregs = - (struct cyber_dma_registers *) esp->dregs; - - cache_clear(addr, length); - - addr &= ~(1); - dregs->dma_addr0 = (addr >> 24) & 0xff; - dregs->dma_addr1 = (addr >> 16) & 0xff; - dregs->dma_addr2 = (addr >> 8) & 0xff; - dregs->dma_addr3 = (addr ) & 0xff; - ctrl_data &= ~(CYBER_DMA_WRITE); - - /* Check if physical address is outside Z2 space and of - * block length/block aligned in memory. If this is the - * case, enable 32 bit transfer. In all other cases, fall back - * to 16 bit transfer. - * Obviously 32 bit transfer should be enabled if the DMA address - * and length are 32 bit aligned. However, this leads to some - * strange behavior. Even 64 bit aligned addr/length fails. - * Until I've found a reason for this, 32 bit transfer is only - * used for full-block transfers (1kB). - * -jskov - */ -#if 0 - if((addr & 0x3fc) || length & 0x3ff || ((addr > 0x200000) && - (addr < 0xff0000))) - ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */ - else - ctrl_data |= CYBER_DMA_Z3; /* CHIP/Z3, do 32 bit DMA */ -#else - ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */ -#endif - dregs->ctrl_reg = ctrl_data; -} - -static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) -{ - struct cyber_dma_registers *dregs = - (struct cyber_dma_registers *) esp->dregs; - - cache_push(addr, length); - - addr |= 1; - dregs->dma_addr0 = (addr >> 24) & 0xff; - dregs->dma_addr1 = (addr >> 16) & 0xff; - dregs->dma_addr2 = (addr >> 8) & 0xff; - dregs->dma_addr3 = (addr ) & 0xff; - ctrl_data |= CYBER_DMA_WRITE; - - /* See comment above */ -#if 0 - if((addr & 0x3fc) || length & 0x3ff || ((addr > 0x200000) && - (addr < 0xff0000))) - ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */ - else - ctrl_data |= CYBER_DMA_Z3; /* CHIP/Z3, do 32 bit DMA */ -#else - ctrl_data &= ~(CYBER_DMA_Z3); /* Z2, do 16 bit DMA */ -#endif - dregs->ctrl_reg = ctrl_data; -} - -static void dma_ints_off(struct NCR_ESP *esp) -{ - disable_irq(esp->irq); -} - -static void dma_ints_on(struct NCR_ESP *esp) -{ - enable_irq(esp->irq); -} - -static int dma_irq_p(struct NCR_ESP *esp) -{ - /* It's important to check the DMA IRQ bit in the correct way! */ - return ((esp_read(esp->eregs->esp_status) & ESP_STAT_INTR) && - ((((struct cyber_dma_registers *)(esp->dregs))->cond_reg) & - CYBER_DMA_HNDL_INTR)); -} - -static void dma_led_off(struct NCR_ESP *esp) -{ - ctrl_data &= ~CYBER_DMA_LED; - ((struct cyber_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data; -} - -static void dma_led_on(struct NCR_ESP *esp) -{ - ctrl_data |= CYBER_DMA_LED; - ((struct cyber_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data; -} - -static int dma_ports_p(struct NCR_ESP *esp) -{ - return ((amiga_custom.intenar) & IF_PORTS); -} - -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) -{ - /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" - * so when (write) is true, it actually means READ! - */ - if(write){ - dma_init_read(esp, addr, count); - } else { - dma_init_write(esp, addr, count); - } -} - -#define HOSTS_C - -int cyber_esp_release(struct Scsi_Host *instance) -{ -#ifdef MODULE - unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; - - esp_deallocate((struct NCR_ESP *)instance->hostdata); - esp_release(); - release_mem_region(address, sizeof(struct ESP_regs)); - free_irq(IRQ_AMIGA_PORTS, esp_intr); -#endif - return 1; -} - - -static struct scsi_host_template driver_template = { - .proc_name = "esp-cyberstorm", - .proc_info = esp_proc_info, - .name = "CyberStorm SCSI", - .detect = cyber_esp_detect, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .release = cyber_esp_release, - .queuecommand = esp_queue, - .eh_abort_handler = esp_abort, - .eh_bus_reset_handler = esp_reset, - .can_queue = 7, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING -}; - - -#include "scsi_module.c" - -MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c deleted file mode 100644 index e336e853e66f..000000000000 --- a/drivers/scsi/cyberstormII.c +++ /dev/null @@ -1,314 +0,0 @@ -/* cyberstormII.c: Driver for CyberStorm SCSI Mk II - * - * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) - * - * This driver is based on cyberstorm.c - */ - -/* TODO: - * - * 1) Figure out how to make a cleaner merge with the sparc driver with regard - * to the caches and the Sparc MMU mapping. - * 2) Make as few routines required outside the generic driver. A lot of the - * routines in this file used to be inline! - */ - -#include <linux/module.h> - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/blkdev.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/interrupt.h> - -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "NCR53C9x.h" - -#include <linux/zorro.h> -#include <asm/irq.h> -#include <asm/amigaints.h> -#include <asm/amigahw.h> - -#include <asm/pgtable.h> - -/* The controller registers can be found in the Z2 config area at these - * offsets: - */ -#define CYBERII_ESP_ADDR 0x1ff03 -#define CYBERII_DMA_ADDR 0x1ff43 - - -/* The CyberStorm II DMA interface */ -struct cyberII_dma_registers { - volatile unsigned char cond_reg; /* DMA cond (ro) [0x000] */ -#define ctrl_reg cond_reg /* DMA control (wo) [0x000] */ - unsigned char dmapad4[0x3f]; - volatile unsigned char dma_addr0; /* DMA address (MSB) [0x040] */ - unsigned char dmapad1[3]; - volatile unsigned char dma_addr1; /* DMA address [0x044] */ - unsigned char dmapad2[3]; - volatile unsigned char dma_addr2; /* DMA address [0x048] */ - unsigned char dmapad3[3]; - volatile unsigned char dma_addr3; /* DMA address (LSB) [0x04c] */ -}; - -/* DMA control bits */ -#define CYBERII_DMA_LED 0x02 /* HD led control 1 = on */ - -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_dump_state(struct NCR_ESP *esp); -static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); -static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length); -static void dma_ints_off(struct NCR_ESP *esp); -static void dma_ints_on(struct NCR_ESP *esp); -static int dma_irq_p(struct NCR_ESP *esp); -static void dma_led_off(struct NCR_ESP *esp); -static void dma_led_on(struct NCR_ESP *esp); -static int dma_ports_p(struct NCR_ESP *esp); -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); - -static volatile unsigned char cmd_buffer[16]; - /* This is where all commands are put - * before they are transferred to the ESP chip - * via PIO. - */ - -/***************************************************************** Detection */ -int __init cyberII_esp_detect(struct scsi_host_template *tpnt) -{ - struct NCR_ESP *esp; - struct zorro_dev *z = NULL; - unsigned long address; - struct ESP_regs *eregs; - - if ((z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERSTORM_MK_II, z))) { - unsigned long board = z->resource.start; - if (request_mem_region(board+CYBERII_ESP_ADDR, - sizeof(struct ESP_regs), "NCR53C9x")) { - /* Do some magic to figure out if the CyberStorm Mk II - * is equipped with a SCSI controller - */ - address = (unsigned long)ZTWO_VADDR(board); - eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR); - - esp = esp_allocate(tpnt, (void *)board + CYBERII_ESP_ADDR, 0); - - esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); - udelay(5); - if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)) { - esp_deallocate(esp); - scsi_unregister(esp->ehost); - release_mem_region(board+CYBERII_ESP_ADDR, - sizeof(struct ESP_regs)); - return 0; /* Bail out if address did not hold data */ - } - - /* Do command transfer with programmed I/O */ - esp->do_pio_cmds = 1; - - /* Required functions */ - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = &dma_init_read; - esp->dma_init_write = &dma_init_write; - esp->dma_ints_off = &dma_ints_off; - esp->dma_ints_on = &dma_ints_on; - esp->dma_irq_p = &dma_irq_p; - esp->dma_ports_p = &dma_ports_p; - esp->dma_setup = &dma_setup; - - /* Optional functions */ - esp->dma_barrier = 0; - esp->dma_drain = 0; - esp->dma_invalidate = 0; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = 0; - esp->dma_led_on = &dma_led_on; - esp->dma_led_off = &dma_led_off; - esp->dma_poll = 0; - esp->dma_reset = 0; - - /* SCSI chip speed */ - esp->cfreq = 40000000; - - /* The DMA registers on the CyberStorm are mapped - * relative to the device (i.e. in the same Zorro - * I/O block). - */ - esp->dregs = (void *)(address + CYBERII_DMA_ADDR); - - /* ESP register base */ - esp->eregs = eregs; - - /* Set the command buffer */ - esp->esp_command = cmd_buffer; - esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); - - esp->irq = IRQ_AMIGA_PORTS; - request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, - "CyberStorm SCSI Mk II", esp->ehost); - - /* Figure out our scsi ID on the bus */ - esp->scsi_id = 7; - - /* We don't have a differential SCSI-bus. */ - esp->diff = 0; - - esp_initialize(esp); - - printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); - esps_running = esps_in_use; - return esps_in_use; - } - } - return 0; -} - -/************************************************************* DMA Functions */ -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) -{ - /* Since the CyberStorm DMA is fully dedicated to the ESP chip, - * the number of bytes sent (to the ESP chip) equals the number - * of bytes in the FIFO - there is no buffering in the DMA controller. - * XXXX Do I read this right? It is from host to ESP, right? - */ - return fifo_count; -} - -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - /* I don't think there's any limit on the CyberDMA. So we use what - * the ESP chip can handle (24 bit). - */ - unsigned long sz = sp->SCp.this_residual; - if(sz > 0x1000000) - sz = 0x1000000; - return sz; -} - -static void dma_dump_state(struct NCR_ESP *esp) -{ - ESPLOG(("esp%d: dma -- cond_reg<%02x>\n", - esp->esp_id, ((struct cyberII_dma_registers *) - (esp->dregs))->cond_reg)); - ESPLOG(("intreq:<%04x>, intena:<%04x>\n", - amiga_custom.intreqr, amiga_custom.intenar)); -} - -static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) -{ - struct cyberII_dma_registers *dregs = - (struct cyberII_dma_registers *) esp->dregs; - - cache_clear(addr, length); - - addr &= ~(1); - dregs->dma_addr0 = (addr >> 24) & 0xff; - dregs->dma_addr1 = (addr >> 16) & 0xff; - dregs->dma_addr2 = (addr >> 8) & 0xff; - dregs->dma_addr3 = (addr ) & 0xff; -} - -static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) -{ - struct cyberII_dma_registers *dregs = - (struct cyberII_dma_registers *) esp->dregs; - - cache_push(addr, length); - - addr |= 1; - dregs->dma_addr0 = (addr >> 24) & 0xff; - dregs->dma_addr1 = (addr >> 16) & 0xff; - dregs->dma_addr2 = (addr >> 8) & 0xff; - dregs->dma_addr3 = (addr ) & 0xff; -} - -static void dma_ints_off(struct NCR_ESP *esp) -{ - disable_irq(esp->irq); -} - -static void dma_ints_on(struct NCR_ESP *esp) -{ - enable_irq(esp->irq); -} - -static int dma_irq_p(struct NCR_ESP *esp) -{ - /* It's important to check the DMA IRQ bit in the correct way! */ - return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR); -} - -static void dma_led_off(struct NCR_ESP *esp) -{ - ((struct cyberII_dma_registers *)(esp->dregs))->ctrl_reg &= ~CYBERII_DMA_LED; -} - -static void dma_led_on(struct NCR_ESP *esp) -{ - ((struct cyberII_dma_registers *)(esp->dregs))->ctrl_reg |= CYBERII_DMA_LED; -} - -static int dma_ports_p(struct NCR_ESP *esp) -{ - return ((amiga_custom.intenar) & IF_PORTS); -} - -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) -{ - /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" - * so when (write) is true, it actually means READ! - */ - if(write){ - dma_init_read(esp, addr, count); - } else { - dma_init_write(esp, addr, count); - } -} - -#define HOSTS_C - -int cyberII_esp_release(struct Scsi_Host *instance) -{ -#ifdef MODULE - unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; - - esp_deallocate((struct NCR_ESP *)instance->hostdata); - esp_release(); - release_mem_region(address, sizeof(struct ESP_regs)); - free_irq(IRQ_AMIGA_PORTS, esp_intr); -#endif - return 1; -} - - -static struct scsi_host_template driver_template = { - .proc_name = "esp-cyberstormII", - .proc_info = esp_proc_info, - .name = "CyberStorm Mk II SCSI", - .detect = cyberII_esp_detect, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .release = cyberII_esp_release, - .queuecommand = esp_queue, - .eh_abort_handler = esp_abort, - .eh_bus_reset_handler = esp_reset, - .can_queue = 7, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING -}; - - -#include "scsi_module.c" - -MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 22ef3716e786..e351db6c0077 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -4267,7 +4267,7 @@ static int __devinit adapter_sg_tables_alloc(struct AdapterCtlBlk *acb) const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN; int srb_idx = 0; unsigned i = 0; - struct SGentry *ptr; + struct SGentry *uninitialized_var(ptr); for (i = 0; i < DC395x_MAX_SRB_CNT; i++) acb->srb_array[i].segment_x = NULL; diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c deleted file mode 100644 index d42ad663ffee..000000000000 --- a/drivers/scsi/dec_esp.c +++ /dev/null @@ -1,687 +0,0 @@ -/* - * dec_esp.c: Driver for SCSI chips on IOASIC based TURBOchannel DECstations - * and TURBOchannel PMAZ-A cards - * - * TURBOchannel changes by Harald Koerfgen - * PMAZ-A support by David Airlie - * - * based on jazz_esp.c: - * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) - * - * jazz_esp is based on David S. Miller's ESP driver and cyber_esp - * - * 20000819 - Small PMAZ-AA fixes by Florian Lohoff <flo@rfc822.org> - * Be warned the PMAZ-AA works currently as a single card. - * Dont try to put multiple cards in one machine - They are - * both detected but it may crash under high load garbling your - * data. - * 20001005 - Initialization fixes for 2.4.0-test9 - * Florian Lohoff <flo@rfc822.org> - * - * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki - */ - -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/blkdev.h> -#include <linux/proc_fs.h> -#include <linux/spinlock.h> -#include <linux/stat.h> -#include <linux/tc.h> - -#include <asm/dma.h> -#include <asm/irq.h> -#include <asm/pgtable.h> -#include <asm/system.h> - -#include <asm/dec/interrupts.h> -#include <asm/dec/ioasic.h> -#include <asm/dec/ioasic_addrs.h> -#include <asm/dec/ioasic_ints.h> -#include <asm/dec/machtype.h> -#include <asm/dec/system.h> - -#define DEC_SCSI_SREG 0 -#define DEC_SCSI_DMAREG 0x40000 -#define DEC_SCSI_SRAM 0x80000 -#define DEC_SCSI_DIAG 0xC0000 - -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "NCR53C9x.h" - -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); -static void dma_drain(struct NCR_ESP *esp); -static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd *sp); -static void dma_dump_state(struct NCR_ESP *esp); -static void dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length); -static void dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length); -static void dma_ints_off(struct NCR_ESP *esp); -static void dma_ints_on(struct NCR_ESP *esp); -static int dma_irq_p(struct NCR_ESP *esp); -static int dma_ports_p(struct NCR_ESP *esp); -static void dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write); -static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp); -static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp); -static void dma_advance_sg(struct scsi_cmnd * sp); - -static void pmaz_dma_drain(struct NCR_ESP *esp); -static void pmaz_dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length); -static void pmaz_dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length); -static void pmaz_dma_ints_off(struct NCR_ESP *esp); -static void pmaz_dma_ints_on(struct NCR_ESP *esp); -static void pmaz_dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write); -static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp); - -#define TC_ESP_RAM_SIZE 0x20000 -#define ESP_TGT_DMA_SIZE ((TC_ESP_RAM_SIZE/7) & ~(sizeof(int)-1)) -#define ESP_NCMD 7 - -#define TC_ESP_DMAR_MASK 0x1ffff -#define TC_ESP_DMAR_WRITE 0x80000000 -#define TC_ESP_DMA_ADDR(x) ((unsigned)(x) & TC_ESP_DMAR_MASK) - -u32 esp_virt_buffer; -int scsi_current_length; - -volatile unsigned char cmd_buffer[16]; -volatile unsigned char pmaz_cmd_buffer[16]; - /* This is where all commands are put - * before they are trasfered to the ESP chip - * via PIO. - */ - -static irqreturn_t scsi_dma_merr_int(int, void *); -static irqreturn_t scsi_dma_err_int(int, void *); -static irqreturn_t scsi_dma_int(int, void *); - -static struct scsi_host_template dec_esp_template = { - .module = THIS_MODULE, - .name = "NCR53C94", - .info = esp_info, - .queuecommand = esp_queue, - .eh_abort_handler = esp_abort, - .eh_bus_reset_handler = esp_reset, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .proc_info = esp_proc_info, - .proc_name = "dec_esp", - .can_queue = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, -}; - -static struct NCR_ESP *dec_esp_platform; - -/***************************************************************** Detection */ -static int dec_esp_platform_probe(void) -{ - struct NCR_ESP *esp; - int err = 0; - - if (IOASIC) { - esp = esp_allocate(&dec_esp_template, NULL, 1); - - /* Do command transfer with programmed I/O */ - esp->do_pio_cmds = 1; - - /* Required functions */ - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = &dma_init_read; - esp->dma_init_write = &dma_init_write; - esp->dma_ints_off = &dma_ints_off; - esp->dma_ints_on = &dma_ints_on; - esp->dma_irq_p = &dma_irq_p; - esp->dma_ports_p = &dma_ports_p; - esp->dma_setup = &dma_setup; - - /* Optional functions */ - esp->dma_barrier = 0; - esp->dma_drain = &dma_drain; - esp->dma_invalidate = 0; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = 0; - esp->dma_poll = 0; - esp->dma_reset = 0; - esp->dma_led_off = 0; - esp->dma_led_on = 0; - - /* virtual DMA functions */ - esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; - esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; - esp->dma_mmu_release_scsi_one = 0; - esp->dma_mmu_release_scsi_sgl = 0; - esp->dma_advance_sg = &dma_advance_sg; - - - /* SCSI chip speed */ - esp->cfreq = 25000000; - - esp->dregs = 0; - - /* ESP register base */ - esp->eregs = (void *)CKSEG1ADDR(dec_kn_slot_base + - IOASIC_SCSI); - - /* Set the command buffer */ - esp->esp_command = (volatile unsigned char *) cmd_buffer; - - /* get virtual dma address for command buffer */ - esp->esp_command_dvma = virt_to_phys(cmd_buffer); - - esp->irq = dec_interrupt[DEC_IRQ_ASC]; - - esp->scsi_id = 7; - - /* Check for differential SCSI-bus */ - esp->diff = 0; - - err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, - "ncr53c94", esp->ehost); - if (err) - goto err_alloc; - err = request_irq(dec_interrupt[DEC_IRQ_ASC_MERR], - scsi_dma_merr_int, IRQF_DISABLED, - "ncr53c94 error", esp->ehost); - if (err) - goto err_irq; - err = request_irq(dec_interrupt[DEC_IRQ_ASC_ERR], - scsi_dma_err_int, IRQF_DISABLED, - "ncr53c94 overrun", esp->ehost); - if (err) - goto err_irq_merr; - err = request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], scsi_dma_int, - IRQF_DISABLED, "ncr53c94 dma", esp->ehost); - if (err) - goto err_irq_err; - - esp_initialize(esp); - - err = scsi_add_host(esp->ehost, NULL); - if (err) { - printk(KERN_ERR "ESP: Unable to register adapter\n"); - goto err_irq_dma; - } - - scsi_scan_host(esp->ehost); - - dec_esp_platform = esp; - } - - return 0; - -err_irq_dma: - free_irq(dec_interrupt[DEC_IRQ_ASC_DMA], esp->ehost); -err_irq_err: - free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], esp->ehost); -err_irq_merr: - free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], esp->ehost); -err_irq: - free_irq(esp->irq, esp->ehost); -err_alloc: - esp_deallocate(esp); - scsi_host_put(esp->ehost); - return err; -} - -static int __init dec_esp_probe(struct device *dev) -{ - struct NCR_ESP *esp; - resource_size_t start, len; - int err; - - esp = esp_allocate(&dec_esp_template, NULL, 1); - - dev_set_drvdata(dev, esp); - - start = to_tc_dev(dev)->resource.start; - len = to_tc_dev(dev)->resource.end - start + 1; - - if (!request_mem_region(start, len, dev->bus_id)) { - printk(KERN_ERR "%s: Unable to reserve MMIO resource\n", - dev->bus_id); - err = -EBUSY; - goto err_alloc; - } - - /* Store base addr into esp struct. */ - esp->slot = start; - - esp->dregs = 0; - esp->eregs = (void *)CKSEG1ADDR(start + DEC_SCSI_SREG); - esp->do_pio_cmds = 1; - - /* Set the command buffer. */ - esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer; - - /* Get virtual dma address for command buffer. */ - esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer); - - esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus); - - esp->irq = to_tc_dev(dev)->interrupt; - - /* Required functions. */ - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = &pmaz_dma_init_read; - esp->dma_init_write = &pmaz_dma_init_write; - esp->dma_ints_off = &pmaz_dma_ints_off; - esp->dma_ints_on = &pmaz_dma_ints_on; - esp->dma_irq_p = &dma_irq_p; - esp->dma_ports_p = &dma_ports_p; - esp->dma_setup = &pmaz_dma_setup; - - /* Optional functions. */ - esp->dma_barrier = 0; - esp->dma_drain = &pmaz_dma_drain; - esp->dma_invalidate = 0; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = 0; - esp->dma_poll = 0; - esp->dma_reset = 0; - esp->dma_led_off = 0; - esp->dma_led_on = 0; - - esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one; - esp->dma_mmu_get_scsi_sgl = 0; - esp->dma_mmu_release_scsi_one = 0; - esp->dma_mmu_release_scsi_sgl = 0; - esp->dma_advance_sg = 0; - - err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, "PMAZ_AA", - esp->ehost); - if (err) { - printk(KERN_ERR "%s: Unable to get IRQ %d\n", - dev->bus_id, esp->irq); - goto err_resource; - } - - esp->scsi_id = 7; - esp->diff = 0; - esp_initialize(esp); - - err = scsi_add_host(esp->ehost, dev); - if (err) { - printk(KERN_ERR "%s: Unable to register adapter\n", - dev->bus_id); - goto err_irq; - } - - scsi_scan_host(esp->ehost); - - return 0; - -err_irq: - free_irq(esp->irq, esp->ehost); - -err_resource: - release_mem_region(start, len); - -err_alloc: - esp_deallocate(esp); - scsi_host_put(esp->ehost); - return err; -} - -static void __exit dec_esp_platform_remove(void) -{ - struct NCR_ESP *esp = dec_esp_platform; - - free_irq(esp->irq, esp->ehost); - esp_deallocate(esp); - scsi_host_put(esp->ehost); - dec_esp_platform = NULL; -} - -static void __exit dec_esp_remove(struct device *dev) -{ - struct NCR_ESP *esp = dev_get_drvdata(dev); - - free_irq(esp->irq, esp->ehost); - esp_deallocate(esp); - scsi_host_put(esp->ehost); -} - - -/************************************************************* DMA Functions */ -static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id) -{ - printk("Got unexpected SCSI DMA Interrupt! < "); - printk("SCSI_DMA_MEMRDERR "); - printk(">\n"); - - return IRQ_HANDLED; -} - -static irqreturn_t scsi_dma_err_int(int irq, void *dev_id) -{ - /* empty */ - - return IRQ_HANDLED; -} - -static irqreturn_t scsi_dma_int(int irq, void *dev_id) -{ - u32 scsi_next_ptr; - - scsi_next_ptr = ioasic_read(IO_REG_SCSI_DMA_P); - - /* next page */ - scsi_next_ptr = (((scsi_next_ptr >> 3) + PAGE_SIZE) & PAGE_MASK) << 3; - ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr); - fast_iob(); - - return IRQ_HANDLED; -} - -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) -{ - return fifo_count; -} - -static void dma_drain(struct NCR_ESP *esp) -{ - u32 nw, data0, data1, scsi_data_ptr; - u16 *p; - - nw = ioasic_read(IO_REG_SCSI_SCR); - - /* - * Is there something in the dma buffers left? - */ - if (nw) { - scsi_data_ptr = ioasic_read(IO_REG_SCSI_DMA_P) >> 3; - p = phys_to_virt(scsi_data_ptr); - switch (nw) { - case 1: - data0 = ioasic_read(IO_REG_SCSI_SDR0); - p[0] = data0 & 0xffff; - break; - case 2: - data0 = ioasic_read(IO_REG_SCSI_SDR0); - p[0] = data0 & 0xffff; - p[1] = (data0 >> 16) & 0xffff; - break; - case 3: - data0 = ioasic_read(IO_REG_SCSI_SDR0); - data1 = ioasic_read(IO_REG_SCSI_SDR1); - p[0] = data0 & 0xffff; - p[1] = (data0 >> 16) & 0xffff; - p[2] = data1 & 0xffff; - break; - default: - printk("Strange: %d words in dma buffer left\n", nw); - break; - } - } -} - -static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd * sp) -{ - return sp->SCp.this_residual; -} - -static void dma_dump_state(struct NCR_ESP *esp) -{ -} - -static void dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length) -{ - u32 scsi_next_ptr, ioasic_ssr; - unsigned long flags; - - if (vaddress & 3) - panic("dec_esp.c: unable to handle partial word transfers, yet..."); - - dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length); - - spin_lock_irqsave(&ioasic_ssr_lock, flags); - - fast_mb(); - ioasic_ssr = ioasic_read(IO_REG_SSR); - - ioasic_ssr &= ~IO_SSR_SCSI_DMA_EN; - ioasic_write(IO_REG_SSR, ioasic_ssr); - - fast_wmb(); - ioasic_write(IO_REG_SCSI_SCR, 0); - ioasic_write(IO_REG_SCSI_DMA_P, vaddress << 3); - - /* prepare for next page */ - scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; - ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr); - - ioasic_ssr |= (IO_SSR_SCSI_DMA_DIR | IO_SSR_SCSI_DMA_EN); - fast_wmb(); - ioasic_write(IO_REG_SSR, ioasic_ssr); - - fast_iob(); - spin_unlock_irqrestore(&ioasic_ssr_lock, flags); -} - -static void dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length) -{ - u32 scsi_next_ptr, ioasic_ssr; - unsigned long flags; - - if (vaddress & 3) - panic("dec_esp.c: unable to handle partial word transfers, yet..."); - - dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length); - - spin_lock_irqsave(&ioasic_ssr_lock, flags); - - fast_mb(); - ioasic_ssr = ioasic_read(IO_REG_SSR); - - ioasic_ssr &= ~(IO_SSR_SCSI_DMA_DIR | IO_SSR_SCSI_DMA_EN); - ioasic_write(IO_REG_SSR, ioasic_ssr); - - fast_wmb(); - ioasic_write(IO_REG_SCSI_SCR, 0); - ioasic_write(IO_REG_SCSI_DMA_P, vaddress << 3); - - /* prepare for next page */ - scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; - ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr); - - ioasic_ssr |= IO_SSR_SCSI_DMA_EN; - fast_wmb(); - ioasic_write(IO_REG_SSR, ioasic_ssr); - - fast_iob(); - spin_unlock_irqrestore(&ioasic_ssr_lock, flags); -} - -static void dma_ints_off(struct NCR_ESP *esp) -{ - disable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]); -} - -static void dma_ints_on(struct NCR_ESP *esp) -{ - enable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]); -} - -static int dma_irq_p(struct NCR_ESP *esp) -{ - return (esp->eregs->esp_status & ESP_STAT_INTR); -} - -static int dma_ports_p(struct NCR_ESP *esp) -{ - /* - * FIXME: what's this good for? - */ - return 1; -} - -static void dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write) -{ - /* - * DMA_ST_WRITE means "move data from device to memory" - * so when (write) is true, it actually means READ! - */ - if (write) - dma_init_read(esp, addr, count); - else - dma_init_write(esp, addr, count); -} - -static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp) -{ - sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer); -} - -static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp) -{ - int sz = sp->SCp.buffers_residual; - struct scatterlist *sg = sp->SCp.buffer; - - while (sz >= 0) { - sg[sz].dma_address = page_to_phys(sg[sz].page) + sg[sz].offset; - sz--; - } - sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address); -} - -static void dma_advance_sg(struct scsi_cmnd * sp) -{ - sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address); -} - -static void pmaz_dma_drain(struct NCR_ESP *esp) -{ - memcpy(phys_to_virt(esp_virt_buffer), - (void *)CKSEG1ADDR(esp->slot + DEC_SCSI_SRAM + - ESP_TGT_DMA_SIZE), - scsi_current_length); -} - -static void pmaz_dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length) -{ - volatile u32 *dmareg = - (volatile u32 *)CKSEG1ADDR(esp->slot + DEC_SCSI_DMAREG); - - if (length > ESP_TGT_DMA_SIZE) - length = ESP_TGT_DMA_SIZE; - - *dmareg = TC_ESP_DMA_ADDR(ESP_TGT_DMA_SIZE); - - iob(); - - esp_virt_buffer = vaddress; - scsi_current_length = length; -} - -static void pmaz_dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length) -{ - volatile u32 *dmareg = - (volatile u32 *)CKSEG1ADDR(esp->slot + DEC_SCSI_DMAREG); - - memcpy((void *)CKSEG1ADDR(esp->slot + DEC_SCSI_SRAM + - ESP_TGT_DMA_SIZE), - phys_to_virt(vaddress), length); - - wmb(); - *dmareg = TC_ESP_DMAR_WRITE | TC_ESP_DMA_ADDR(ESP_TGT_DMA_SIZE); - - iob(); -} - -static void pmaz_dma_ints_off(struct NCR_ESP *esp) -{ -} - -static void pmaz_dma_ints_on(struct NCR_ESP *esp) -{ -} - -static void pmaz_dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write) -{ - /* - * DMA_ST_WRITE means "move data from device to memory" - * so when (write) is true, it actually means READ! - */ - if (write) - pmaz_dma_init_read(esp, addr, count); - else - pmaz_dma_init_write(esp, addr, count); -} - -static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp) -{ - sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer); -} - - -#ifdef CONFIG_TC -static int __init dec_esp_tc_probe(struct device *dev); -static int __exit dec_esp_tc_remove(struct device *dev); - -static const struct tc_device_id dec_esp_tc_table[] = { - { "DEC ", "PMAZ-AA " }, - { } -}; -MODULE_DEVICE_TABLE(tc, dec_esp_tc_table); - -static struct tc_driver dec_esp_tc_driver = { - .id_table = dec_esp_tc_table, - .driver = { - .name = "dec_esp", - .bus = &tc_bus_type, - .probe = dec_esp_tc_probe, - .remove = __exit_p(dec_esp_tc_remove), - }, -}; - -static int __init dec_esp_tc_probe(struct device *dev) -{ - int status = dec_esp_probe(dev); - if (!status) - get_device(dev); - return status; -} - -static int __exit dec_esp_tc_remove(struct device *dev) -{ - put_device(dev); - dec_esp_remove(dev); - return 0; -} -#endif - -static int __init dec_esp_init(void) -{ - int status; - - status = tc_register_driver(&dec_esp_tc_driver); - if (!status) - dec_esp_platform_probe(); - - if (nesps) { - pr_info("ESP: Total of %d ESP hosts found, " - "%d actually in use.\n", nesps, esps_in_use); - esps_running = esps_in_use; - } - - return status; -} - -static void __exit dec_esp_exit(void) -{ - dec_esp_platform_remove(); - tc_unregister_driver(&dec_esp_tc_driver); -} - - -module_init(dec_esp_init); -module_exit(dec_esp_exit); diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c deleted file mode 100644 index 4266a2139b5f..000000000000 --- a/drivers/scsi/fastlane.c +++ /dev/null @@ -1,421 +0,0 @@ -/* fastlane.c: Driver for Phase5's Fastlane SCSI Controller. - * - * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) - * - * This driver is based on the CyberStorm driver, hence the occasional - * reference to CyberStorm. - * - * Betatesting & crucial adjustments by - * Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz) - * - */ - -/* TODO: - * - * o According to the doc from laire, it is required to reset the DMA when - * the transfer is done. ATM we reset DMA just before every new - * dma_init_(read|write). - * - * 1) Figure out how to make a cleaner merge with the sparc driver with regard - * to the caches and the Sparc MMU mapping. - * 2) Make as few routines required outside the generic driver. A lot of the - * routines in this file used to be inline! - */ - -#include <linux/module.h> - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/blkdev.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/interrupt.h> - -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "NCR53C9x.h" - -#include <linux/zorro.h> -#include <asm/irq.h> - -#include <asm/amigaints.h> -#include <asm/amigahw.h> - -#include <asm/pgtable.h> - -/* Such day has just come... */ -#if 0 -/* Let this defined unless you really need to enable DMA IRQ one day */ -#define NODMAIRQ -#endif - -/* The controller registers can be found in the Z2 config area at these - * offsets: - */ -#define FASTLANE_ESP_ADDR 0x1000001 -#define FASTLANE_DMA_ADDR 0x1000041 - - -/* The Fastlane DMA interface */ -struct fastlane_dma_registers { - volatile unsigned char cond_reg; /* DMA status (ro) [0x0000] */ -#define ctrl_reg cond_reg /* DMA control (wo) [0x0000] */ - unsigned char dmapad1[0x3f]; - volatile unsigned char clear_strobe; /* DMA clear (wo) [0x0040] */ -}; - - -/* DMA status bits */ -#define FASTLANE_DMA_MINT 0x80 -#define FASTLANE_DMA_IACT 0x40 -#define FASTLANE_DMA_CREQ 0x20 - -/* DMA control bits */ -#define FASTLANE_DMA_FCODE 0xa0 -#define FASTLANE_DMA_MASK 0xf3 -#define FASTLANE_DMA_LED 0x10 /* HD led control 1 = on */ -#define FASTLANE_DMA_WRITE 0x08 /* 1 = write */ -#define FASTLANE_DMA_ENABLE 0x04 /* Enable DMA */ -#define FASTLANE_DMA_EDI 0x02 /* Enable DMA IRQ ? */ -#define FASTLANE_DMA_ESI 0x01 /* Enable SCSI IRQ */ - -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_dump_state(struct NCR_ESP *esp); -static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length); -static void dma_init_write(struct NCR_ESP *esp, __u32 vaddr, int length); -static void dma_ints_off(struct NCR_ESP *esp); -static void dma_ints_on(struct NCR_ESP *esp); -static int dma_irq_p(struct NCR_ESP *esp); -static void dma_irq_exit(struct NCR_ESP *esp); -static void dma_led_off(struct NCR_ESP *esp); -static void dma_led_on(struct NCR_ESP *esp); -static int dma_ports_p(struct NCR_ESP *esp); -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); - -static unsigned char ctrl_data = 0; /* Keep backup of the stuff written - * to ctrl_reg. Always write a copy - * to this register when writing to - * the hardware register! - */ - -static volatile unsigned char cmd_buffer[16]; - /* This is where all commands are put - * before they are transferred to the ESP chip - * via PIO. - */ - -static inline void dma_clear(struct NCR_ESP *esp) -{ - struct fastlane_dma_registers *dregs = - (struct fastlane_dma_registers *) (esp->dregs); - unsigned long *t; - - ctrl_data = (ctrl_data & FASTLANE_DMA_MASK); - dregs->ctrl_reg = ctrl_data; - - t = (unsigned long *)(esp->edev); - - dregs->clear_strobe = 0; - *t = 0 ; -} - -/***************************************************************** Detection */ -int __init fastlane_esp_detect(struct scsi_host_template *tpnt) -{ - struct NCR_ESP *esp; - struct zorro_dev *z = NULL; - unsigned long address; - - if ((z = zorro_find_device(ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060, z))) { - unsigned long board = z->resource.start; - if (request_mem_region(board+FASTLANE_ESP_ADDR, - sizeof(struct ESP_regs), "NCR53C9x")) { - /* Check if this is really a fastlane controller. The problem - * is that also the cyberstorm and blizzard controllers use - * this ID value. Fortunately only Fastlane maps in Z3 space - */ - if (board < 0x1000000) { - goto err_release; - } - esp = esp_allocate(tpnt, (void *)board + FASTLANE_ESP_ADDR, 0); - - /* Do command transfer with programmed I/O */ - esp->do_pio_cmds = 1; - - /* Required functions */ - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = &dma_init_read; - esp->dma_init_write = &dma_init_write; - esp->dma_ints_off = &dma_ints_off; - esp->dma_ints_on = &dma_ints_on; - esp->dma_irq_p = &dma_irq_p; - esp->dma_ports_p = &dma_ports_p; - esp->dma_setup = &dma_setup; - - /* Optional functions */ - esp->dma_barrier = 0; - esp->dma_drain = 0; - esp->dma_invalidate = 0; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = &dma_irq_exit; - esp->dma_led_on = &dma_led_on; - esp->dma_led_off = &dma_led_off; - esp->dma_poll = 0; - esp->dma_reset = 0; - - /* Initialize the portBits (enable IRQs) */ - ctrl_data = (FASTLANE_DMA_FCODE | -#ifndef NODMAIRQ - FASTLANE_DMA_EDI | -#endif - FASTLANE_DMA_ESI); - - - /* SCSI chip clock */ - esp->cfreq = 40000000; - - - /* Map the physical address space into virtual kernel space */ - address = (unsigned long) - z_ioremap(board, z->resource.end-board+1); - - if(!address){ - printk("Could not remap Fastlane controller memory!"); - goto err_unregister; - } - - - /* The DMA registers on the Fastlane are mapped - * relative to the device (i.e. in the same Zorro - * I/O block). - */ - esp->dregs = (void *)(address + FASTLANE_DMA_ADDR); - - /* ESP register base */ - esp->eregs = (struct ESP_regs *)(address + FASTLANE_ESP_ADDR); - - /* Board base */ - esp->edev = (void *) address; - - /* Set the command buffer */ - esp->esp_command = cmd_buffer; - esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); - - esp->irq = IRQ_AMIGA_PORTS; - esp->slot = board+FASTLANE_ESP_ADDR; - if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, - "Fastlane SCSI", esp->ehost)) { - printk(KERN_WARNING "Fastlane: Could not get IRQ%d, aborting.\n", IRQ_AMIGA_PORTS); - goto err_unmap; - } - - /* Controller ID */ - esp->scsi_id = 7; - - /* We don't have a differential SCSI-bus. */ - esp->diff = 0; - - dma_clear(esp); - esp_initialize(esp); - - printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); - esps_running = esps_in_use; - return esps_in_use; - } - } - return 0; - - err_unmap: - z_iounmap((void *)address); - err_unregister: - scsi_unregister (esp->ehost); - err_release: - release_mem_region(z->resource.start+FASTLANE_ESP_ADDR, - sizeof(struct ESP_regs)); - return 0; -} - - -/************************************************************* DMA Functions */ -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) -{ - /* Since the Fastlane DMA is fully dedicated to the ESP chip, - * the number of bytes sent (to the ESP chip) equals the number - * of bytes in the FIFO - there is no buffering in the DMA controller. - * XXXX Do I read this right? It is from host to ESP, right? - */ - return fifo_count; -} - -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - unsigned long sz = sp->SCp.this_residual; - if(sz > 0xfffc) - sz = 0xfffc; - return sz; -} - -static void dma_dump_state(struct NCR_ESP *esp) -{ - ESPLOG(("esp%d: dma -- cond_reg<%02x>\n", - esp->esp_id, ((struct fastlane_dma_registers *) - (esp->dregs))->cond_reg)); - ESPLOG(("intreq:<%04x>, intena:<%04x>\n", - amiga_custom.intreqr, amiga_custom.intenar)); -} - -static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) -{ - struct fastlane_dma_registers *dregs = - (struct fastlane_dma_registers *) (esp->dregs); - unsigned long *t; - - cache_clear(addr, length); - - dma_clear(esp); - - t = (unsigned long *)((addr & 0x00ffffff) + esp->edev); - - dregs->clear_strobe = 0; - *t = addr; - - ctrl_data = (ctrl_data & FASTLANE_DMA_MASK) | FASTLANE_DMA_ENABLE; - dregs->ctrl_reg = ctrl_data; -} - -static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) -{ - struct fastlane_dma_registers *dregs = - (struct fastlane_dma_registers *) (esp->dregs); - unsigned long *t; - - cache_push(addr, length); - - dma_clear(esp); - - t = (unsigned long *)((addr & 0x00ffffff) + (esp->edev)); - - dregs->clear_strobe = 0; - *t = addr; - - ctrl_data = ((ctrl_data & FASTLANE_DMA_MASK) | - FASTLANE_DMA_ENABLE | - FASTLANE_DMA_WRITE); - dregs->ctrl_reg = ctrl_data; -} - - -static void dma_ints_off(struct NCR_ESP *esp) -{ - disable_irq(esp->irq); -} - -static void dma_ints_on(struct NCR_ESP *esp) -{ - enable_irq(esp->irq); -} - -static void dma_irq_exit(struct NCR_ESP *esp) -{ - struct fastlane_dma_registers *dregs = - (struct fastlane_dma_registers *) (esp->dregs); - - dregs->ctrl_reg = ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI); -#ifdef __mc68000__ - nop(); -#endif - dregs->ctrl_reg = ctrl_data; -} - -static int dma_irq_p(struct NCR_ESP *esp) -{ - struct fastlane_dma_registers *dregs = - (struct fastlane_dma_registers *) (esp->dregs); - unsigned char dma_status; - - dma_status = dregs->cond_reg; - - if(dma_status & FASTLANE_DMA_IACT) - return 0; /* not our IRQ */ - - /* Return non-zero if ESP requested IRQ */ - return ( -#ifndef NODMAIRQ - (dma_status & FASTLANE_DMA_CREQ) && -#endif - (!(dma_status & FASTLANE_DMA_MINT)) && - (esp_read(((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR)); -} - -static void dma_led_off(struct NCR_ESP *esp) -{ - ctrl_data &= ~FASTLANE_DMA_LED; - ((struct fastlane_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data; -} - -static void dma_led_on(struct NCR_ESP *esp) -{ - ctrl_data |= FASTLANE_DMA_LED; - ((struct fastlane_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data; -} - -static int dma_ports_p(struct NCR_ESP *esp) -{ - return ((amiga_custom.intenar) & IF_PORTS); -} - -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) -{ - /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" - * so when (write) is true, it actually means READ! - */ - if(write){ - dma_init_read(esp, addr, count); - } else { - dma_init_write(esp, addr, count); - } -} - -#define HOSTS_C - -int fastlane_esp_release(struct Scsi_Host *instance) -{ -#ifdef MODULE - unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; - esp_deallocate((struct NCR_ESP *)instance->hostdata); - esp_release(); - release_mem_region(address, sizeof(struct ESP_regs)); - free_irq(IRQ_AMIGA_PORTS, esp_intr); -#endif - return 1; -} - - -static struct scsi_host_template driver_template = { - .proc_name = "esp-fastlane", - .proc_info = esp_proc_info, - .name = "Fastlane SCSI", - .detect = fastlane_esp_detect, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .release = fastlane_esp_release, - .queuecommand = esp_queue, - .eh_abort_handler = esp_abort, - .eh_bus_reset_handler = esp_reset, - .can_queue = 7, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING -}; - -#include "scsi_module.c" - -MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index b6f99dfbb038..8a178674cb18 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -629,8 +629,9 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) int rc; if (tcp_conn->in.datalen) { - printk(KERN_ERR "iscsi_tcp: invalid R2t with datalen %d\n", - tcp_conn->in.datalen); + iscsi_conn_printk(KERN_ERR, conn, + "invalid R2t with datalen %d\n", + tcp_conn->in.datalen); return ISCSI_ERR_DATALEN; } @@ -644,8 +645,9 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) { - printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " - "recovery...\n", ctask->itt); + iscsi_conn_printk(KERN_INFO, conn, + "dropping R2T itt %d in recovery.\n", + ctask->itt); return 0; } @@ -655,7 +657,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->exp_statsn = rhdr->statsn; r2t->data_length = be32_to_cpu(rhdr->data_length); if (r2t->data_length == 0) { - printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n"); + iscsi_conn_printk(KERN_ERR, conn, + "invalid R2T with zero data len\n"); __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); return ISCSI_ERR_DATALEN; @@ -668,9 +671,10 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_offset = be32_to_cpu(rhdr->data_offset); if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) { - printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at " - "offset %u and total length %d\n", r2t->data_length, - r2t->data_offset, scsi_bufflen(ctask->sc)); + iscsi_conn_printk(KERN_ERR, conn, + "invalid R2T with data len %u at offset %u " + "and total length %d\n", r2t->data_length, + r2t->data_offset, scsi_bufflen(ctask->sc)); __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); return ISCSI_ERR_DATALEN; @@ -736,8 +740,9 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) /* verify PDU length */ tcp_conn->in.datalen = ntoh24(hdr->dlength); if (tcp_conn->in.datalen > conn->max_recv_dlength) { - printk(KERN_ERR "iscsi_tcp: datalen %d > %d\n", - tcp_conn->in.datalen, conn->max_recv_dlength); + iscsi_conn_printk(KERN_ERR, conn, + "iscsi_tcp: datalen %d > %d\n", + tcp_conn->in.datalen, conn->max_recv_dlength); return ISCSI_ERR_DATALEN; } @@ -819,10 +824,12 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) * For now we fail until we find a vendor that needs it */ if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) { - printk(KERN_ERR "iscsi_tcp: received buffer of len %u " - "but conn buffer is only %u (opcode %0x)\n", - tcp_conn->in.datalen, - ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); + iscsi_conn_printk(KERN_ERR, conn, + "iscsi_tcp: received buffer of " + "len %u but conn buffer is only %u " + "(opcode %0x)\n", + tcp_conn->in.datalen, + ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); rc = ISCSI_ERR_PROTO; break; } @@ -1496,30 +1503,25 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); tcp_conn->tx_hash.flags = 0; - if (IS_ERR(tcp_conn->tx_hash.tfm)) { - printk(KERN_ERR "Could not create connection due to crc32c " - "loading error %ld. Make sure the crc32c module is " - "built as a module or into the kernel\n", - PTR_ERR(tcp_conn->tx_hash.tfm)); + if (IS_ERR(tcp_conn->tx_hash.tfm)) goto free_tcp_conn; - } tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); tcp_conn->rx_hash.flags = 0; - if (IS_ERR(tcp_conn->rx_hash.tfm)) { - printk(KERN_ERR "Could not create connection due to crc32c " - "loading error %ld. Make sure the crc32c module is " - "built as a module or into the kernel\n", - PTR_ERR(tcp_conn->rx_hash.tfm)); + if (IS_ERR(tcp_conn->rx_hash.tfm)) goto free_tx_tfm; - } return cls_conn; free_tx_tfm: crypto_free_hash(tcp_conn->tx_hash.tfm); free_tcp_conn: + iscsi_conn_printk(KERN_ERR, conn, + "Could not create connection due to crc32c " + "loading error. Make sure the crc32c " + "module is built as a module or into the " + "kernel\n"); kfree(tcp_conn); tcp_conn_alloc_fail: iscsi_conn_teardown(cls_conn); @@ -1627,7 +1629,8 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, /* lookup for existing socket */ sock = sockfd_lookup((int)transport_eph, &err); if (!sock) { - printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err); + iscsi_conn_printk(KERN_ERR, conn, + "sockfd_lookup failed %d\n", err); return -EEXIST; } /* diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 553168ae44f1..59f8445eab0d 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -160,7 +160,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) hdr->opcode = ISCSI_OP_SCSI_CMD; hdr->flags = ISCSI_ATTR_SIMPLE; int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); - hdr->itt = build_itt(ctask->itt, conn->id, session->age); + hdr->itt = build_itt(ctask->itt, session->age); hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); hdr->cmdsn = cpu_to_be32(session->cmdsn); session->cmdsn++; @@ -416,8 +416,9 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (datalen < 2) { invalid_datalen: - printk(KERN_ERR "iscsi: Got CHECK_CONDITION but " - "invalid data buffer size of %d\n", datalen); + iscsi_conn_printk(KERN_ERR, conn, + "Got CHECK_CONDITION but invalid data " + "buffer size of %d\n", datalen); sc->result = DID_BAD_TARGET << 16; goto out; } @@ -494,7 +495,7 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); if (!mtask) { - printk(KERN_ERR "Could not send nopout\n"); + iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n"); return; } @@ -522,9 +523,10 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); itt = get_itt(rejected_pdu.itt); - printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected " - "due to DataDigest error.\n", itt, - rejected_pdu.opcode); + iscsi_conn_printk(KERN_ERR, conn, + "itt 0x%x had pdu (op 0x%x) rejected " + "due to DataDigest error.\n", itt, + rejected_pdu.opcode); } } return 0; @@ -541,8 +543,8 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, * queuecommand or send generic. session lock must be held and verify * itt must have been called. */ -int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, - char *data, int datalen) +static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + char *data, int datalen) { struct iscsi_session *session = conn->session; int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; @@ -672,7 +674,6 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, return rc; } -EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, char *data, int datalen) @@ -697,18 +698,13 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (hdr->itt != RESERVED_ITT) { if (((__force u32)hdr->itt & ISCSI_AGE_MASK) != (session->age << ISCSI_AGE_SHIFT)) { - printk(KERN_ERR "iscsi: received itt %x expected " - "session age (%x)\n", (__force u32)hdr->itt, - session->age & ISCSI_AGE_MASK); + iscsi_conn_printk(KERN_ERR, conn, + "received itt %x expected session " + "age (%x)\n", (__force u32)hdr->itt, + session->age & ISCSI_AGE_MASK); return ISCSI_ERR_BAD_ITT; } - if (((__force u32)hdr->itt & ISCSI_CID_MASK) != - (conn->id << ISCSI_CID_SHIFT)) { - printk(KERN_ERR "iscsi: received itt %x, expected " - "CID (%x)\n", (__force u32)hdr->itt, conn->id); - return ISCSI_ERR_BAD_ITT; - } itt = get_itt(hdr->itt); } else itt = ~0U; @@ -717,16 +713,17 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, ctask = session->cmds[itt]; if (!ctask->sc) { - printk(KERN_INFO "iscsi: dropping ctask with " - "itt 0x%x\n", ctask->itt); + iscsi_conn_printk(KERN_INFO, conn, "dropping ctask " + "with itt 0x%x\n", ctask->itt); /* force drop */ return ISCSI_ERR_NO_SCSI_CMD; } if (ctask->sc->SCp.phase != session->age) { - printk(KERN_ERR "iscsi: ctask's session age %d, " - "expected %d\n", ctask->sc->SCp.phase, - session->age); + iscsi_conn_printk(KERN_ERR, conn, + "iscsi: ctask's session age %d, " + "expected %d\n", ctask->sc->SCp.phase, + session->age); return ISCSI_ERR_SESSION_FAILED; } } @@ -771,7 +768,7 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn, */ nop->cmdsn = cpu_to_be32(session->cmdsn); if (hdr->itt != RESERVED_ITT) { - hdr->itt = build_itt(mtask->itt, conn->id, session->age); + hdr->itt = build_itt(mtask->itt, session->age); /* * TODO: We always use immediate, so we never hit this. * If we start to send tmfs or nops as non-immediate then @@ -997,6 +994,7 @@ enum { FAILURE_SESSION_IN_RECOVERY, FAILURE_SESSION_RECOVERY_TIMEOUT, FAILURE_SESSION_LOGGING_OUT, + FAILURE_SESSION_NOT_READY, }; int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) @@ -1017,6 +1015,12 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) session = iscsi_hostdata(host->hostdata); spin_lock(&session->lock); + reason = iscsi_session_chkready(session_to_cls(session)); + if (reason) { + sc->result = reason; + goto fault; + } + /* * ISCSI_STATE_FAILED is a temp. state. The recovery * code will decide what is best to do with command queued @@ -1033,18 +1037,23 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) switch (session->state) { case ISCSI_STATE_IN_RECOVERY: reason = FAILURE_SESSION_IN_RECOVERY; - goto reject; + sc->result = DID_IMM_RETRY << 16; + break; case ISCSI_STATE_LOGGING_OUT: reason = FAILURE_SESSION_LOGGING_OUT; - goto reject; + sc->result = DID_IMM_RETRY << 16; + break; case ISCSI_STATE_RECOVERY_FAILED: reason = FAILURE_SESSION_RECOVERY_TIMEOUT; + sc->result = DID_NO_CONNECT << 16; break; case ISCSI_STATE_TERMINATE: reason = FAILURE_SESSION_TERMINATE; + sc->result = DID_NO_CONNECT << 16; break; default: reason = FAILURE_SESSION_FREED; + sc->result = DID_NO_CONNECT << 16; } goto fault; } @@ -1052,6 +1061,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) conn = session->leadconn; if (!conn) { reason = FAILURE_SESSION_FREED; + sc->result = DID_NO_CONNECT << 16; goto fault; } @@ -1091,9 +1101,7 @@ reject: fault: spin_unlock(&session->lock); - printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n", - sc->cmnd[0], reason); - sc->result = (DID_NO_CONNECT << 16); + debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); scsi_set_resid(sc, scsi_bufflen(sc)); sc->scsi_done(sc); spin_lock(host->host_lock); @@ -1160,7 +1168,8 @@ failed: mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_LOGGED_IN) - printk(KERN_INFO "iscsi: host reset succeeded\n"); + iscsi_session_printk(KERN_INFO, session, + "host reset succeeded\n"); else goto failed; spin_unlock_bh(&session->lock); @@ -1239,7 +1248,8 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, * Fail commands. session lock held and recv side suspended and xmit * thread flushed */ -static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) +static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, + int error) { struct iscsi_cmd_task *ctask, *tmp; @@ -1251,7 +1261,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) if (lun == ctask->sc->device->lun || lun == -1) { debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, ctask->itt); - fail_command(conn, ctask, DID_BUS_BUSY << 16); + fail_command(conn, ctask, error << 16); } } @@ -1259,7 +1269,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) if (lun == ctask->sc->device->lun || lun == -1) { debug_scsi("failing requeued sc %p itt 0x%x\n", ctask->sc, ctask->itt); - fail_command(conn, ctask, DID_BUS_BUSY << 16); + fail_command(conn, ctask, error << 16); } } @@ -1357,10 +1367,10 @@ static void iscsi_check_transport_timeouts(unsigned long data) last_recv = conn->last_recv; if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ), jiffies)) { - printk(KERN_ERR "ping timeout of %d secs expired, " - "last rx %lu, last ping %lu, now %lu\n", - conn->ping_timeout, last_recv, - conn->last_ping, jiffies); + iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs " + "expired, last rx %lu, last ping %lu, " + "now %lu\n", conn->ping_timeout, last_recv, + conn->last_ping, jiffies); spin_unlock(&session->lock); iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return; @@ -1373,14 +1383,11 @@ static void iscsi_check_transport_timeouts(unsigned long data) iscsi_send_nopout(conn, NULL); } next_timeout = last_recv + timeout + (conn->ping_timeout * HZ); - } else { + } else next_timeout = last_recv + timeout; - } - if (next_timeout) { - debug_scsi("Setting next tmo %lu\n", next_timeout); - mod_timer(&conn->transport_timer, next_timeout); - } + debug_scsi("Setting next tmo %lu\n", next_timeout); + mod_timer(&conn->transport_timer, next_timeout); done: spin_unlock(&session->lock); } @@ -1573,7 +1580,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) /* need to grab the recv lock then session lock */ write_lock_bh(conn->recv_lock); spin_lock(&session->lock); - fail_all_commands(conn, sc->device->lun); + fail_all_commands(conn, sc->device->lun, DID_ERROR); conn->tmf_state = TMF_INITIAL; spin_unlock(&session->lock); write_unlock_bh(conn->recv_lock); @@ -1944,9 +1951,10 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) } spin_unlock_irqrestore(session->host->host_lock, flags); msleep_interruptible(500); - printk(KERN_INFO "iscsi: scsi conn_destroy(): host_busy %d " - "host_failed %d\n", session->host->host_busy, - session->host->host_failed); + iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): " + "host_busy %d host_failed %d\n", + session->host->host_busy, + session->host->host_failed); /* * force eh_abort() to unblock */ @@ -1975,27 +1983,28 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) struct iscsi_session *session = conn->session; if (!session) { - printk(KERN_ERR "iscsi: can't start unbound connection\n"); + iscsi_conn_printk(KERN_ERR, conn, + "can't start unbound connection\n"); return -EPERM; } if ((session->imm_data_en || !session->initial_r2t_en) && session->first_burst > session->max_burst) { - printk("iscsi: invalid burst lengths: " - "first_burst %d max_burst %d\n", - session->first_burst, session->max_burst); + iscsi_conn_printk(KERN_INFO, conn, "invalid burst lengths: " + "first_burst %d max_burst %d\n", + session->first_burst, session->max_burst); return -EINVAL; } if (conn->ping_timeout && !conn->recv_timeout) { - printk(KERN_ERR "iscsi: invalid recv timeout of zero " - "Using 5 seconds\n."); + iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of " + "zero. Using 5 seconds\n."); conn->recv_timeout = 5; } if (conn->recv_timeout && !conn->ping_timeout) { - printk(KERN_ERR "iscsi: invalid ping timeout of zero " - "Using 5 seconds.\n"); + iscsi_conn_printk(KERN_ERR, conn, "invalid ping timeout of " + "zero. Using 5 seconds.\n"); conn->ping_timeout = 5; } @@ -2019,11 +2028,9 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) conn->stop_stage = 0; conn->tmf_state = TMF_INITIAL; session->age++; - spin_unlock_bh(&session->lock); - - iscsi_unblock_session(session_to_cls(session)); - wake_up(&conn->ehwait); - return 0; + if (session->age == 16) + session->age = 0; + break; case STOP_CONN_TERM: conn->stop_stage = 0; break; @@ -2032,6 +2039,8 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) } spin_unlock_bh(&session->lock); + iscsi_unblock_session(session_to_cls(session)); + wake_up(&conn->ehwait); return 0; } EXPORT_SYMBOL_GPL(iscsi_conn_start); @@ -2123,7 +2132,8 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, * flush queues. */ spin_lock_bh(&session->lock); - fail_all_commands(conn, -1); + fail_all_commands(conn, -1, + STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR); flush_control_queues(session, conn); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); @@ -2140,7 +2150,8 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) iscsi_start_session_recovery(session, conn, flag); break; default: - printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); + iscsi_conn_printk(KERN_ERR, conn, + "invalid stop flag %d\n", flag); } } EXPORT_SYMBOL_GPL(iscsi_conn_stop); diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c deleted file mode 100644 index bcb49021b7e2..000000000000 --- a/drivers/scsi/mac_esp.c +++ /dev/null @@ -1,751 +0,0 @@ -/* - * 68k mac 53c9[46] scsi driver - * - * copyright (c) 1998, David Weis weisd3458@uni.edu - * - * debugging on Quadra 800 and 660AV Michael Schmitz, Dave Kilzer 7/98 - * - * based loosely on cyber_esp.c - */ - -/* these are unused for now */ -#define myreadl(addr) (*(volatile unsigned int *) (addr)) -#define mywritel(b, addr) ((*(volatile unsigned int *) (addr)) = (b)) - - -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/ctype.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/blkdev.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/init.h> -#include <linux/interrupt.h> - -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "NCR53C9x.h" - -#include <asm/io.h> - -#include <asm/setup.h> -#include <asm/irq.h> -#include <asm/macints.h> -#include <asm/machw.h> -#include <asm/mac_via.h> - -#include <asm/pgtable.h> - -#include <asm/macintosh.h> - -/* #define DEBUG_MAC_ESP */ - -extern void esp_handle(struct NCR_ESP *esp); -extern void mac_esp_intr(int irq, void *dev_id); - -static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count); -static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd *sp); -static void dma_dump_state(struct NCR_ESP * esp); -static void dma_init_read(struct NCR_ESP * esp, char * vaddress, int length); -static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length); -static void dma_ints_off(struct NCR_ESP * esp); -static void dma_ints_on(struct NCR_ESP * esp); -static int dma_irq_p(struct NCR_ESP * esp); -static int dma_irq_p_quick(struct NCR_ESP * esp); -static void dma_led_off(struct NCR_ESP * esp); -static void dma_led_on(struct NCR_ESP *esp); -static int dma_ports_p(struct NCR_ESP *esp); -static void dma_setup(struct NCR_ESP * esp, __u32 addr, int count, int write); -static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int write); - -static int esp_dafb_dma_irq_p(struct NCR_ESP * espdev); -static int esp_iosb_dma_irq_p(struct NCR_ESP * espdev); - -static volatile unsigned char cmd_buffer[16]; - /* This is where all commands are put - * before they are transferred to the ESP chip - * via PIO. - */ - -static int esp_initialized = 0; - -static int setup_num_esps = -1; -static int setup_disconnect = -1; -static int setup_nosync = -1; -static int setup_can_queue = -1; -static int setup_cmd_per_lun = -1; -static int setup_sg_tablesize = -1; -#ifdef SUPPORT_TAGS -static int setup_use_tagged_queuing = -1; -#endif -static int setup_hostid = -1; - -/* - * Experimental ESP inthandler; check macints.c to make sure dev_id is - * set up properly! - */ - -void mac_esp_intr(int irq, void *dev_id) -{ - struct NCR_ESP *esp = (struct NCR_ESP *) dev_id; - int irq_p = 0; - - /* Handle the one ESP interrupt showing at this IRQ level. */ - if(((esp)->irq & 0xff) == irq) { - /* - * Debug .. - */ - irq_p = esp->dma_irq_p(esp); - printk("mac_esp: irq_p %x current %p disconnected %p\n", - irq_p, esp->current_SC, esp->disconnected_SC); - - /* - * Mac: if we're here, it's an ESP interrupt for sure! - */ - if((esp->current_SC || esp->disconnected_SC)) { - esp->dma_ints_off(esp); - - ESPIRQ(("I%d(", esp->esp_id)); - esp_handle(esp); - ESPIRQ((")")); - - esp->dma_ints_on(esp); - } - } -} - -/* - * Debug hooks; use for playing with the interrupt flag testing and interrupt - * acknowledge on the various machines - */ - -void scsi_esp_polled(int irq, void *dev_id) -{ - if (esp_initialized == 0) - return; - - mac_esp_intr(irq, dev_id); -} - -void fake_intr(int irq, void *dev_id) -{ -#ifdef DEBUG_MAC_ESP - printk("mac_esp: got irq\n"); -#endif - - mac_esp_intr(irq, dev_id); -} - -irqreturn_t fake_drq(int irq, void *dev_id) -{ - printk("mac_esp: got drq\n"); - return IRQ_HANDLED; -} - -#define DRIVER_SETUP - -/* - * Function : mac_esp_setup(char *str) - * - * Purpose : booter command line initialization of the overrides array, - * - * Inputs : str - parameters, separated by commas. - * - * Currently unused in the new driver; need to add settable parameters to the - * detect function. - * - */ - -static int __init mac_esp_setup(char *str) { -#ifdef DRIVER_SETUP - /* Format of mac53c9x parameter is: - * mac53c9x=<num_esps>,<disconnect>,<nosync>,<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags> - * Negative values mean don't change. - */ - - char *this_opt; - long opt; - - this_opt = strsep (&str, ","); - if(this_opt) { - opt = simple_strtol( this_opt, NULL, 0 ); - - if (opt >= 0 && opt <= 2) - setup_num_esps = opt; - else if (opt > 2) - printk( "mac_esp_setup: invalid number of hosts %ld !\n", opt ); - - this_opt = strsep (&str, ","); - } - if(this_opt) { - opt = simple_strtol( this_opt, NULL, 0 ); - - if (opt > 0) - setup_disconnect = opt; - - this_opt = strsep (&str, ","); - } - if(this_opt) { - opt = simple_strtol( this_opt, NULL, 0 ); - - if (opt >= 0) - setup_nosync = opt; - - this_opt = strsep (&str, ","); - } - if(this_opt) { - opt = simple_strtol( this_opt, NULL, 0 ); - - if (opt > 0) - setup_can_queue = opt; - - this_opt = strsep (&str, ","); - } - if(this_opt) { - opt = simple_strtol( this_opt, NULL, 0 ); - - if (opt > 0) - setup_cmd_per_lun = opt; - - this_opt = strsep (&str, ","); - } - if(this_opt) { - opt = simple_strtol( this_opt, NULL, 0 ); - - if (opt >= 0) { - setup_sg_tablesize = opt; - /* Must be <= SG_ALL (255) */ - if (setup_sg_tablesize > SG_ALL) - setup_sg_tablesize = SG_ALL; - } - - this_opt = strsep (&str, ","); - } - if(this_opt) { - opt = simple_strtol( this_opt, NULL, 0 ); - - /* Must be between 0 and 7 */ - if (opt >= 0 && opt <= 7) - setup_hostid = opt; - else if (opt > 7) - printk( "mac_esp_setup: invalid host ID %ld !\n", opt); - - this_opt = strsep (&str, ","); - } -#ifdef SUPPORT_TAGS - if(this_opt) { - opt = simple_strtol( this_opt, NULL, 0 ); - if (opt >= 0) - setup_use_tagged_queuing = !!opt; - } -#endif -#endif - return 1; -} - -__setup("mac53c9x=", mac_esp_setup); - - -/* - * ESP address 'detection' - */ - -unsigned long get_base(int chip_num) -{ - /* - * using the chip_num and mac model, figure out where the - * chips are mapped - */ - - unsigned long io_base = 0x50f00000; - unsigned int second_offset = 0x402; - unsigned long scsi_loc = 0; - - switch (macintosh_config->scsi_type) { - - /* 950, 900, 700 */ - case MAC_SCSI_QUADRA2: - scsi_loc = io_base + 0xf000 + ((chip_num == 0) ? 0 : second_offset); - break; - - /* av's */ - case MAC_SCSI_QUADRA3: - scsi_loc = io_base + 0x18000 + ((chip_num == 0) ? 0 : second_offset); - break; - - /* most quadra/centris models are like this */ - case MAC_SCSI_QUADRA: - scsi_loc = io_base + 0x10000; - break; - - default: - printk("mac_esp: get_base: hit default!\n"); - scsi_loc = io_base + 0x10000; - break; - - } /* switch */ - - printk("mac_esp: io base at 0x%lx\n", scsi_loc); - - return scsi_loc; -} - -/* - * Model dependent ESP setup - */ - -int mac_esp_detect(struct scsi_host_template * tpnt) -{ - int quick = 0; - int chipnum, chipspresent = 0; -#if 0 - unsigned long timeout; -#endif - - if (esp_initialized > 0) - return -ENODEV; - - /* what do we have in this machine... */ - if (MACHW_PRESENT(MAC_SCSI_96)) { - chipspresent ++; - } - - if (MACHW_PRESENT(MAC_SCSI_96_2)) { - chipspresent ++; - } - - /* number of ESPs present ? */ - if (setup_num_esps >= 0) { - if (chipspresent >= setup_num_esps) - chipspresent = setup_num_esps; - else - printk("mac_esp_detect: num_hosts detected %d setup %d \n", - chipspresent, setup_num_esps); - } - - /* TODO: add disconnect / nosync flags */ - - /* setup variables */ - tpnt->can_queue = - (setup_can_queue > 0) ? setup_can_queue : 7; - tpnt->cmd_per_lun = - (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : 1; - tpnt->sg_tablesize = - (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_ALL; - - if (setup_hostid >= 0) - tpnt->this_id = setup_hostid; - else { - /* use 7 as default */ - tpnt->this_id = 7; - } - -#ifdef SUPPORT_TAGS - if (setup_use_tagged_queuing < 0) - setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING; -#endif - - for (chipnum = 0; chipnum < chipspresent; chipnum ++) { - struct NCR_ESP * esp; - - esp = esp_allocate(tpnt, NULL, 0); - esp->eregs = (struct ESP_regs *) get_base(chipnum); - - esp->dma_irq_p = &esp_dafb_dma_irq_p; - if (chipnum == 0) { - - if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) { - /* most machines except those below :-) */ - quick = 1; - esp->dma_irq_p = &esp_iosb_dma_irq_p; - } else if (macintosh_config->scsi_type == MAC_SCSI_QUADRA3) { - /* mostly av's */ - quick = 0; - } else { - /* q950, 900, 700 */ - quick = 1; - out_be32(0xf9800024, 0x1d1); - esp->dregs = (void *) 0xf9800024; - } - - } else { /* chipnum */ - - quick = 1; - out_be32(0xf9800028, 0x1d1); - esp->dregs = (void *) 0xf9800028; - - } /* chipnum == 0 */ - - /* use pio for command bytes; pio for message/data: TBI */ - esp->do_pio_cmds = 1; - - /* Set the command buffer */ - esp->esp_command = (volatile unsigned char*) cmd_buffer; - esp->esp_command_dvma = (__u32) cmd_buffer; - - /* various functions */ - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = NULL; - esp->dma_init_write = NULL; - esp->dma_ints_off = &dma_ints_off; - esp->dma_ints_on = &dma_ints_on; - - esp->dma_ports_p = &dma_ports_p; - - - /* Optional functions */ - esp->dma_barrier = NULL; - esp->dma_drain = NULL; - esp->dma_invalidate = NULL; - esp->dma_irq_entry = NULL; - esp->dma_irq_exit = NULL; - esp->dma_led_on = NULL; - esp->dma_led_off = NULL; - esp->dma_poll = NULL; - esp->dma_reset = NULL; - - /* SCSI chip speed */ - /* below esp->cfreq = 40000000; */ - - - if (quick) { - /* 'quick' means there's handshake glue logic like in the 5380 case */ - esp->dma_setup = &dma_setup_quick; - } else { - esp->dma_setup = &dma_setup; - } - - if (chipnum == 0) { - - esp->irq = IRQ_MAC_SCSI; - - request_irq(IRQ_MAC_SCSI, esp_intr, 0, "Mac ESP SCSI", esp->ehost); -#if 0 /* conflicts with IOP ADB */ - request_irq(IRQ_MAC_SCSIDRQ, fake_drq, 0, "Mac ESP DRQ", esp->ehost); -#endif - - if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) { - esp->cfreq = 16500000; - } else { - esp->cfreq = 25000000; - } - - - } else { /* chipnum == 1 */ - - esp->irq = IRQ_MAC_SCSIDRQ; -#if 0 /* conflicts with IOP ADB */ - request_irq(IRQ_MAC_SCSIDRQ, esp_intr, 0, "Mac ESP SCSI 2", esp->ehost); -#endif - - esp->cfreq = 25000000; - - } - - if (quick) { - printk("esp: using quick version\n"); - } - - printk("esp: addr at 0x%p\n", esp->eregs); - - esp->scsi_id = 7; - esp->diff = 0; - - esp_initialize(esp); - - } /* for chipnum */ - - if (chipspresent) - printk("\nmac_esp: %d esp controllers found\n", chipspresent); - - esp_initialized = chipspresent; - - return chipspresent; -} - -static int mac_esp_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, NULL); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - return 0; -} - -/* - * I've been wondering what this is supposed to do, for some time. Talking - * to Allen Briggs: These machines have an extra register someplace where the - * DRQ pin of the ESP can be monitored. That isn't useful for determining - * anything else (such as reselect interrupt or other magic) though. - * Maybe make the semantics should be changed like - * if (esp->current_SC) - * ... check DRQ flag ... - * else - * ... disconnected, check pending VIA interrupt ... - * - * There's a problem with using the dabf flag or mac_irq_pending() here: both - * seem to return 1 even though no interrupt is currently pending, resulting - * in esp_exec_cmd() holding off the next command, and possibly infinite loops - * in esp_intr(). - * Short term fix: just use esp_status & ESP_STAT_INTR here, as long as we - * use simple PIO. The DRQ status will be important when implementing pseudo - * DMA mode (set up ESP transfer count, return, do a batch of bytes in PIO or - * 'hardware handshake' mode upon DRQ). - * If you plan on changing this (i.e. to save the esp_status register access in - * favor of a VIA register access or a shadow register for the IFR), make sure - * to try a debug version of this first to monitor what registers would be a good - * indicator of the ESP interrupt. - */ - -static int esp_dafb_dma_irq_p(struct NCR_ESP * esp) -{ - unsigned int ret; - int sreg = esp_read(esp->eregs->esp_status); - -#ifdef DEBUG_MAC_ESP - printk("mac_esp: esp_dafb_dma_irq_p dafb %d irq %d\n", - readl(esp->dregs), mac_irq_pending(IRQ_MAC_SCSI)); -#endif - - sreg &= ESP_STAT_INTR; - - /* - * maybe working; this is essentially what's used for iosb_dma_irq_p - */ - if (sreg) - return 1; - else - return 0; - - /* - * didn't work ... - */ -#if 0 - if (esp->current_SC) - ret = readl(esp->dregs) & 0x200; - else if (esp->disconnected_SC) - ret = 1; /* sreg ?? */ - else - ret = mac_irq_pending(IRQ_MAC_SCSI); - - return(ret); -#endif - -} - -/* - * See above: testing mac_irq_pending always returned 8 (SCSI IRQ) regardless - * of the actual ESP status. - */ - -static int esp_iosb_dma_irq_p(struct NCR_ESP * esp) -{ - int ret = mac_irq_pending(IRQ_MAC_SCSI) || mac_irq_pending(IRQ_MAC_SCSIDRQ); - int sreg = esp_read(esp->eregs->esp_status); - -#ifdef DEBUG_MAC_ESP - printk("mac_esp: dma_irq_p drq %d irq %d sreg %x curr %p disc %p\n", - mac_irq_pending(IRQ_MAC_SCSIDRQ), mac_irq_pending(IRQ_MAC_SCSI), - sreg, esp->current_SC, esp->disconnected_SC); -#endif - - sreg &= ESP_STAT_INTR; - - if (sreg) - return (sreg); - else - return 0; -} - -/* - * This seems to be OK for PIO at least ... usually 0 after PIO. - */ - -static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count) -{ - -#ifdef DEBUG_MAC_ESP - printk("mac_esp: dma bytes sent = %x\n", fifo_count); -#endif - - return fifo_count; -} - -/* - * dma_can_transfer is used to switch between DMA and PIO, if DMA (pseudo) - * is ever implemented. Returning 0 here will use PIO. - */ - -static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd * sp) -{ - unsigned long sz = sp->SCp.this_residual; -#if 0 /* no DMA yet; make conditional */ - if (sz > 0x10000000) { - sz = 0x10000000; - } - printk("mac_esp: dma can transfer = 0lx%x\n", sz); -#else - -#ifdef DEBUG_MAC_ESP - printk("mac_esp: pio to transfer = %ld\n", sz); -#endif - - sz = 0; -#endif - return sz; -} - -/* - * Not yet ... - */ - -static void dma_dump_state(struct NCR_ESP * esp) -{ -#ifdef DEBUG_MAC_ESP - printk("mac_esp: dma_dump_state: called\n"); -#endif -#if 0 - ESPLOG(("esp%d: dma -- cond_reg<%02x>\n", - esp->esp_id, ((struct mac_dma_registers *) - (esp->dregs))->cond_reg)); -#endif -} - -/* - * DMA setup: should be used to set up the ESP transfer count for pseudo - * DMA transfers; need a DRQ transfer function to do the actual transfer - */ - -static void dma_init_read(struct NCR_ESP * esp, char * vaddress, int length) -{ - printk("mac_esp: dma_init_read\n"); -} - - -static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length) -{ - printk("mac_esp: dma_init_write\n"); -} - - -static void dma_ints_off(struct NCR_ESP * esp) -{ - disable_irq(esp->irq); -} - - -static void dma_ints_on(struct NCR_ESP * esp) -{ - enable_irq(esp->irq); -} - -/* - * generic dma_irq_p(), unused - */ - -static int dma_irq_p(struct NCR_ESP * esp) -{ - int i = esp_read(esp->eregs->esp_status); - -#ifdef DEBUG_MAC_ESP - printk("mac_esp: dma_irq_p status %d\n", i); -#endif - - return (i & ESP_STAT_INTR); -} - -static int dma_irq_p_quick(struct NCR_ESP * esp) -{ - /* - * Copied from iosb_dma_irq_p() - */ - int ret = mac_irq_pending(IRQ_MAC_SCSI) || mac_irq_pending(IRQ_MAC_SCSIDRQ); - int sreg = esp_read(esp->eregs->esp_status); - -#ifdef DEBUG_MAC_ESP - printk("mac_esp: dma_irq_p drq %d irq %d sreg %x curr %p disc %p\n", - mac_irq_pending(IRQ_MAC_SCSIDRQ), mac_irq_pending(IRQ_MAC_SCSI), - sreg, esp->current_SC, esp->disconnected_SC); -#endif - - sreg &= ESP_STAT_INTR; - - if (sreg) - return (sreg); - else - return 0; - -} - -static void dma_led_off(struct NCR_ESP * esp) -{ -#ifdef DEBUG_MAC_ESP - printk("mac_esp: dma_led_off: called\n"); -#endif -} - - -static void dma_led_on(struct NCR_ESP * esp) -{ -#ifdef DEBUG_MAC_ESP - printk("mac_esp: dma_led_on: called\n"); -#endif -} - - -static int dma_ports_p(struct NCR_ESP * esp) -{ - return 0; -} - - -static void dma_setup(struct NCR_ESP * esp, __u32 addr, int count, int write) -{ - -#ifdef DEBUG_MAC_ESP - printk("mac_esp: dma_setup\n"); -#endif - - if (write) { - dma_init_read(esp, (char *) addr, count); - } else { - dma_init_write(esp, (char *) addr, count); - } -} - - -static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int write) -{ -#ifdef DEBUG_MAC_ESP - printk("mac_esp: dma_setup_quick\n"); -#endif -} - -static struct scsi_host_template driver_template = { - .proc_name = "mac_esp", - .name = "Mac 53C9x SCSI", - .detect = mac_esp_detect, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .release = mac_esp_release, - .info = esp_info, - .queuecommand = esp_queue, - .eh_abort_handler = esp_abort, - .eh_bus_reset_handler = esp_reset, - .can_queue = 7, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING -}; - - -#include "scsi_module.c" - -MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c deleted file mode 100644 index d693d0f21395..000000000000 --- a/drivers/scsi/mca_53c9x.c +++ /dev/null @@ -1,520 +0,0 @@ -/* mca_53c9x.c: Driver for the SCSI adapter found on NCR 35xx - * (and maybe some other) Microchannel machines - * - * Code taken mostly from Cyberstorm SCSI drivers - * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) - * - * Hacked to work with the NCR MCA stuff by Tymm Twillman (tymm@computer.org) - * - * The CyberStorm SCSI driver (and this driver) is based on David S. Miller's - * ESP driver * for the Sparc computers. - * - * Special thanks to Ken Stewart at Symbios (LSI) for helping with info on - * the 86C01. I was on the brink of going ga-ga... - * - * Also thanks to Jesper Skov for helping me with info on how the Amiga - * does things... - */ - -/* - * This is currently only set up to use one 53c9x card at a time; it could be - * changed fairly easily to detect/use more than one, but I'm not too sure how - * many cards that use the 53c9x on MCA systems there are (if, in fact, there - * are cards that use them, other than the one built into some NCR systems)... - * If anyone requests this, I'll throw it in, otherwise it's not worth the - * effort. - */ - -/* - * Info on the 86C01 MCA interface chip at the bottom, if you care enough to - * look. - */ - -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/mca.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/blkdev.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/mca-legacy.h> - -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "NCR53C9x.h" - -#include <asm/dma.h> -#include <asm/irq.h> -#include <asm/mca_dma.h> -#include <asm/pgtable.h> - -/* - * From ibmmca.c (IBM scsi controller card driver) -- used for turning PS2 disk - * activity LED on and off - */ - -#define PS2_SYS_CTR 0x92 - -/* Ports the ncr's 53c94 can be put at; indexed by pos register value */ - -#define MCA_53C9X_IO_PORTS { \ - 0x0000, 0x0240, 0x0340, 0x0400, \ - 0x0420, 0x3240, 0x8240, 0xA240, \ - } - -/* - * Supposedly there were some cards put together with the 'c9x and 86c01. If - * they have different ID's from the ones on the 3500 series machines, - * you can add them here and hopefully things will work out. - */ - -#define MCA_53C9X_IDS { \ - 0x7F4C, \ - 0x0000, \ - } - -static int dma_bytes_sent(struct NCR_ESP *, int); -static int dma_can_transfer(struct NCR_ESP *, Scsi_Cmnd *); -static void dma_dump_state(struct NCR_ESP *); -static void dma_init_read(struct NCR_ESP *, __u32, int); -static void dma_init_write(struct NCR_ESP *, __u32, int); -static void dma_ints_off(struct NCR_ESP *); -static void dma_ints_on(struct NCR_ESP *); -static int dma_irq_p(struct NCR_ESP *); -static int dma_ports_p(struct NCR_ESP *); -static void dma_setup(struct NCR_ESP *, __u32, int, int); -static void dma_led_on(struct NCR_ESP *); -static void dma_led_off(struct NCR_ESP *); - -/* This is where all commands are put before they are trasfered to the - * 53c9x via PIO. - */ - -static volatile unsigned char cmd_buffer[16]; - -/* - * We keep the structure that is used to access the registers on the 53c9x - * here. - */ - -static struct ESP_regs eregs; - -/***************************************************************** Detection */ -static int mca_esp_detect(struct scsi_host_template *tpnt) -{ - struct NCR_ESP *esp; - static int io_port_by_pos[] = MCA_53C9X_IO_PORTS; - int mca_53c9x_ids[] = MCA_53C9X_IDS; - int *id_to_check = mca_53c9x_ids; - int slot; - int pos[3]; - unsigned int tmp_io_addr; - unsigned char tmp_byte; - - - if (!MCA_bus) - return 0; - - while (*id_to_check) { - if ((slot = mca_find_adapter(*id_to_check, 0)) != - MCA_NOTFOUND) - { - esp = esp_allocate(tpnt, NULL, 0); - - pos[0] = mca_read_stored_pos(slot, 2); - pos[1] = mca_read_stored_pos(slot, 3); - pos[2] = mca_read_stored_pos(slot, 4); - - esp->eregs = &eregs; - - /* - * IO port base is given in the first (non-ID) pos - * register, like so: - * - * Bits 3 2 1 IO base - * ---------------------------- - * 0 0 0 <disabled> - * 0 0 1 0x0240 - * 0 1 0 0x0340 - * 0 1 1 0x0400 - * 1 0 0 0x0420 - * 1 0 1 0x3240 - * 1 1 0 0x8240 - * 1 1 1 0xA240 - */ - - tmp_io_addr = - io_port_by_pos[(pos[0] & 0x0E) >> 1]; - - esp->eregs->io_addr = tmp_io_addr + 0x10; - - if (esp->eregs->io_addr == 0x0000) { - printk("Adapter is disabled.\n"); - break; - } - - /* - * IRQ is specified in bits 4 and 5: - * - * Bits 4 5 IRQ - * ----------------------- - * 0 0 3 - * 0 1 5 - * 1 0 7 - * 1 1 9 - */ - - esp->irq = ((pos[0] & 0x30) >> 3) + 3; - - /* - * DMA channel is in the low 3 bits of the second - * POS register - */ - - esp->dma = pos[1] & 7; - esp->slot = slot; - - if (request_irq(esp->irq, esp_intr, 0, - "NCR 53c9x SCSI", esp->ehost)) - { - printk("Unable to request IRQ %d.\n", esp->irq); - esp_deallocate(esp); - scsi_unregister(esp->ehost); - return 0; - } - - if (request_dma(esp->dma, "NCR 53c9x SCSI")) { - printk("Unable to request DMA channel %d.\n", - esp->dma); - free_irq(esp->irq, esp_intr); - esp_deallocate(esp); - scsi_unregister(esp->ehost); - return 0; - } - - request_region(tmp_io_addr, 32, "NCR 53c9x SCSI"); - - /* - * 86C01 handles DMA, IO mode, from address - * (base + 0x0a) - */ - - mca_disable_dma(esp->dma); - mca_set_dma_io(esp->dma, tmp_io_addr + 0x0a); - mca_enable_dma(esp->dma); - - /* Tell the 86C01 to give us interrupts */ - - tmp_byte = inb(tmp_io_addr + 0x02) | 0x40; - outb(tmp_byte, tmp_io_addr + 0x02); - - /* - * Scsi ID -- general purpose register, hi - * 2 bits; add 4 to this number to get the - * ID - */ - - esp->scsi_id = ((pos[2] & 0xC0) >> 6) + 4; - - /* Do command transfer with programmed I/O */ - - esp->do_pio_cmds = 1; - - /* Required functions */ - - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = &dma_init_read; - esp->dma_init_write = &dma_init_write; - esp->dma_ints_off = &dma_ints_off; - esp->dma_ints_on = &dma_ints_on; - esp->dma_irq_p = &dma_irq_p; - esp->dma_ports_p = &dma_ports_p; - esp->dma_setup = &dma_setup; - - /* Optional functions */ - - esp->dma_barrier = NULL; - esp->dma_drain = NULL; - esp->dma_invalidate = NULL; - esp->dma_irq_entry = NULL; - esp->dma_irq_exit = NULL; - esp->dma_led_on = dma_led_on; - esp->dma_led_off = dma_led_off; - esp->dma_poll = NULL; - esp->dma_reset = NULL; - - /* Set the command buffer */ - - esp->esp_command = (volatile unsigned char*) - cmd_buffer; - esp->esp_command_dvma = isa_virt_to_bus(cmd_buffer); - - /* SCSI chip speed */ - - esp->cfreq = 25000000; - - /* Differential SCSI? I think not. */ - - esp->diff = 0; - - esp_initialize(esp); - - printk(" Adapter found in slot %2d: io port 0x%x " - "irq %d dma channel %d\n", slot + 1, tmp_io_addr, - esp->irq, esp->dma); - - mca_set_adapter_name(slot, "NCR 53C9X SCSI Adapter"); - mca_mark_as_used(slot); - - break; - } - - id_to_check++; - } - - return esps_in_use; -} - - -/******************************************************************* Release */ - -static int mca_esp_release(struct Scsi_Host *host) -{ - struct NCR_ESP *esp = (struct NCR_ESP *)host->hostdata; - unsigned char tmp_byte; - - esp_deallocate(esp); - /* - * Tell the 86C01 to stop sending interrupts - */ - - tmp_byte = inb(esp->eregs->io_addr - 0x0E); - tmp_byte &= ~0x40; - outb(tmp_byte, esp->eregs->io_addr - 0x0E); - - free_irq(esp->irq, esp_intr); - free_dma(esp->dma); - - mca_mark_as_unused(esp->slot); - - return 0; -} - -/************************************************************* DMA Functions */ -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) -{ - /* Ask the 53c9x. It knows. */ - - return fifo_count; -} - -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - /* - * The MCA dma channels can only do up to 128K bytes at a time. - * (16 bit mode) - */ - - unsigned long sz = sp->SCp.this_residual; - if(sz > 0x20000) - sz = 0x20000; - return sz; -} - -static void dma_dump_state(struct NCR_ESP *esp) -{ - /* - * Doesn't quite match up to the other drivers, but we do what we - * can. - */ - - ESPLOG(("esp%d: dma channel <%d>\n", esp->esp_id, esp->dma)); - ESPLOG(("bytes left to dma: %d\n", mca_get_dma_residue(esp->dma))); -} - -static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) -{ - unsigned long flags; - - - save_flags(flags); - cli(); - - mca_disable_dma(esp->dma); - mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_16 | - MCA_DMA_MODE_IO); - mca_set_dma_addr(esp->dma, addr); - mca_set_dma_count(esp->dma, length / 2); /* !!! */ - mca_enable_dma(esp->dma); - - restore_flags(flags); -} - -static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) -{ - unsigned long flags; - - - save_flags(flags); - cli(); - - mca_disable_dma(esp->dma); - mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_WRITE | - MCA_DMA_MODE_16 | MCA_DMA_MODE_IO); - mca_set_dma_addr(esp->dma, addr); - mca_set_dma_count(esp->dma, length / 2); /* !!! */ - mca_enable_dma(esp->dma); - - restore_flags(flags); -} - -static void dma_ints_off(struct NCR_ESP *esp) -{ - /* - * Tell the 'C01 to shut up. All interrupts are routed through it. - */ - - outb(inb(esp->eregs->io_addr - 0x0E) & ~0x40, - esp->eregs->io_addr - 0x0E); -} - -static void dma_ints_on(struct NCR_ESP *esp) -{ - /* - * Ok. You can speak again. - */ - - outb(inb(esp->eregs->io_addr - 0x0E) | 0x40, - esp->eregs->io_addr - 0x0E); -} - -static int dma_irq_p(struct NCR_ESP *esp) -{ - /* - * DaveM says that this should return a "yes" if there is an interrupt - * or a DMA error occurred. I copied the Amiga driver's semantics, - * though, because it seems to work and we can't really tell if - * a DMA error happened. This gives the "yes" if the scsi chip - * is sending an interrupt and no DMA activity is taking place - */ - - return (!(inb(esp->eregs->io_addr - 0x04) & 1) && - !(inb(esp->eregs->io_addr - 0x04) & 2) ); -} - -static int dma_ports_p(struct NCR_ESP *esp) -{ - /* - * Check to see if interrupts are enabled on the 'C01 (in case abort - * is entered multiple times, so we only do the abort once) - */ - - return (inb(esp->eregs->io_addr - 0x0E) & 0x40) ? 1:0; -} - -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) -{ - if(write){ - dma_init_write(esp, addr, count); - } else { - dma_init_read(esp, addr, count); - } -} - -/* - * These will not play nicely with other disk controllers that try to use the - * disk active LED... but what can you do? Don't answer that. - * - * Stolen shamelessly from ibmmca.c -- IBM Microchannel SCSI adapter driver - * - */ - -static void dma_led_on(struct NCR_ESP *esp) -{ - outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); -} - -static void dma_led_off(struct NCR_ESP *esp) -{ - outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); -} - -static struct scsi_host_template driver_template = { - .proc_name = "mca_53c9x", - .name = "NCR 53c9x SCSI", - .detect = mca_esp_detect, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .release = mca_esp_release, - .queuecommand = esp_queue, - .eh_abort_handler = esp_abort, - .eh_bus_reset_handler = esp_reset, - .can_queue = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .unchecked_isa_dma = 1, - .use_clustering = DISABLE_CLUSTERING -}; - - -#include "scsi_module.c" - -/* - * OK, here's the goods I promised. The NCR 86C01 is an MCA interface chip - * that handles enabling/diabling IRQ, dma interfacing, IO port selection - * and other fun stuff. It takes up 16 addresses, and the chip it is - * connnected to gets the following 16. Registers are as follows: - * - * Offsets 0-1 : Card ID - * - * Offset 2 : Mode enable register -- - * Bit 7 : Data Word width (1 = 16, 0 = 8) - * Bit 6 : IRQ enable (1 = enabled) - * Bits 5,4 : IRQ select - * 0 0 : IRQ 3 - * 0 1 : IRQ 5 - * 1 0 : IRQ 7 - * 1 1 : IRQ 9 - * Bits 3-1 : Base Address - * 0 0 0 : <disabled> - * 0 0 1 : 0x0240 - * 0 1 0 : 0x0340 - * 0 1 1 : 0x0400 - * 1 0 0 : 0x0420 - * 1 0 1 : 0x3240 - * 1 1 0 : 0x8240 - * 1 1 1 : 0xA240 - * Bit 0 : Card enable (1 = enabled) - * - * Offset 3 : DMA control register -- - * Bit 7 : DMA enable (1 = enabled) - * Bits 6,5 : Preemt Count Select (transfers to complete after - * 'C01 has been preempted on MCA bus) - * 0 0 : 0 - * 0 1 : 1 - * 1 0 : 3 - * 1 1 : 7 - * (all these wacky numbers; I'm sure there's a reason somewhere) - * Bit 4 : Fairness enable (1 = fair bus priority) - * Bits 3-0 : Arbitration level (0-15 consecutive) - * - * Offset 4 : General purpose register - * Bits 7-3 : User definable (here, 7,6 are SCSI ID) - * Bits 2-0 : reserved - * - * Offset 10 : DMA decode register (used for IO based DMA; also can do - * PIO through this port) - * - * Offset 12 : Status - * Bits 7-2 : reserved - * Bit 1 : DMA pending (1 = pending) - * Bit 0 : IRQ pending (0 = pending) - * - * Exciting, huh? - * - */ diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c deleted file mode 100644 index 8e5eadbd5c51..000000000000 --- a/drivers/scsi/oktagon_esp.c +++ /dev/null @@ -1,606 +0,0 @@ -/* - * Oktagon_esp.c -- Driver for bsc Oktagon - * - * Written by Carsten Pluntke 1998 - * - * Based on cyber_esp.c - */ - - -#if defined(CONFIG_AMIGA) || defined(CONFIG_APUS) -#define USE_BOTTOM_HALF -#endif - -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/blkdev.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/reboot.h> -#include <asm/system.h> -#include <asm/ptrace.h> -#include <asm/pgtable.h> - - -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "NCR53C9x.h" - -#include <linux/zorro.h> -#include <asm/irq.h> -#include <asm/amigaints.h> -#include <asm/amigahw.h> - -#ifdef USE_BOTTOM_HALF -#include <linux/workqueue.h> -#include <linux/interrupt.h> -#endif - -/* The controller registers can be found in the Z2 config area at these - * offsets: - */ -#define OKTAGON_ESP_ADDR 0x03000 -#define OKTAGON_DMA_ADDR 0x01000 - - -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_dump_state(struct NCR_ESP *esp); -static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); -static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); -static void dma_ints_off(struct NCR_ESP *esp); -static void dma_ints_on(struct NCR_ESP *esp); -static int dma_irq_p(struct NCR_ESP *esp); -static void dma_led_off(struct NCR_ESP *esp); -static void dma_led_on(struct NCR_ESP *esp); -static int dma_ports_p(struct NCR_ESP *esp); -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); - -static void dma_irq_exit(struct NCR_ESP *esp); -static void dma_invalidate(struct NCR_ESP *esp); - -static void dma_mmu_get_scsi_one(struct NCR_ESP *,Scsi_Cmnd *); -static void dma_mmu_get_scsi_sgl(struct NCR_ESP *,Scsi_Cmnd *); -static void dma_mmu_release_scsi_one(struct NCR_ESP *,Scsi_Cmnd *); -static void dma_mmu_release_scsi_sgl(struct NCR_ESP *,Scsi_Cmnd *); -static void dma_advance_sg(Scsi_Cmnd *); -static int oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x); - -#ifdef USE_BOTTOM_HALF -static void dma_commit(struct work_struct *unused); - -long oktag_to_io(long *paddr, long *addr, long len); -long oktag_from_io(long *addr, long *paddr, long len); - -static DECLARE_WORK(tq_fake_dma, dma_commit); - -#define DMA_MAXTRANSFER 0x8000 - -#else - -/* - * No bottom half. Use transfer directly from IRQ. Find a narrow path - * between too much IRQ overhead and clogging the IRQ for too long. - */ - -#define DMA_MAXTRANSFER 0x1000 - -#endif - -static struct notifier_block oktagon_notifier = { - oktagon_notify_reboot, - NULL, - 0 -}; - -static long *paddress; -static long *address; -static long len; -static long dma_on; -static int direction; -static struct NCR_ESP *current_esp; - - -static volatile unsigned char cmd_buffer[16]; - /* This is where all commands are put - * before they are trasfered to the ESP chip - * via PIO. - */ - -/***************************************************************** Detection */ -int oktagon_esp_detect(struct scsi_host_template *tpnt) -{ - struct NCR_ESP *esp; - struct zorro_dev *z = NULL; - unsigned long address; - struct ESP_regs *eregs; - - while ((z = zorro_find_device(ZORRO_PROD_BSC_OKTAGON_2008, z))) { - unsigned long board = z->resource.start; - if (request_mem_region(board+OKTAGON_ESP_ADDR, - sizeof(struct ESP_regs), "NCR53C9x")) { - /* - * It is a SCSI controller. - * Hardwire Host adapter to SCSI ID 7 - */ - - address = (unsigned long)ZTWO_VADDR(board); - eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR); - - /* This line was 5 lines lower */ - esp = esp_allocate(tpnt, (void *)board + OKTAGON_ESP_ADDR, 0); - - /* we have to shift the registers only one bit for oktagon */ - esp->shift = 1; - - esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); - udelay(5); - if (esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)) - return 0; /* Bail out if address did not hold data */ - - /* Do command transfer with programmed I/O */ - esp->do_pio_cmds = 1; - - /* Required functions */ - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = &dma_init_read; - esp->dma_init_write = &dma_init_write; - esp->dma_ints_off = &dma_ints_off; - esp->dma_ints_on = &dma_ints_on; - esp->dma_irq_p = &dma_irq_p; - esp->dma_ports_p = &dma_ports_p; - esp->dma_setup = &dma_setup; - - /* Optional functions */ - esp->dma_barrier = 0; - esp->dma_drain = 0; - esp->dma_invalidate = &dma_invalidate; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = &dma_irq_exit; - esp->dma_led_on = &dma_led_on; - esp->dma_led_off = &dma_led_off; - esp->dma_poll = 0; - esp->dma_reset = 0; - - esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; - esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; - esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one; - esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl; - esp->dma_advance_sg = &dma_advance_sg; - - /* SCSI chip speed */ - /* Looking at the quartz of the SCSI board... */ - esp->cfreq = 25000000; - - /* The DMA registers on the CyberStorm are mapped - * relative to the device (i.e. in the same Zorro - * I/O block). - */ - esp->dregs = (void *)(address + OKTAGON_DMA_ADDR); - - paddress = (long *) esp->dregs; - - /* ESP register base */ - esp->eregs = eregs; - - /* Set the command buffer */ - esp->esp_command = (volatile unsigned char*) cmd_buffer; - - /* Yes, the virtual address. See below. */ - esp->esp_command_dvma = (__u32) cmd_buffer; - - esp->irq = IRQ_AMIGA_PORTS; - request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED, - "BSC Oktagon SCSI", esp->ehost); - - /* Figure out our scsi ID on the bus */ - esp->scsi_id = 7; - - /* We don't have a differential SCSI-bus. */ - esp->diff = 0; - - esp_initialize(esp); - - printk("ESP_Oktagon Driver 1.1" -#ifdef USE_BOTTOM_HALF - " [BOTTOM_HALF]" -#else - " [IRQ]" -#endif - " registered.\n"); - printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,esps_in_use); - esps_running = esps_in_use; - current_esp = esp; - register_reboot_notifier(&oktagon_notifier); - return esps_in_use; - } - } - return 0; -} - - -/* - * On certain configurations the SCSI equipment gets confused on reboot, - * so we have to reset it then. - */ - -static int -oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x) -{ - struct NCR_ESP *esp; - - if((code == SYS_DOWN || code == SYS_HALT) && (esp = current_esp)) - { - esp_bootup_reset(esp,esp->eregs); - udelay(500); /* Settle time. Maybe unnecessary. */ - } - return NOTIFY_DONE; -} - - - -#ifdef USE_BOTTOM_HALF - - -/* - * The bsc Oktagon controller has no real DMA, so we have to do the 'DMA - * transfer' in the interrupt (Yikes!) or use a bottom half to not to clutter - * IRQ's for longer-than-good. - * - * FIXME - * BIG PROBLEM: 'len' is usually the buffer length, not the expected length - * of the data. So DMA may finish prematurely, further reads lead to - * 'machine check' on APUS systems (don't know about m68k systems, AmigaOS - * deliberately ignores the bus faults) and a normal copy-loop can't - * be exited prematurely just at the right moment by the dma_invalidate IRQ. - * So do it the hard way, write an own copier in assembler and - * catch the exception. - * -- Carsten - */ - - -static void dma_commit(struct work_struct *unused) -{ - long wait,len2,pos; - struct NCR_ESP *esp; - - ESPDATA(("Transfer: %ld bytes, Address 0x%08lX, Direction: %d\n", - len,(long) address,direction)); - dma_ints_off(current_esp); - - pos = 0; - wait = 1; - if(direction) /* write? (memory to device) */ - { - while(len > 0) - { - len2 = oktag_to_io(paddress, address+pos, len); - if(!len2) - { - if(wait > 1000) - { - printk("Expedited DMA exit (writing) %ld\n",len); - break; - } - mdelay(wait); - wait *= 2; - } - pos += len2; - len -= len2*sizeof(long); - } - } else { - while(len > 0) - { - len2 = oktag_from_io(address+pos, paddress, len); - if(!len2) - { - if(wait > 1000) - { - printk("Expedited DMA exit (reading) %ld\n",len); - break; - } - mdelay(wait); - wait *= 2; - } - pos += len2; - len -= len2*sizeof(long); - } - } - - /* to make esp->shift work */ - esp=current_esp; - -#if 0 - len2 = (esp_read(current_esp->eregs->esp_tclow) & 0xff) | - ((esp_read(current_esp->eregs->esp_tcmed) & 0xff) << 8); - - /* - * Uh uh. If you see this, len and transfer count registers were out of - * sync. That means really serious trouble. - */ - - if(len2) - printk("Eeeek!! Transfer count still %ld!\n",len2); -#endif - - /* - * Normally we just need to exit and wait for the interrupt to come. - * But at least one device (my Microtek ScanMaker 630) regularly mis- - * calculates the bytes it should send which is really ugly because - * it locks up the SCSI bus if not accounted for. - */ - - if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR)) - { - long len = 100; - long trash[10]; - - /* - * Interrupt bit was not set. Either the device is just plain lazy - * so we give it a 10 ms chance or... - */ - while(len-- && (!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR))) - udelay(100); - - - if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR)) - { - /* - * So we think that the transfer count is out of sync. Since we - * have all we want we are happy and can ditch the trash. - */ - - len = DMA_MAXTRANSFER; - - while(len-- && (!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR))) - oktag_from_io(trash,paddress,2); - - if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR)) - { - /* - * Things really have gone wrong. If we leave the system in that - * state, the SCSI bus is locked forever. I hope that this will - * turn the system in a more or less running state. - */ - printk("Device is bolixed, trying bus reset...\n"); - esp_bootup_reset(current_esp,current_esp->eregs); - } - } - } - - ESPDATA(("Transfer_finale: do_data_finale should come\n")); - - len = 0; - dma_on = 0; - dma_ints_on(current_esp); -} - -#endif - -/************************************************************* DMA Functions */ -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) -{ - /* Since the CyberStorm DMA is fully dedicated to the ESP chip, - * the number of bytes sent (to the ESP chip) equals the number - * of bytes in the FIFO - there is no buffering in the DMA controller. - * XXXX Do I read this right? It is from host to ESP, right? - */ - return fifo_count; -} - -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - unsigned long sz = sp->SCp.this_residual; - if(sz > DMA_MAXTRANSFER) - sz = DMA_MAXTRANSFER; - return sz; -} - -static void dma_dump_state(struct NCR_ESP *esp) -{ -} - -/* - * What the f$@& is this? - * - * Some SCSI devices (like my Microtek ScanMaker 630 scanner) want to transfer - * more data than requested. How much? Dunno. So ditch the bogus data into - * the sink, hoping the device will advance to the next phase sooner or later. - * - * -- Carsten - */ - -static long oktag_eva_buffer[16]; /* The data sink */ - -static void oktag_check_dma(void) -{ - struct NCR_ESP *esp; - - esp=current_esp; - if(!len) - { - address = oktag_eva_buffer; - len = 2; - /* esp_do_data sets them to zero like len */ - esp_write(current_esp->eregs->esp_tclow,2); - esp_write(current_esp->eregs->esp_tcmed,0); - } -} - -static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) -{ - /* Zorro is noncached, everything else done using processor. */ - /* cache_clear(addr, length); */ - - if(dma_on) - panic("dma_init_read while dma process is initialized/running!\n"); - direction = 0; - address = (long *) vaddress; - current_esp = esp; - len = length; - oktag_check_dma(); - dma_on = 1; -} - -static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length) -{ - /* cache_push(addr, length); */ - - if(dma_on) - panic("dma_init_write while dma process is initialized/running!\n"); - direction = 1; - address = (long *) vaddress; - current_esp = esp; - len = length; - oktag_check_dma(); - dma_on = 1; -} - -static void dma_ints_off(struct NCR_ESP *esp) -{ - disable_irq(esp->irq); -} - -static void dma_ints_on(struct NCR_ESP *esp) -{ - enable_irq(esp->irq); -} - -static int dma_irq_p(struct NCR_ESP *esp) -{ - /* It's important to check the DMA IRQ bit in the correct way! */ - return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR); -} - -static void dma_led_off(struct NCR_ESP *esp) -{ -} - -static void dma_led_on(struct NCR_ESP *esp) -{ -} - -static int dma_ports_p(struct NCR_ESP *esp) -{ - return ((amiga_custom.intenar) & IF_PORTS); -} - -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) -{ - /* On the Sparc, DMA_ST_WRITE means "move data from device to memory" - * so when (write) is true, it actually means READ! - */ - if(write){ - dma_init_read(esp, addr, count); - } else { - dma_init_write(esp, addr, count); - } -} - -/* - * IRQ entry when DMA transfer is ready to be started - */ - -static void dma_irq_exit(struct NCR_ESP *esp) -{ -#ifdef USE_BOTTOM_HALF - if(dma_on) - { - schedule_work(&tq_fake_dma); - } -#else - while(len && !dma_irq_p(esp)) - { - if(direction) - *paddress = *address++; - else - *address++ = *paddress; - len -= (sizeof(long)); - } - len = 0; - dma_on = 0; -#endif -} - -/* - * IRQ entry when DMA has just finished - */ - -static void dma_invalidate(struct NCR_ESP *esp) -{ -} - -/* - * Since the processor does the data transfer we have to use the custom - * mmu interface to pass the virtual address, not the physical. - */ - -void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - sp->SCp.ptr = - sp->request_buffer; -} - -void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - sp->SCp.ptr = sg_virt(sp->SCp.buffer); -} - -void dma_mmu_release_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ -} - -void dma_mmu_release_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ -} - -void dma_advance_sg(Scsi_Cmnd *sp) -{ - sp->SCp.ptr = sg_virt(sp->SCp.buffer); -} - - -#define HOSTS_C - -int oktagon_esp_release(struct Scsi_Host *instance) -{ -#ifdef MODULE - unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev; - esp_release(); - release_mem_region(address, sizeof(struct ESP_regs)); - free_irq(IRQ_AMIGA_PORTS, esp_intr); - unregister_reboot_notifier(&oktagon_notifier); -#endif - return 1; -} - - -static struct scsi_host_template driver_template = { - .proc_name = "esp-oktagon", - .proc_info = &esp_proc_info, - .name = "BSC Oktagon SCSI", - .detect = oktagon_esp_detect, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .release = oktagon_esp_release, - .queuecommand = esp_queue, - .eh_abort_handler = esp_abort, - .eh_bus_reset_handler = esp_reset, - .can_queue = 7, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING -}; - - -#include "scsi_module.c" - -MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/oktagon_io.S b/drivers/scsi/oktagon_io.S deleted file mode 100644 index 8a7340b02707..000000000000 --- a/drivers/scsi/oktagon_io.S +++ /dev/null @@ -1,194 +0,0 @@ -/* -*- mode: asm -*- - * Due to problems while transferring data I've put these routines as assembly - * code. - * Since I'm no PPC assembler guru, the code is just the assembler version of - -int oktag_to_io(long *paddr,long *addr,long len) -{ - long *addr2 = addr; - for(len=(len+sizeof(long)-1)/sizeof(long);len--;) - *paddr = *addr2++; - return addr2 - addr; -} - -int oktag_from_io(long *addr,long *paddr,long len) -{ - long *addr2 = addr; - for(len=(len+sizeof(long)-1)/sizeof(long);len--;) - *addr2++ = *paddr; - return addr2 - addr; -} - - * assembled using gcc -O2 -S, with two exception catch points where data - * is moved to/from the IO register. - */ - - -#ifdef CONFIG_APUS - - .file "oktagon_io.c" - -gcc2_compiled.: -/* - .section ".text" -*/ - .align 2 - .globl oktag_to_io - .type oktag_to_io,@function -oktag_to_io: - addi 5,5,3 - srwi 5,5,2 - cmpwi 1,5,0 - mr 9,3 - mr 3,4 - addi 5,5,-1 - bc 12,6,.L3 -.L5: - cmpwi 1,5,0 - lwz 0,0(3) - addi 3,3,4 - addi 5,5,-1 -exp1: stw 0,0(9) - bc 4,6,.L5 -.L3: -ret1: subf 3,4,3 - srawi 3,3,2 - blr -.Lfe1: - .size oktag_to_io,.Lfe1-oktag_to_io - .align 2 - .globl oktag_from_io - .type oktag_from_io,@function -oktag_from_io: - addi 5,5,3 - srwi 5,5,2 - cmpwi 1,5,0 - mr 9,3 - addi 5,5,-1 - bc 12,6,.L9 -.L11: - cmpwi 1,5,0 -exp2: lwz 0,0(4) - addi 5,5,-1 - stw 0,0(3) - addi 3,3,4 - bc 4,6,.L11 -.L9: -ret2: subf 3,9,3 - srawi 3,3,2 - blr -.Lfe2: - .size oktag_from_io,.Lfe2-oktag_from_io - .ident "GCC: (GNU) egcs-2.90.29 980515 (egcs-1.0.3 release)" - -/* - * Exception table. - * Second longword shows where to jump when an exception at the addr the first - * longword is pointing to is caught. - */ - -.section __ex_table,"a" - .align 2 -oktagon_except: - .long exp1,ret1 - .long exp2,ret2 - -#else - -/* -The code which follows is for 680x0 based assembler and is meant for -Linux/m68k. It was created by cross compiling the code using the -instructions given above. I then added the four labels used in the -exception handler table at the bottom of this file. -- Kevin <kcozens@interlog.com> -*/ - -#ifdef CONFIG_AMIGA - - .file "oktagon_io.c" - .version "01.01" -gcc2_compiled.: -.text - .align 2 -.globl oktag_to_io - .type oktag_to_io,@function -oktag_to_io: - link.w %a6,#0 - move.l %d2,-(%sp) - move.l 8(%a6),%a1 - move.l 12(%a6),%d1 - move.l %d1,%a0 - move.l 16(%a6),%d0 - addq.l #3,%d0 - lsr.l #2,%d0 - subq.l #1,%d0 - moveq.l #-1,%d2 - cmp.l %d0,%d2 - jbeq .L3 -.L5: -exp1: - move.l (%a0)+,(%a1) - dbra %d0,.L5 - clr.w %d0 - subq.l #1,%d0 - jbcc .L5 -.L3: -ret1: - move.l %a0,%d0 - sub.l %d1,%d0 - asr.l #2,%d0 - move.l -4(%a6),%d2 - unlk %a6 - rts - -.Lfe1: - .size oktag_to_io,.Lfe1-oktag_to_io - .align 2 -.globl oktag_from_io - .type oktag_from_io,@function -oktag_from_io: - link.w %a6,#0 - move.l %d2,-(%sp) - move.l 8(%a6),%d1 - move.l 12(%a6),%a1 - move.l %d1,%a0 - move.l 16(%a6),%d0 - addq.l #3,%d0 - lsr.l #2,%d0 - subq.l #1,%d0 - moveq.l #-1,%d2 - cmp.l %d0,%d2 - jbeq .L9 -.L11: -exp2: - move.l (%a1),(%a0)+ - dbra %d0,.L11 - clr.w %d0 - subq.l #1,%d0 - jbcc .L11 -.L9: -ret2: - move.l %a0,%d0 - sub.l %d1,%d0 - asr.l #2,%d0 - move.l -4(%a6),%d2 - unlk %a6 - rts -.Lfe2: - .size oktag_from_io,.Lfe2-oktag_from_io - .ident "GCC: (GNU) 2.7.2.1" - -/* - * Exception table. - * Second longword shows where to jump when an exception at the addr the first - * longword is pointing to is caught. - */ - -.section __ex_table,"a" - .align 2 -oktagon_except: - .long exp1,ret1 - .long exp2,ret2 - -#endif -#endif diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c index 17b4a7c4618c..0cd614a0fa73 100644 --- a/drivers/scsi/ps3rom.c +++ b/drivers/scsi/ps3rom.c @@ -35,7 +35,7 @@ #define BOUNCE_SIZE (64*1024) -#define PS3ROM_MAX_SECTORS (BOUNCE_SIZE / CD_FRAMESIZE) +#define PS3ROM_MAX_SECTORS (BOUNCE_SIZE >> 9) struct ps3rom_private { diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index adf97320574b..4894dc886b62 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -428,6 +428,19 @@ qla2x00_sysfs_read_sfp(struct kobject *kobj, if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2) return 0; + if (ha->sfp_data) + goto do_read; + + ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, + &ha->sfp_data_dma); + if (!ha->sfp_data) { + qla_printk(KERN_WARNING, ha, + "Unable to allocate memory for SFP read-data.\n"); + return 0; + } + +do_read: + memset(ha->sfp_data, 0, SFP_BLOCK_SIZE); addr = 0xa0; for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE; iter++, offset += SFP_BLOCK_SIZE) { @@ -835,7 +848,7 @@ qla2x00_get_host_port_id(struct Scsi_Host *shost) static void qla2x00_get_host_speed(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = shost_priv(shost); + scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); uint32_t speed = 0; switch (ha->link_data_rate) { @@ -848,6 +861,9 @@ qla2x00_get_host_speed(struct Scsi_Host *shost) case PORT_SPEED_4GB: speed = 4; break; + case PORT_SPEED_8GB: + speed = 8; + break; } fc_host_speed(shost) = speed; } @@ -855,7 +871,7 @@ qla2x00_get_host_speed(struct Scsi_Host *shost) static void qla2x00_get_host_port_type(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = shost_priv(shost); + scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); uint32_t port_type = FC_PORTTYPE_UNKNOWN; switch (ha->current_topology) { @@ -965,7 +981,7 @@ qla2x00_issue_lip(struct Scsi_Host *shost) static struct fc_host_statistics * qla2x00_get_fc_host_stats(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = shost_priv(shost); + scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); int rval; struct link_statistics *stats; dma_addr_t stats_dma; @@ -1049,7 +1065,7 @@ qla2x00_get_host_fabric_name(struct Scsi_Host *shost) static void qla2x00_get_host_port_state(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = shost_priv(shost); + scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); if (!ha->flags.online) fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index b72c7f170854..3750319f4968 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2041,8 +2041,6 @@ typedef struct vport_params { #define VP_RET_CODE_NO_MEM 5 #define VP_RET_CODE_NOT_FOUND 6 -#define to_qla_parent(x) (((x)->parent) ? (x)->parent : (x)) - /* * ISP operations */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index ba35fc26ce6b..193f688ec3d7 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -66,6 +66,7 @@ extern int ql2xqfullrampup; extern int num_hosts; extern int qla2x00_loop_reset(scsi_qla_host_t *); +extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); /* * Global Functions in qla_mid.c source file. diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d0633ca894be..d5c7853e7eba 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -925,6 +925,16 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) { int rval; uint32_t srisc_address = 0; + struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + unsigned long flags; + + if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) { + /* Disable SRAM, Instruction RAM and GP RAM parity. */ + spin_lock_irqsave(&ha->hardware_lock, flags); + WRT_REG_WORD(®->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); @@ -968,6 +978,19 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) } } + if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) { + /* Enable proper parity. */ + spin_lock_irqsave(&ha->hardware_lock, flags); + if (IS_QLA2300(ha)) + /* SRAM parity */ + WRT_REG_WORD(®->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)); @@ -3213,9 +3236,6 @@ int qla2x00_abort_isp(scsi_qla_host_t *ha) { int rval; - unsigned long flags = 0; - uint16_t cnt; - srb_t *sp; uint8_t status = 0; if (ha->flags.online) { @@ -3236,19 +3256,8 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) LOOP_DOWN_TIME); } - spin_lock_irqsave(&ha->hardware_lock, flags); /* Requeue all commands in outstanding command list. */ - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = ha->outstanding_cmds[cnt]; - if (sp) { - ha->outstanding_cmds[cnt] = NULL; - sp->flags = 0; - sp->cmd->result = DID_RESET << 16; - sp->cmd->host_scribble = (unsigned char *)NULL; - qla2x00_sp_compl(ha, sp); - } - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); + qla2x00_abort_all_cmds(ha, DID_RESET << 16); ha->isp_ops->get_flash_version(ha, ha->request_ring); @@ -3273,6 +3282,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags); if (ha->eft) { + memset(ha->eft, 0, EFT_SIZE); rval = qla2x00_enable_eft_trace(ha, ha->eft_dma, EFT_NUM_BUFFERS); if (rval) { @@ -3357,60 +3367,15 @@ static int qla2x00_restart_isp(scsi_qla_host_t *ha) { uint8_t status = 0; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - unsigned long flags = 0; uint32_t wait_time; /* If firmware needs to be loaded */ if (qla2x00_isp_firmware(ha)) { ha->flags.online = 0; - if (!(status = ha->isp_ops->chip_diag(ha))) { - if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - status = qla2x00_setup_chip(ha); - goto done; - } - - spin_lock_irqsave(&ha->hardware_lock, flags); - - if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha) && - !IS_QLA25XX(ha)) { - /* - * Disable SRAM, Instruction RAM and GP RAM - * parity. - */ - WRT_REG_WORD(®->hccr, - (HCCR_ENABLE_PARITY + 0x0)); - RD_REG_WORD(®->hccr); - } - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - + if (!(status = ha->isp_ops->chip_diag(ha))) status = qla2x00_setup_chip(ha); - - spin_lock_irqsave(&ha->hardware_lock, flags); - - if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha) && - !IS_QLA25XX(ha)) { - /* Enable proper parity */ - if (IS_QLA2300(ha)) - /* SRAM parity */ - WRT_REG_WORD(®->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/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 8e3b04464cff..5d1a3f7c408f 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -119,6 +119,13 @@ static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *ha) qla2x00_get_firmware_state(ha, &fw_state); } +static __inline__ scsi_qla_host_t * to_qla_parent(scsi_qla_host_t *); +static __inline__ scsi_qla_host_t * +to_qla_parent(scsi_qla_host_t *ha) +{ + return ha->parent ? ha->parent : ha; +} + /** * qla2x00_issue_marker() - Issue a Marker IOCB if necessary. * @ha: HA context diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 642a0c3f09c6..14e6f22944b7 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1815,6 +1815,8 @@ int qla2x00_request_irqs(scsi_qla_host_t *ha) { int ret; + device_reg_t __iomem *reg = ha->iobase; + unsigned long flags; /* If possible, enable MSI-X. */ if (!IS_QLA2432(ha) && !IS_QLA2532(ha)) @@ -1846,7 +1848,7 @@ qla2x00_request_irqs(scsi_qla_host_t *ha) DEBUG2(qla_printk(KERN_INFO, ha, "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision, ha->fw_attributes)); - return ret; + goto clear_risc_ints; } qla_printk(KERN_WARNING, ha, "MSI-X: Falling back-to INTa mode -- %d.\n", ret); @@ -1864,15 +1866,30 @@ skip_msi: ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler, IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha); - if (!ret) { - ha->flags.inta_enabled = 1; - ha->host->irq = ha->pdev->irq; - } else { + if (ret) { qla_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d already in use.\n", ha->pdev->irq); + goto fail; + } + ha->flags.inta_enabled = 1; + ha->host->irq = ha->pdev->irq; +clear_risc_ints: + + ha->isp_ops->disable_intrs(ha); + spin_lock_irqsave(&ha->hardware_lock, flags); + if (IS_FWI2_CAPABLE(ha)) { + WRT_REG_DWORD(®->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/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 0c10c0b0fb73..99d29fff836d 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -980,7 +980,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size) DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n", ha->host_no)); - if (ha->fw_attributes & BIT_2) + if (ha->flags.npiv_supported) mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE; else mcp->mb[0] = MBC_INITIALIZE_FIRMWARE; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 8f69caf83272..3c1b43356adb 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -204,10 +204,8 @@ static int qla2x00_do_dpc(void *data); static void qla2x00_rst_aen(scsi_qla_host_t *); -static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *); +static int qla2x00_mem_alloc(scsi_qla_host_t *); static void qla2x00_mem_free(scsi_qla_host_t *ha); -static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha); -static void qla2x00_free_sp_pool(scsi_qla_host_t *ha); static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *); /* -------------------------------------------------------------------------- */ @@ -1117,6 +1115,27 @@ qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport) return ha->isp_ops->abort_target(reset_fcport); } +void +qla2x00_abort_all_cmds(scsi_qla_host_t *ha, int res) +{ + int cnt; + unsigned long flags; + srb_t *sp; + + spin_lock_irqsave(&ha->hardware_lock, flags); + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + sp = ha->outstanding_cmds[cnt]; + if (sp) { + ha->outstanding_cmds[cnt] = NULL; + sp->flags = 0; + sp->cmd->result = res; + sp->cmd->host_scribble = (unsigned char *)NULL; + qla2x00_sp_compl(ha, sp); + } + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + static int qla2xxx_slave_alloc(struct scsi_device *sdev) { @@ -1557,10 +1576,8 @@ static int __devinit qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { int ret = -ENODEV; - device_reg_t __iomem *reg; struct Scsi_Host *host; scsi_qla_host_t *ha; - unsigned long flags = 0; char pci_info[30]; char fw_str[30]; struct scsi_host_template *sht; @@ -1608,6 +1625,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->parent = NULL; ha->bars = bars; ha->mem_only = mem_only; + spin_lock_init(&ha->hardware_lock); /* Set ISP-type information. */ qla2x00_set_isp_flags(ha); @@ -1621,8 +1639,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) "Found an ISP%04X, irq %d, iobase 0x%p\n", pdev->device, pdev->irq, ha->iobase); - spin_lock_init(&ha->hardware_lock); - ha->prev_topology = 0; ha->init_cb_size = sizeof(init_cb_t); ha->mgmt_svr_loop_id = MANAGEMENT_SERVER + ha->vp_idx; @@ -1751,34 +1767,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n", ha->host_no, ha)); - ha->isp_ops->disable_intrs(ha); - - spin_lock_irqsave(&ha->hardware_lock, flags); - reg = ha->iobase; - if (IS_FWI2_CAPABLE(ha)) { - WRT_REG_DWORD(®->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; @@ -1848,10 +1836,14 @@ qla2x00_remove_one(struct pci_dev *pdev) static void qla2x00_free_device(scsi_qla_host_t *ha) { + qla2x00_abort_all_cmds(ha, DID_NO_CONNECT << 16); + /* Disable timer */ if (ha->timer_active) qla2x00_stop_timer(ha); + ha->flags.online = 0; + /* Kill the kernel thread for this host */ if (ha->dpc_thread) { struct task_struct *t = ha->dpc_thread; @@ -1870,8 +1862,6 @@ qla2x00_free_device(scsi_qla_host_t *ha) if (ha->eft) qla2x00_disable_eft_trace(ha); - ha->flags.online = 0; - /* Stop currently executing firmware. */ qla2x00_try_to_stop_firmware(ha); @@ -2010,196 +2000,109 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer) * * Returns: * 0 = success. -* 1 = failure. +* !0 = failure. */ -static uint8_t +static int qla2x00_mem_alloc(scsi_qla_host_t *ha) { char name[16]; - uint8_t status = 1; - int retry= 10; - - do { - /* - * This will loop only once if everything goes well, else some - * number of retries will be performed to get around a kernel - * bug where available mem is not allocated until after a - * little delay and a retry. - */ - ha->request_ring = dma_alloc_coherent(&ha->pdev->dev, - (ha->request_q_length + 1) * sizeof(request_t), - &ha->request_dma, GFP_KERNEL); - if (ha->request_ring == NULL) { - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - request_ring\n"); - - qla2x00_mem_free(ha); - msleep(100); - - continue; - } - - ha->response_ring = dma_alloc_coherent(&ha->pdev->dev, - (ha->response_q_length + 1) * sizeof(response_t), - &ha->response_dma, GFP_KERNEL); - if (ha->response_ring == NULL) { - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - response_ring\n"); - - qla2x00_mem_free(ha); - msleep(100); - - continue; - } - - ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE, - &ha->gid_list_dma, GFP_KERNEL); - if (ha->gid_list == NULL) { - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - gid_list\n"); - - qla2x00_mem_free(ha); - msleep(100); - - continue; - } - - /* get consistent memory allocated for init control block */ - ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, - ha->init_cb_size, &ha->init_cb_dma, GFP_KERNEL); - if (ha->init_cb == NULL) { - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - init_cb\n"); - - qla2x00_mem_free(ha); - msleep(100); - - continue; - } - memset(ha->init_cb, 0, ha->init_cb_size); - - snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME, - ha->host_no); - ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev, - DMA_POOL_SIZE, 8, 0); - if (ha->s_dma_pool == NULL) { - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - s_dma_pool\n"); - - qla2x00_mem_free(ha); - msleep(100); - - continue; - } - - if (qla2x00_allocate_sp_pool(ha)) { - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - " - "qla2x00_allocate_sp_pool()\n"); - - qla2x00_mem_free(ha); - msleep(100); - - continue; - } - - /* Allocate memory for SNS commands */ - if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - /* Get consistent memory allocated for SNS commands */ - ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, - GFP_KERNEL); - if (ha->sns_cmd == NULL) { - /* error */ - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - sns_cmd\n"); - - qla2x00_mem_free(ha); - msleep(100); - - continue; - } - memset(ha->sns_cmd, 0, sizeof(struct sns_cmd_pkt)); - } else { - /* Get consistent memory allocated for MS IOCB */ - ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, - &ha->ms_iocb_dma); - if (ha->ms_iocb == NULL) { - /* error */ - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - ms_iocb\n"); - - qla2x00_mem_free(ha); - msleep(100); - - continue; - } - memset(ha->ms_iocb, 0, sizeof(ms_iocb_entry_t)); - - /* - * Get consistent memory allocated for CT SNS - * commands - */ - ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, - GFP_KERNEL); - if (ha->ct_sns == NULL) { - /* error */ - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - ct_sns\n"); - qla2x00_mem_free(ha); - msleep(100); + ha->request_ring = dma_alloc_coherent(&ha->pdev->dev, + (ha->request_q_length + 1) * sizeof(request_t), &ha->request_dma, + GFP_KERNEL); + if (!ha->request_ring) + goto fail; + + ha->response_ring = dma_alloc_coherent(&ha->pdev->dev, + (ha->response_q_length + 1) * sizeof(response_t), + &ha->response_dma, GFP_KERNEL); + if (!ha->response_ring) + goto fail_free_request_ring; + + ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE, + &ha->gid_list_dma, GFP_KERNEL); + if (!ha->gid_list) + goto fail_free_response_ring; + + ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, ha->init_cb_size, + &ha->init_cb_dma, GFP_KERNEL); + if (!ha->init_cb) + goto fail_free_gid_list; + + snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME, + ha->host_no); + ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev, + DMA_POOL_SIZE, 8, 0); + if (!ha->s_dma_pool) + goto fail_free_init_cb; - continue; - } - memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt)); - - if (IS_FWI2_CAPABLE(ha)) { - /* - * Get consistent memory allocated for SFP - * block. - */ - ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, - GFP_KERNEL, &ha->sfp_data_dma); - if (ha->sfp_data == NULL) { - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - " - "sfp_data\n"); - - qla2x00_mem_free(ha); - msleep(100); - - continue; - } - memset(ha->sfp_data, 0, SFP_BLOCK_SIZE); - } - } - - /* Get memory for cached NVRAM */ - ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL); - if (ha->nvram == NULL) { - /* error */ - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - nvram cache\n"); - - qla2x00_mem_free(ha); - msleep(100); - - continue; - } - - /* Done all allocations without any error. */ - status = 0; - - } while (retry-- && status != 0); + ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep); + if (!ha->srb_mempool) + goto fail_free_s_dma_pool; + + /* Get memory for cached NVRAM */ + ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL); + if (!ha->nvram) + goto fail_free_srb_mempool; + + /* Allocate memory for SNS commands */ + if (IS_QLA2100(ha) || IS_QLA2200(ha)) { + /* Get consistent memory allocated for SNS commands */ + ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, GFP_KERNEL); + if (!ha->sns_cmd) + goto fail_free_nvram; + } else { + /* Get consistent memory allocated for MS IOCB */ + ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, + &ha->ms_iocb_dma); + if (!ha->ms_iocb) + goto fail_free_nvram; - if (status) { - printk(KERN_WARNING - "%s(): **** FAILED ****\n", __func__); + /* Get consistent memory allocated for CT SNS commands */ + ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL); + if (!ha->ct_sns) + goto fail_free_ms_iocb; } - return(status); + return 0; + +fail_free_ms_iocb: + dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); + ha->ms_iocb = NULL; + ha->ms_iocb_dma = 0; +fail_free_nvram: + kfree(ha->nvram); + ha->nvram = NULL; +fail_free_srb_mempool: + mempool_destroy(ha->srb_mempool); + ha->srb_mempool = NULL; +fail_free_s_dma_pool: + dma_pool_destroy(ha->s_dma_pool); + ha->s_dma_pool = NULL; +fail_free_init_cb: + dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, + ha->init_cb_dma); + ha->init_cb = NULL; + ha->init_cb_dma = 0; +fail_free_gid_list: + dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list, + ha->gid_list_dma); + ha->gid_list = NULL; + ha->gid_list_dma = 0; +fail_free_response_ring: + dma_free_coherent(&ha->pdev->dev, (ha->response_q_length + 1) * + sizeof(response_t), ha->response_ring, ha->response_dma); + ha->response_ring = NULL; + ha->response_dma = 0; +fail_free_request_ring: + dma_free_coherent(&ha->pdev->dev, (ha->request_q_length + 1) * + sizeof(request_t), ha->request_ring, ha->request_dma); + ha->request_ring = NULL; + ha->request_dma = 0; +fail: + return -ENOMEM; } /* @@ -2215,14 +2118,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha) struct list_head *fcpl, *fcptemp; fc_port_t *fcport; - if (ha == NULL) { - /* error */ - DEBUG2(printk("%s(): ERROR invalid ha pointer.\n", __func__)); - return; - } - - /* free sp pool */ - qla2x00_free_sp_pool(ha); + if (ha->srb_mempool) + mempool_destroy(ha->srb_mempool); if (ha->fce) dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce, @@ -2270,6 +2167,7 @@ qla2x00_mem_free(scsi_qla_host_t *ha) (ha->request_q_length + 1) * sizeof(request_t), ha->request_ring, ha->request_dma); + ha->srb_mempool = NULL; ha->eft = NULL; ha->eft_dma = 0; ha->sns_cmd = NULL; @@ -2308,44 +2206,6 @@ qla2x00_mem_free(scsi_qla_host_t *ha) kfree(ha->nvram); } -/* - * qla2x00_allocate_sp_pool - * This routine is called during initialization to allocate - * memory for local srb_t. - * - * Input: - * ha = adapter block pointer. - * - * Context: - * Kernel context. - */ -static int -qla2x00_allocate_sp_pool(scsi_qla_host_t *ha) -{ - int rval; - - rval = QLA_SUCCESS; - ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep); - if (ha->srb_mempool == NULL) { - qla_printk(KERN_INFO, ha, "Unable to allocate SRB mempool.\n"); - rval = QLA_FUNCTION_FAILED; - } - return (rval); -} - -/* - * This routine frees all adapter allocated memory. - * - */ -static void -qla2x00_free_sp_pool( scsi_qla_host_t *ha) -{ - if (ha->srb_mempool) { - mempool_destroy(ha->srb_mempool); - ha->srb_mempool = NULL; - } -} - /************************************************************************** * qla2x00_do_dpc * This kernel thread is a task that is schedule by the interrupt handler @@ -2367,6 +2227,9 @@ qla2x00_do_dpc(void *data) fc_port_t *fcport; uint8_t status; uint16_t next_loopid; + struct scsi_qla_host *vha; + int i; + ha = (scsi_qla_host_t *)data; @@ -2409,6 +2272,18 @@ qla2x00_do_dpc(void *data) } clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); } + + for_each_mapped_vp_idx(ha, i) { + list_for_each_entry(vha, &ha->vp_list, + vp_list) { + if (i == vha->vp_idx) { + set_bit(ISP_ABORT_NEEDED, + &vha->dpc_flags); + break; + } + } + } + DEBUG(printk("scsi(%ld): dpc: qla2x00_abort_isp end\n", ha->host_no)); } @@ -3029,3 +2904,4 @@ MODULE_FIRMWARE(FW_FILE_ISP22XX); MODULE_FIRMWARE(FW_FILE_ISP2300); MODULE_FIRMWARE(FW_FILE_ISP2322); MODULE_FIRMWARE(FW_FILE_ISP24XX); +MODULE_FIRMWARE(FW_FILE_ISP25XX); diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index b68fb73613ed..26822c8807ee 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -893,6 +893,8 @@ qla2x00_flip_colors(scsi_qla_host_t *ha, uint16_t *pflags) } } +#define PIO_REG(h, r) ((h)->pio_address + offsetof(struct device_reg_2xxx, r)) + void qla2x00_beacon_blink(struct scsi_qla_host *ha) { @@ -902,15 +904,12 @@ qla2x00_beacon_blink(struct scsi_qla_host *ha) unsigned long flags; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - if (ha->pio_address) - reg = (struct device_reg_2xxx __iomem *)ha->pio_address; - spin_lock_irqsave(&ha->hardware_lock, flags); /* Save the Original GPIOE. */ if (ha->pio_address) { - gpio_enable = RD_REG_WORD_PIO(®->gpioe); - gpio_data = RD_REG_WORD_PIO(®->gpiod); + gpio_enable = RD_REG_WORD_PIO(PIO_REG(ha, gpioe)); + gpio_data = RD_REG_WORD_PIO(PIO_REG(ha, gpiod)); } else { gpio_enable = RD_REG_WORD(®->gpioe); gpio_data = RD_REG_WORD(®->gpiod); @@ -920,7 +919,7 @@ qla2x00_beacon_blink(struct scsi_qla_host *ha) gpio_enable |= GPIO_LED_MASK; if (ha->pio_address) { - WRT_REG_WORD_PIO(®->gpioe, gpio_enable); + WRT_REG_WORD_PIO(PIO_REG(ha, gpioe), gpio_enable); } else { WRT_REG_WORD(®->gpioe, gpio_enable); RD_REG_WORD(®->gpioe); @@ -936,7 +935,7 @@ qla2x00_beacon_blink(struct scsi_qla_host *ha) /* Set the modified gpio_data values */ if (ha->pio_address) { - WRT_REG_WORD_PIO(®->gpiod, gpio_data); + WRT_REG_WORD_PIO(PIO_REG(ha, gpiod), gpio_data); } else { WRT_REG_WORD(®->gpiod, gpio_data); RD_REG_WORD(®->gpiod); @@ -962,14 +961,11 @@ qla2x00_beacon_on(struct scsi_qla_host *ha) return QLA_FUNCTION_FAILED; } - if (ha->pio_address) - reg = (struct device_reg_2xxx __iomem *)ha->pio_address; - /* Turn off LEDs. */ spin_lock_irqsave(&ha->hardware_lock, flags); if (ha->pio_address) { - gpio_enable = RD_REG_WORD_PIO(®->gpioe); - gpio_data = RD_REG_WORD_PIO(®->gpiod); + gpio_enable = RD_REG_WORD_PIO(PIO_REG(ha, gpioe)); + gpio_data = RD_REG_WORD_PIO(PIO_REG(ha, gpiod)); } else { gpio_enable = RD_REG_WORD(®->gpioe); gpio_data = RD_REG_WORD(®->gpiod); @@ -978,7 +974,7 @@ qla2x00_beacon_on(struct scsi_qla_host *ha) /* Set the modified gpio_enable values. */ if (ha->pio_address) { - WRT_REG_WORD_PIO(®->gpioe, gpio_enable); + WRT_REG_WORD_PIO(PIO_REG(ha, gpioe), gpio_enable); } else { WRT_REG_WORD(®->gpioe, gpio_enable); RD_REG_WORD(®->gpioe); @@ -987,7 +983,7 @@ qla2x00_beacon_on(struct scsi_qla_host *ha) /* Clear out previously set LED colour. */ gpio_data &= ~GPIO_LED_MASK; if (ha->pio_address) { - WRT_REG_WORD_PIO(®->gpiod, gpio_data); + WRT_REG_WORD_PIO(PIO_REG(ha, gpiod), gpio_data); } else { WRT_REG_WORD(®->gpiod, gpio_data); RD_REG_WORD(®->gpiod); @@ -1244,13 +1240,12 @@ qla2x00_read_flash_byte(scsi_qla_host_t *ha, uint32_t addr) if (ha->pio_address) { uint16_t data2; - reg = (struct device_reg_2xxx __iomem *)ha->pio_address; - WRT_REG_WORD_PIO(®->flash_address, (uint16_t)addr); + WRT_REG_WORD_PIO(PIO_REG(ha, flash_address), (uint16_t)addr); do { - data = RD_REG_WORD_PIO(®->flash_data); + data = RD_REG_WORD_PIO(PIO_REG(ha, flash_data)); barrier(); cpu_relax(); - data2 = RD_REG_WORD_PIO(®->flash_data); + data2 = RD_REG_WORD_PIO(PIO_REG(ha, flash_data)); } while (data != data2); } else { WRT_REG_WORD(®->flash_address, (uint16_t)addr); @@ -1304,9 +1299,8 @@ qla2x00_write_flash_byte(scsi_qla_host_t *ha, uint32_t addr, uint8_t data) /* Always perform IO mapped accesses to the FLASH registers. */ if (ha->pio_address) { - reg = (struct device_reg_2xxx __iomem *)ha->pio_address; - WRT_REG_WORD_PIO(®->flash_address, (uint16_t)addr); - WRT_REG_WORD_PIO(®->flash_data, (uint16_t)data); + WRT_REG_WORD_PIO(PIO_REG(ha, flash_address), (uint16_t)addr); + WRT_REG_WORD_PIO(PIO_REG(ha, flash_data), (uint16_t)data); } else { WRT_REG_WORD(®->flash_address, (uint16_t)addr); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 2c2f6b4697c7..c5742cc15abb 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.02.00-k7" +#define QLA2XXX_VERSION "8.02.00-k8" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 2 diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 49925f92555e..10b3b9a620f3 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -1306,6 +1306,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, atomic_set(&ddb_entry->relogin_timer, 0); clear_bit(DF_RELOGIN, &ddb_entry->flags); clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); + iscsi_unblock_session(ddb_entry->sess); iscsi_session_event(ddb_entry->sess, ISCSI_KEVENT_CREATE_SESSION); /* diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 2e2b9fedffcc..c3c59d763037 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -63,8 +63,6 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, enum iscsi_param param, char *buf); static int qla4xxx_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf); -static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag); -static int qla4xxx_conn_start(struct iscsi_cls_conn *conn); static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session); /* @@ -91,6 +89,8 @@ static struct scsi_host_template qla4xxx_driver_template = { .slave_alloc = qla4xxx_slave_alloc, .slave_destroy = qla4xxx_slave_destroy, + .scan_finished = iscsi_scan_finished, + .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, @@ -116,8 +116,6 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { .get_conn_param = qla4xxx_conn_get_param, .get_session_param = qla4xxx_sess_get_param, .get_host_param = qla4xxx_host_get_param, - .start_conn = qla4xxx_conn_start, - .stop_conn = qla4xxx_conn_stop, .session_recovery_timedout = qla4xxx_recovery_timedout, }; @@ -128,48 +126,19 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) struct ddb_entry *ddb_entry = session->dd_data; struct scsi_qla_host *ha = ddb_entry->ha; - DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count of (%d) " - "secs exhausted, marking device DEAD.\n", ha->host_no, - __func__, ddb_entry->fw_ddb_index, - ha->port_down_retry_count)); - - atomic_set(&ddb_entry->state, DDB_STATE_DEAD); - - DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc flags = " - "0x%lx\n", ha->host_no, __func__, ha->dpc_flags)); - queue_work(ha->dpc_thread, &ha->dpc_work); -} - -static int qla4xxx_conn_start(struct iscsi_cls_conn *conn) -{ - struct iscsi_cls_session *session; - struct ddb_entry *ddb_entry; - - session = iscsi_dev_to_session(conn->dev.parent); - ddb_entry = session->dd_data; - - DEBUG2(printk("scsi%ld: %s: index [%d] starting conn\n", - ddb_entry->ha->host_no, __func__, - ddb_entry->fw_ddb_index)); - iscsi_unblock_session(session); - return 0; -} - -static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag) -{ - struct iscsi_cls_session *session; - struct ddb_entry *ddb_entry; + if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { + atomic_set(&ddb_entry->state, DDB_STATE_DEAD); - session = iscsi_dev_to_session(conn->dev.parent); - ddb_entry = session->dd_data; + DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count " + "of (%d) secs exhausted, marking device DEAD.\n", + ha->host_no, __func__, ddb_entry->fw_ddb_index, + ha->port_down_retry_count)); - DEBUG2(printk("scsi%ld: %s: index [%d] stopping conn\n", - ddb_entry->ha->host_no, __func__, - ddb_entry->fw_ddb_index)); - if (flag == STOP_CONN_RECOVER) - iscsi_block_session(session); - else - printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); + DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc " + "flags = 0x%lx\n", + ha->host_no, __func__, ha->dpc_flags)); + queue_work(ha->dpc_thread, &ha->dpc_work); + } } static int qla4xxx_host_get_param(struct Scsi_Host *shost, @@ -308,6 +277,9 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) DEBUG2(printk(KERN_ERR "Could not add connection.\n")); return -ENOMEM; } + + /* finally ready to go */ + iscsi_unblock_session(ddb_entry->sess); return 0; } @@ -364,6 +336,7 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n", ha->host_no, ddb_entry->bus, ddb_entry->target, ddb_entry->fw_ddb_index)); + iscsi_block_session(ddb_entry->sess); iscsi_conn_error(ddb_entry->conn, ISCSI_ERR_CONN_FAILED); } @@ -430,9 +403,21 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, { struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; + struct iscsi_cls_session *sess = ddb_entry->sess; struct srb *srb; int rval; + if (!sess) { + cmd->result = DID_IMM_RETRY << 16; + goto qc_fail_command; + } + + rval = iscsi_session_chkready(sess); + if (rval) { + cmd->result = rval; + goto qc_fail_command; + } + if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) { cmd->result = DID_NO_CONNECT << 16; @@ -1323,7 +1308,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), ha->host_no, ha->firmware_version[0], ha->firmware_version[1], ha->patch_number, ha->build_number); - + scsi_scan_host(host); return 0; remove_host: diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index b35d19472caa..fecba05b4e77 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -969,9 +969,10 @@ void starget_for_each_device(struct scsi_target *starget, void *data, EXPORT_SYMBOL(starget_for_each_device); /** - * __starget_for_each_device - helper to walk all devices of a target - * (UNLOCKED) + * __starget_for_each_device - helper to walk all devices of a target (UNLOCKED) * @starget: target whose devices we want to iterate over. + * @data: parameter for callback @fn() + * @fn: callback function that is invoked for each device * * This traverses over each device of @starget. It does _not_ * take a reference on the scsi_device, so the whole loop must be diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index f243fc30c908..135c1d054701 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -301,7 +301,6 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, page = sg_page(sg); off = sg->offset; len = sg->length; - data_len += len; while (len > 0 && data_len > 0) { /* diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 0d7b4e79415c..fac7534f3ec4 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -30,10 +30,10 @@ #include <scsi/scsi_transport_iscsi.h> #include <scsi/iscsi_if.h> -#define ISCSI_SESSION_ATTRS 18 -#define ISCSI_CONN_ATTRS 11 +#define ISCSI_SESSION_ATTRS 19 +#define ISCSI_CONN_ATTRS 13 #define ISCSI_HOST_ATTRS 4 -#define ISCSI_TRANSPORT_VERSION "2.0-867" +#define ISCSI_TRANSPORT_VERSION "2.0-868" struct iscsi_internal { int daemon_pid; @@ -127,12 +127,13 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, memset(ihost, 0, sizeof(*ihost)); INIT_LIST_HEAD(&ihost->sessions); mutex_init(&ihost->mutex); + atomic_set(&ihost->nr_scans, 0); - snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d", + snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", shost->host_no); - ihost->unbind_workq = create_singlethread_workqueue( - ihost->unbind_workq_name); - if (!ihost->unbind_workq) + ihost->scan_workq = create_singlethread_workqueue( + ihost->scan_workq_name); + if (!ihost->scan_workq) return -ENOMEM; return 0; } @@ -143,7 +144,7 @@ static int iscsi_remove_host(struct transport_container *tc, struct device *dev, struct Scsi_Host *shost = dev_to_shost(dev); struct iscsi_host *ihost = shost->shost_data; - destroy_workqueue(ihost->unbind_workq); + destroy_workqueue(ihost->scan_workq); return 0; } @@ -221,6 +222,54 @@ static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid) * The following functions can be used by LLDs that allocate * their own scsi_hosts or by software iscsi LLDs */ +static struct { + int value; + char *name; +} iscsi_session_state_names[] = { + { ISCSI_SESSION_LOGGED_IN, "LOGGED_IN" }, + { ISCSI_SESSION_FAILED, "FAILED" }, + { ISCSI_SESSION_FREE, "FREE" }, +}; + +const char *iscsi_session_state_name(int state) +{ + int i; + char *name = NULL; + + for (i = 0; i < ARRAY_SIZE(iscsi_session_state_names); i++) { + if (iscsi_session_state_names[i].value == state) { + name = iscsi_session_state_names[i].name; + break; + } + } + return name; +} + +int iscsi_session_chkready(struct iscsi_cls_session *session) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&session->lock, flags); + switch (session->state) { + case ISCSI_SESSION_LOGGED_IN: + err = 0; + break; + case ISCSI_SESSION_FAILED: + err = DID_IMM_RETRY << 16; + break; + case ISCSI_SESSION_FREE: + err = DID_NO_CONNECT << 16; + break; + default: + err = DID_NO_CONNECT << 16; + break; + } + spin_unlock_irqrestore(&session->lock, flags); + return err; +} +EXPORT_SYMBOL_GPL(iscsi_session_chkready); + static void iscsi_session_release(struct device *dev) { struct iscsi_cls_session *session = iscsi_dev_to_session(dev); @@ -236,6 +285,25 @@ static int iscsi_is_session_dev(const struct device *dev) return dev->release == iscsi_session_release; } +/** + * iscsi_scan_finished - helper to report when running scans are done + * @shost: scsi host + * @time: scan run time + * + * This function can be used by drives like qla4xxx to report to the scsi + * layer when the scans it kicked off at module load time are done. + */ +int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) +{ + struct iscsi_host *ihost = shost->shost_data; + /* + * qla4xxx will have kicked off some session unblocks before calling + * scsi_scan_host, so just wait for them to complete. + */ + return !atomic_read(&ihost->nr_scans); +} +EXPORT_SYMBOL_GPL(iscsi_scan_finished); + static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, uint id, uint lun) { @@ -254,14 +322,50 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, return 0; } +static void iscsi_scan_session(struct work_struct *work) +{ + struct iscsi_cls_session *session = + container_of(work, struct iscsi_cls_session, scan_work); + struct Scsi_Host *shost = iscsi_session_to_shost(session); + struct iscsi_host *ihost = shost->shost_data; + unsigned long flags; + + spin_lock_irqsave(&session->lock, flags); + if (session->state != ISCSI_SESSION_LOGGED_IN) { + spin_unlock_irqrestore(&session->lock, flags); + goto done; + } + spin_unlock_irqrestore(&session->lock, flags); + + scsi_scan_target(&session->dev, 0, session->target_id, + SCAN_WILD_CARD, 1); +done: + atomic_dec(&ihost->nr_scans); +} + static void session_recovery_timedout(struct work_struct *work) { struct iscsi_cls_session *session = container_of(work, struct iscsi_cls_session, recovery_work.work); + unsigned long flags; + + iscsi_cls_session_printk(KERN_INFO, session, + "session recovery timed out after %d secs\n", + session->recovery_tmo); - dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed " - "out after %d secs\n", session->recovery_tmo); + spin_lock_irqsave(&session->lock, flags); + switch (session->state) { + case ISCSI_SESSION_FAILED: + session->state = ISCSI_SESSION_FREE; + break; + case ISCSI_SESSION_LOGGED_IN: + case ISCSI_SESSION_FREE: + /* we raced with the unblock's flush */ + spin_unlock_irqrestore(&session->lock, flags); + return; + } + spin_unlock_irqrestore(&session->lock, flags); if (session->transport->session_recovery_timedout) session->transport->session_recovery_timedout(session); @@ -269,16 +373,44 @@ static void session_recovery_timedout(struct work_struct *work) scsi_target_unblock(&session->dev); } -void iscsi_unblock_session(struct iscsi_cls_session *session) +void __iscsi_unblock_session(struct iscsi_cls_session *session) { if (!cancel_delayed_work(&session->recovery_work)) flush_workqueue(iscsi_eh_timer_workq); scsi_target_unblock(&session->dev); } + +void iscsi_unblock_session(struct iscsi_cls_session *session) +{ + struct Scsi_Host *shost = iscsi_session_to_shost(session); + struct iscsi_host *ihost = shost->shost_data; + unsigned long flags; + + spin_lock_irqsave(&session->lock, flags); + session->state = ISCSI_SESSION_LOGGED_IN; + spin_unlock_irqrestore(&session->lock, flags); + + __iscsi_unblock_session(session); + /* + * Only do kernel scanning if the driver is properly hooked into + * the async scanning code (drivers like iscsi_tcp do login and + * scanning from userspace). + */ + if (shost->hostt->scan_finished) { + if (queue_work(ihost->scan_workq, &session->scan_work)) + atomic_inc(&ihost->nr_scans); + } +} EXPORT_SYMBOL_GPL(iscsi_unblock_session); void iscsi_block_session(struct iscsi_cls_session *session) { + unsigned long flags; + + spin_lock_irqsave(&session->lock, flags); + session->state = ISCSI_SESSION_FAILED; + spin_unlock_irqrestore(&session->lock, flags); + scsi_target_block(&session->dev); queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work, session->recovery_tmo * HZ); @@ -311,7 +443,7 @@ static int iscsi_unbind_session(struct iscsi_cls_session *session) struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_host *ihost = shost->shost_data; - return queue_work(ihost->unbind_workq, &session->unbind_work); + return queue_work(ihost->scan_workq, &session->unbind_work); } struct iscsi_cls_session * @@ -327,10 +459,13 @@ iscsi_alloc_session(struct Scsi_Host *shost, session->transport = transport; session->recovery_tmo = 120; + session->state = ISCSI_SESSION_FREE; INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); INIT_WORK(&session->unbind_work, __iscsi_unbind_session); + INIT_WORK(&session->scan_work, iscsi_scan_session); + spin_lock_init(&session->lock); /* this is released in the dev's release function */ scsi_host_get(shost); @@ -358,8 +493,8 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) session->sid); err = device_add(&session->dev); if (err) { - dev_printk(KERN_ERR, &session->dev, "iscsi: could not " - "register session's dev\n"); + iscsi_cls_session_printk(KERN_ERR, session, + "could not register session's dev\n"); goto release_host; } transport_register_device(&session->dev); @@ -444,22 +579,28 @@ void iscsi_remove_session(struct iscsi_cls_session *session) * If we are blocked let commands flow again. The lld or iscsi * layer should set up the queuecommand to fail commands. */ - iscsi_unblock_session(session); - iscsi_unbind_session(session); + spin_lock_irqsave(&session->lock, flags); + session->state = ISCSI_SESSION_FREE; + spin_unlock_irqrestore(&session->lock, flags); + __iscsi_unblock_session(session); + __iscsi_unbind_session(&session->unbind_work); + + /* flush running scans */ + flush_workqueue(ihost->scan_workq); /* * If the session dropped while removing devices then we need to make * sure it is not blocked */ if (!cancel_delayed_work(&session->recovery_work)) flush_workqueue(iscsi_eh_timer_workq); - flush_workqueue(ihost->unbind_workq); /* hw iscsi may not have removed all connections from session */ err = device_for_each_child(&session->dev, NULL, iscsi_iter_destroy_conn_fn); if (err) - dev_printk(KERN_ERR, &session->dev, "iscsi: Could not delete " - "all connections for session. Error %d.\n", err); + iscsi_cls_session_printk(KERN_ERR, session, + "Could not delete all connections " + "for session. Error %d.\n", err); transport_unregister_device(&session->dev); device_del(&session->dev); @@ -531,8 +672,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) conn->dev.release = iscsi_conn_release; err = device_register(&conn->dev); if (err) { - dev_printk(KERN_ERR, &conn->dev, "iscsi: could not register " - "connection's dev\n"); + iscsi_cls_session_printk(KERN_ERR, session, "could not " + "register connection's dev\n"); goto release_parent_ref; } transport_register_device(&conn->dev); @@ -639,8 +780,8 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { iscsi_conn_error(conn, ISCSI_ERR_CONN_FAILED); - dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver " - "control PDU: OOM\n"); + iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver " + "control PDU: OOM\n"); return -ENOMEM; } @@ -661,20 +802,27 @@ EXPORT_SYMBOL_GPL(iscsi_recv_pdu); void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) { + struct iscsi_cls_session *session = iscsi_conn_to_session(conn); struct nlmsghdr *nlh; struct sk_buff *skb; struct iscsi_uevent *ev; struct iscsi_internal *priv; int len = NLMSG_SPACE(sizeof(*ev)); + unsigned long flags; priv = iscsi_if_transport_lookup(conn->transport); if (!priv) return; + spin_lock_irqsave(&session->lock, flags); + if (session->state == ISCSI_SESSION_LOGGED_IN) + session->state = ISCSI_SESSION_FAILED; + spin_unlock_irqrestore(&session->lock, flags); + skb = alloc_skb(len, GFP_ATOMIC); if (!skb) { - dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored " - "conn error (%d)\n", error); + iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored " + "conn error (%d)\n", error); return; } @@ -688,8 +836,8 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) iscsi_broadcast_skb(skb, GFP_ATOMIC); - dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", - error); + iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n", + error); } EXPORT_SYMBOL_GPL(iscsi_conn_error); @@ -744,8 +892,8 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) skbstat = alloc_skb(len, GFP_ATOMIC); if (!skbstat) { - dev_printk(KERN_ERR, &conn->dev, "iscsi: can not " - "deliver stats: OOM\n"); + iscsi_cls_conn_printk(KERN_ERR, conn, "can not " + "deliver stats: OOM\n"); return -ENOMEM; } @@ -801,8 +949,9 @@ int iscsi_session_event(struct iscsi_cls_session *session, skb = alloc_skb(len, GFP_KERNEL); if (!skb) { - dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace " - "of session event %u\n", event); + iscsi_cls_session_printk(KERN_ERR, session, + "Cannot notify userspace of session " + "event %u\n", event); return -ENOMEM; } @@ -825,8 +974,8 @@ int iscsi_session_event(struct iscsi_cls_session *session, ev->r.unbind_session.sid = session->sid; break; default: - dev_printk(KERN_ERR, &session->dev, "Invalid event %u.\n", - event); + iscsi_cls_session_printk(KERN_ERR, session, "Invalid event " + "%u.\n", event); kfree_skb(skb); return -EINVAL; } @@ -837,8 +986,10 @@ int iscsi_session_event(struct iscsi_cls_session *session, */ rc = iscsi_broadcast_skb(skb, GFP_KERNEL); if (rc < 0) - dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace " - "of session event %u. Check iscsi daemon\n", event); + iscsi_cls_session_printk(KERN_ERR, session, + "Cannot notify userspace of session " + "event %u. Check iscsi daemon\n", + event); return rc; } EXPORT_SYMBOL_GPL(iscsi_session_event); @@ -871,16 +1022,15 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) session = iscsi_session_lookup(ev->u.c_conn.sid); if (!session) { - printk(KERN_ERR "iscsi: invalid session %d\n", + printk(KERN_ERR "iscsi: invalid session %d.\n", ev->u.c_conn.sid); return -EINVAL; } conn = transport->create_conn(session, ev->u.c_conn.cid); if (!conn) { - printk(KERN_ERR "iscsi: couldn't create a new " - "connection for session %d\n", - session->sid); + iscsi_cls_session_printk(KERN_ERR, session, + "couldn't create a new connection."); return -ENOMEM; } @@ -1246,6 +1396,15 @@ iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0); iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); +static ssize_t +show_priv_session_state(struct class_device *cdev, char *buf) +{ + struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); + return sprintf(buf, "%s\n", iscsi_session_state_name(session->state)); +} +static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state, + NULL); + #define iscsi_priv_session_attr_show(field, format) \ static ssize_t \ show_priv_session_##field(struct class_device *cdev, char *buf) \ @@ -1472,6 +1631,7 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO); SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO); SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); + SETUP_PRIV_SESSION_RD_ATTR(state); BUG_ON(count > ISCSI_SESSION_ATTRS); priv->session_attrs[count] = NULL; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 51a5557f42dd..37df8bbe7f46 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -929,6 +929,7 @@ static int sd_done(struct scsi_cmnd *SCpnt) unsigned int xfer_size = scsi_bufflen(SCpnt); unsigned int good_bytes = result ? 0 : xfer_size; u64 start_lba = SCpnt->request->sector; + u64 end_lba = SCpnt->request->sector + (xfer_size / 512); u64 bad_lba; struct scsi_sense_hdr sshdr; int sense_valid = 0; @@ -967,26 +968,23 @@ static int sd_done(struct scsi_cmnd *SCpnt) goto out; if (xfer_size <= SCpnt->device->sector_size) goto out; - switch (SCpnt->device->sector_size) { - case 256: + if (SCpnt->device->sector_size < 512) { + /* only legitimate sector_size here is 256 */ start_lba <<= 1; - break; - case 512: - break; - case 1024: - start_lba >>= 1; - break; - case 2048: - start_lba >>= 2; - break; - case 4096: - start_lba >>= 3; - break; - default: - /* Print something here with limiting frequency. */ - goto out; - break; + end_lba <<= 1; + } else { + /* be careful ... don't want any overflows */ + u64 factor = SCpnt->device->sector_size / 512; + do_div(start_lba, factor); + do_div(end_lba, factor); } + + if (bad_lba < start_lba || bad_lba >= end_lba) + /* the bad lba was reported incorrectly, we have + * no idea where the error is + */ + goto out; + /* This computation should always be done in terms of * the resolution of the device's medium. */ diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c new file mode 100644 index 000000000000..2a6e4f472eaa --- /dev/null +++ b/drivers/scsi/ses.c @@ -0,0 +1,689 @@ +/* + * SCSI Enclosure Services + * + * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com> + * +**----------------------------------------------------------------------------- +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** version 2 as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +**----------------------------------------------------------------------------- +*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/enclosure.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_dbg.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_driver.h> +#include <scsi/scsi_host.h> + +struct ses_device { + char *page1; + char *page2; + char *page10; + short page1_len; + short page2_len; + short page10_len; +}; + +struct ses_component { + u64 addr; + unsigned char *desc; +}; + +static int ses_probe(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + int err = -ENODEV; + + if (sdev->type != TYPE_ENCLOSURE) + goto out; + + err = 0; + sdev_printk(KERN_NOTICE, sdev, "Attached Enclosure device\n"); + + out: + return err; +} + +#define SES_TIMEOUT 30 +#define SES_RETRIES 3 + +static int ses_recv_diag(struct scsi_device *sdev, int page_code, + void *buf, int bufflen) +{ + char cmd[] = { + RECEIVE_DIAGNOSTIC, + 1, /* Set PCV bit */ + page_code, + bufflen >> 8, + bufflen & 0xff, + 0 + }; + + return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen, + NULL, SES_TIMEOUT, SES_RETRIES); +} + +static int ses_send_diag(struct scsi_device *sdev, int page_code, + void *buf, int bufflen) +{ + u32 result; + + char cmd[] = { + SEND_DIAGNOSTIC, + 0x10, /* Set PF bit */ + 0, + bufflen >> 8, + bufflen & 0xff, + 0 + }; + + result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, buf, bufflen, + NULL, SES_TIMEOUT, SES_RETRIES); + if (result) + sdev_printk(KERN_ERR, sdev, "SEND DIAGNOSTIC result: %8x\n", + result); + return result; +} + +static int ses_set_page2_descriptor(struct enclosure_device *edev, + struct enclosure_component *ecomp, + char *desc) +{ + int i, j, count = 0, descriptor = ecomp->number; + struct scsi_device *sdev = to_scsi_device(edev->cdev.dev); + struct ses_device *ses_dev = edev->scratch; + char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; + char *desc_ptr = ses_dev->page2 + 8; + + /* Clear everything */ + memset(desc_ptr, 0, ses_dev->page2_len - 8); + for (i = 0; i < ses_dev->page1[10]; i++, type_ptr += 4) { + for (j = 0; j < type_ptr[1]; j++) { + desc_ptr += 4; + if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && + type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) + continue; + if (count++ == descriptor) { + memcpy(desc_ptr, desc, 4); + /* set select */ + desc_ptr[0] |= 0x80; + /* clear reserved, just in case */ + desc_ptr[0] &= 0xf0; + } + } + } + + return ses_send_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); +} + +static char *ses_get_page2_descriptor(struct enclosure_device *edev, + struct enclosure_component *ecomp) +{ + int i, j, count = 0, descriptor = ecomp->number; + struct scsi_device *sdev = to_scsi_device(edev->cdev.dev); + struct ses_device *ses_dev = edev->scratch; + char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; + char *desc_ptr = ses_dev->page2 + 8; + + ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); + + for (i = 0; i < ses_dev->page1[10]; i++, type_ptr += 4) { + for (j = 0; j < type_ptr[1]; j++) { + desc_ptr += 4; + if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && + type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) + continue; + if (count++ == descriptor) + return desc_ptr; + } + } + return NULL; +} + +static void ses_get_fault(struct enclosure_device *edev, + struct enclosure_component *ecomp) +{ + char *desc; + + desc = ses_get_page2_descriptor(edev, ecomp); + ecomp->fault = (desc[3] & 0x60) >> 4; +} + +static int ses_set_fault(struct enclosure_device *edev, + struct enclosure_component *ecomp, + enum enclosure_component_setting val) +{ + char desc[4] = {0 }; + + switch (val) { + case ENCLOSURE_SETTING_DISABLED: + /* zero is disabled */ + break; + case ENCLOSURE_SETTING_ENABLED: + desc[2] = 0x02; + break; + default: + /* SES doesn't do the SGPIO blink settings */ + return -EINVAL; + } + + return ses_set_page2_descriptor(edev, ecomp, desc); +} + +static void ses_get_status(struct enclosure_device *edev, + struct enclosure_component *ecomp) +{ + char *desc; + + desc = ses_get_page2_descriptor(edev, ecomp); + ecomp->status = (desc[0] & 0x0f); +} + +static void ses_get_locate(struct enclosure_device *edev, + struct enclosure_component *ecomp) +{ + char *desc; + + desc = ses_get_page2_descriptor(edev, ecomp); + ecomp->locate = (desc[2] & 0x02) ? 1 : 0; +} + +static int ses_set_locate(struct enclosure_device *edev, + struct enclosure_component *ecomp, + enum enclosure_component_setting val) +{ + char desc[4] = {0 }; + + switch (val) { + case ENCLOSURE_SETTING_DISABLED: + /* zero is disabled */ + break; + case ENCLOSURE_SETTING_ENABLED: + desc[2] = 0x02; + break; + default: + /* SES doesn't do the SGPIO blink settings */ + return -EINVAL; + } + return ses_set_page2_descriptor(edev, ecomp, desc); +} + +static int ses_set_active(struct enclosure_device *edev, + struct enclosure_component *ecomp, + enum enclosure_component_setting val) +{ + char desc[4] = {0 }; + + switch (val) { + case ENCLOSURE_SETTING_DISABLED: + /* zero is disabled */ + ecomp->active = 0; + break; + case ENCLOSURE_SETTING_ENABLED: + desc[2] = 0x80; + ecomp->active = 1; + break; + default: + /* SES doesn't do the SGPIO blink settings */ + return -EINVAL; + } + return ses_set_page2_descriptor(edev, ecomp, desc); +} + +static struct enclosure_component_callbacks ses_enclosure_callbacks = { + .get_fault = ses_get_fault, + .set_fault = ses_set_fault, + .get_status = ses_get_status, + .get_locate = ses_get_locate, + .set_locate = ses_set_locate, + .set_active = ses_set_active, +}; + +struct ses_host_edev { + struct Scsi_Host *shost; + struct enclosure_device *edev; +}; + +int ses_match_host(struct enclosure_device *edev, void *data) +{ + struct ses_host_edev *sed = data; + struct scsi_device *sdev; + + if (!scsi_is_sdev_device(edev->cdev.dev)) + return 0; + + sdev = to_scsi_device(edev->cdev.dev); + + if (sdev->host != sed->shost) + return 0; + + sed->edev = edev; + return 1; +} + +static void ses_process_descriptor(struct enclosure_component *ecomp, + unsigned char *desc) +{ + int eip = desc[0] & 0x10; + int invalid = desc[0] & 0x80; + enum scsi_protocol proto = desc[0] & 0x0f; + u64 addr = 0; + struct ses_component *scomp = ecomp->scratch; + unsigned char *d; + + scomp->desc = desc; + + if (invalid) + return; + + switch (proto) { + case SCSI_PROTOCOL_SAS: + if (eip) + d = desc + 8; + else + d = desc + 4; + /* only take the phy0 addr */ + addr = (u64)d[12] << 56 | + (u64)d[13] << 48 | + (u64)d[14] << 40 | + (u64)d[15] << 32 | + (u64)d[16] << 24 | + (u64)d[17] << 16 | + (u64)d[18] << 8 | + (u64)d[19]; + break; + default: + /* FIXME: Need to add more protocols than just SAS */ + break; + } + scomp->addr = addr; +} + +struct efd { + u64 addr; + struct device *dev; +}; + +static int ses_enclosure_find_by_addr(struct enclosure_device *edev, + void *data) +{ + struct efd *efd = data; + int i; + struct ses_component *scomp; + + if (!edev->component[0].scratch) + return 0; + + for (i = 0; i < edev->components; i++) { + scomp = edev->component[i].scratch; + if (scomp->addr != efd->addr) + continue; + + enclosure_add_device(edev, i, efd->dev); + return 1; + } + return 0; +} + +#define VPD_INQUIRY_SIZE 512 + +static void ses_match_to_enclosure(struct enclosure_device *edev, + struct scsi_device *sdev) +{ + unsigned char *buf = kmalloc(VPD_INQUIRY_SIZE, GFP_KERNEL); + unsigned char *desc; + int len; + struct efd efd = { + .addr = 0, + }; + unsigned char cmd[] = { + INQUIRY, + 1, + 0x83, + VPD_INQUIRY_SIZE >> 8, + VPD_INQUIRY_SIZE & 0xff, + 0 + }; + + if (!buf) + return; + + if (scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, + VPD_INQUIRY_SIZE, NULL, SES_TIMEOUT, SES_RETRIES)) + goto free; + + len = (buf[2] << 8) + buf[3]; + desc = buf + 4; + while (desc < buf + len) { + enum scsi_protocol proto = desc[0] >> 4; + u8 code_set = desc[0] & 0x0f; + u8 piv = desc[1] & 0x80; + u8 assoc = (desc[1] & 0x30) >> 4; + u8 type = desc[1] & 0x0f; + u8 len = desc[3]; + + if (piv && code_set == 1 && assoc == 1 && code_set == 1 + && proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8) + efd.addr = (u64)desc[4] << 56 | + (u64)desc[5] << 48 | + (u64)desc[6] << 40 | + (u64)desc[7] << 32 | + (u64)desc[8] << 24 | + (u64)desc[9] << 16 | + (u64)desc[10] << 8 | + (u64)desc[11]; + + desc += len + 4; + } + if (!efd.addr) + goto free; + + efd.dev = &sdev->sdev_gendev; + + enclosure_for_each_device(ses_enclosure_find_by_addr, &efd); + free: + kfree(buf); +} + +#define INIT_ALLOC_SIZE 32 + +static int ses_intf_add(struct class_device *cdev, + struct class_interface *intf) +{ + struct scsi_device *sdev = to_scsi_device(cdev->dev); + struct scsi_device *tmp_sdev; + unsigned char *buf = NULL, *hdr_buf, *type_ptr, *desc_ptr, + *addl_desc_ptr; + struct ses_device *ses_dev; + u32 result; + int i, j, types, len, components = 0; + int err = -ENOMEM; + struct enclosure_device *edev; + struct ses_component *scomp; + + if (!scsi_device_enclosure(sdev)) { + /* not an enclosure, but might be in one */ + edev = enclosure_find(&sdev->host->shost_gendev); + if (edev) { + ses_match_to_enclosure(edev, sdev); + class_device_put(&edev->cdev); + } + return -ENODEV; + } + + /* TYPE_ENCLOSURE prints a message in probe */ + if (sdev->type != TYPE_ENCLOSURE) + sdev_printk(KERN_NOTICE, sdev, "Embedded Enclosure Device\n"); + + ses_dev = kzalloc(sizeof(*ses_dev), GFP_KERNEL); + hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); + if (!hdr_buf || !ses_dev) + goto err_init_free; + + result = ses_recv_diag(sdev, 1, hdr_buf, INIT_ALLOC_SIZE); + if (result) + goto recv_failed; + + if (hdr_buf[1] != 0) { + /* FIXME: need subenclosure support; I've just never + * seen a device with subenclosures and it makes the + * traversal routines more complex */ + sdev_printk(KERN_ERR, sdev, + "FIXME driver has no support for subenclosures (%d)\n", + buf[1]); + goto err_free; + } + + len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; + buf = kzalloc(len, GFP_KERNEL); + if (!buf) + goto err_free; + + ses_dev->page1 = buf; + ses_dev->page1_len = len; + + result = ses_recv_diag(sdev, 1, buf, len); + if (result) + goto recv_failed; + + types = buf[10]; + len = buf[11]; + + type_ptr = buf + 12 + len; + + for (i = 0; i < types; i++, type_ptr += 4) { + if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || + type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) + components += type_ptr[1]; + } + + result = ses_recv_diag(sdev, 2, hdr_buf, INIT_ALLOC_SIZE); + if (result) + goto recv_failed; + + len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; + buf = kzalloc(len, GFP_KERNEL); + if (!buf) + goto err_free; + + /* make sure getting page 2 actually works */ + result = ses_recv_diag(sdev, 2, buf, len); + if (result) + goto recv_failed; + ses_dev->page2 = buf; + ses_dev->page2_len = len; + + /* The additional information page --- allows us + * to match up the devices */ + result = ses_recv_diag(sdev, 10, hdr_buf, INIT_ALLOC_SIZE); + if (result) + goto no_page10; + + len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; + buf = kzalloc(len, GFP_KERNEL); + if (!buf) + goto err_free; + + result = ses_recv_diag(sdev, 10, buf, len); + if (result) + goto recv_failed; + ses_dev->page10 = buf; + ses_dev->page10_len = len; + + no_page10: + scomp = kmalloc(sizeof(struct ses_component) * components, GFP_KERNEL); + if (!scomp) + goto err_free; + + edev = enclosure_register(cdev->dev, sdev->sdev_gendev.bus_id, + components, &ses_enclosure_callbacks); + if (IS_ERR(edev)) { + err = PTR_ERR(edev); + goto err_free; + } + + edev->scratch = ses_dev; + for (i = 0; i < components; i++) + edev->component[i].scratch = scomp++; + + /* Page 7 for the descriptors is optional */ + buf = NULL; + result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE); + if (result) + goto simple_populate; + + len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; + /* add 1 for trailing '\0' we'll use */ + buf = kzalloc(len + 1, GFP_KERNEL); + result = ses_recv_diag(sdev, 7, buf, len); + if (result) { + simple_populate: + kfree(buf); + buf = NULL; + desc_ptr = NULL; + addl_desc_ptr = NULL; + } else { + desc_ptr = buf + 8; + len = (desc_ptr[2] << 8) + desc_ptr[3]; + /* skip past overall descriptor */ + desc_ptr += len + 4; + addl_desc_ptr = ses_dev->page10 + 8; + } + type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; + components = 0; + for (i = 0; i < types; i++, type_ptr += 4) { + for (j = 0; j < type_ptr[1]; j++) { + char *name = NULL; + struct enclosure_component *ecomp; + + if (desc_ptr) { + len = (desc_ptr[2] << 8) + desc_ptr[3]; + desc_ptr += 4; + /* Add trailing zero - pushes into + * reserved space */ + desc_ptr[len] = '\0'; + name = desc_ptr; + } + if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && + type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) + continue; + ecomp = enclosure_component_register(edev, + components++, + type_ptr[0], + name); + if (desc_ptr) { + desc_ptr += len; + if (!IS_ERR(ecomp)) + ses_process_descriptor(ecomp, + addl_desc_ptr); + + if (addl_desc_ptr) + addl_desc_ptr += addl_desc_ptr[1] + 2; + } + } + } + kfree(buf); + kfree(hdr_buf); + + /* see if there are any devices matching before + * we found the enclosure */ + shost_for_each_device(tmp_sdev, sdev->host) { + if (tmp_sdev->lun != 0 || scsi_device_enclosure(tmp_sdev)) + continue; + ses_match_to_enclosure(edev, tmp_sdev); + } + + return 0; + + recv_failed: + sdev_printk(KERN_ERR, sdev, "Failed to get diagnostic page 0x%x\n", + result); + err = -ENODEV; + err_free: + kfree(buf); + kfree(ses_dev->page10); + kfree(ses_dev->page2); + kfree(ses_dev->page1); + err_init_free: + kfree(ses_dev); + kfree(hdr_buf); + sdev_printk(KERN_ERR, sdev, "Failed to bind enclosure %d\n", err); + return err; +} + +static int ses_remove(struct device *dev) +{ + return 0; +} + +static void ses_intf_remove(struct class_device *cdev, + struct class_interface *intf) +{ + struct scsi_device *sdev = to_scsi_device(cdev->dev); + struct enclosure_device *edev; + struct ses_device *ses_dev; + + if (!scsi_device_enclosure(sdev)) + return; + + edev = enclosure_find(cdev->dev); + if (!edev) + return; + + ses_dev = edev->scratch; + edev->scratch = NULL; + + kfree(ses_dev->page1); + kfree(ses_dev->page2); + kfree(ses_dev); + + kfree(edev->component[0].scratch); + + class_device_put(&edev->cdev); + enclosure_unregister(edev); +} + +static struct class_interface ses_interface = { + .add = ses_intf_add, + .remove = ses_intf_remove, +}; + +static struct scsi_driver ses_template = { + .owner = THIS_MODULE, + .gendrv = { + .name = "ses", + .probe = ses_probe, + .remove = ses_remove, + }, +}; + +static int __init ses_init(void) +{ + int err; + + err = scsi_register_interface(&ses_interface); + if (err) + return err; + + err = scsi_register_driver(&ses_template.gendrv); + if (err) + goto out_unreg; + + return 0; + + out_unreg: + scsi_unregister_interface(&ses_interface); + return err; +} + +static void __exit ses_exit(void) +{ + scsi_unregister_driver(&ses_template.gendrv); + scsi_unregister_interface(&ses_interface); +} + +module_init(ses_init); +module_exit(ses_exit); + +MODULE_ALIAS_SCSI_DEVICE(TYPE_ENCLOSURE); + +MODULE_AUTHOR("James Bottomley"); +MODULE_DESCRIPTION("SCSI Enclosure Services (ses) driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index aba28f335b88..e5156aa6dd20 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1160,23 +1160,22 @@ sg_fasync(int fd, struct file *filp, int mode) return (retval < 0) ? retval : 0; } -static struct page * -sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type) +static int +sg_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { Sg_fd *sfp; - struct page *page = NOPAGE_SIGBUS; unsigned long offset, len, sa; Sg_scatter_hold *rsv_schp; struct scatterlist *sg; int k; if ((NULL == vma) || (!(sfp = (Sg_fd *) vma->vm_private_data))) - return page; + return VM_FAULT_SIGBUS; rsv_schp = &sfp->reserve; - offset = addr - vma->vm_start; + offset = vmf->pgoff << PAGE_SHIFT; if (offset >= rsv_schp->bufflen) - return page; - SCSI_LOG_TIMEOUT(3, printk("sg_vma_nopage: offset=%lu, scatg=%d\n", + return VM_FAULT_SIGBUS; + SCSI_LOG_TIMEOUT(3, printk("sg_vma_fault: offset=%lu, scatg=%d\n", offset, rsv_schp->k_use_sg)); sg = rsv_schp->buffer; sa = vma->vm_start; @@ -1185,21 +1184,21 @@ sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type) len = vma->vm_end - sa; len = (len < sg->length) ? len : sg->length; if (offset < len) { + struct page *page; page = virt_to_page(page_address(sg_page(sg)) + offset); get_page(page); /* increment page count */ - break; + vmf->page = page; + return 0; /* success */ } sa += len; offset -= len; } - if (type) - *type = VM_FAULT_MINOR; - return page; + return VM_FAULT_SIGBUS; } static struct vm_operations_struct sg_mmap_vm_ops = { - .nopage = sg_vma_nopage, + .fault = sg_vma_fault, }; static int diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 50ba49250203..208565bdbe8e 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -163,6 +163,29 @@ static void scsi_cd_put(struct scsi_cd *cd) mutex_unlock(&sr_ref_mutex); } +/* identical to scsi_test_unit_ready except that it doesn't + * eat the NOT_READY returns for removable media */ +int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr) +{ + int retries = MAX_RETRIES; + int the_result; + u8 cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0 }; + + /* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION + * conditions are gone, or a timeout happens + */ + do { + the_result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, + 0, sshdr, SR_TIMEOUT, + retries--); + + } while (retries > 0 && + (!scsi_status_is_good(the_result) || + (scsi_sense_valid(sshdr) && + sshdr->sense_key == UNIT_ATTENTION))); + return the_result; +} + /* * This function checks to see if the media has been changed in the * CDROM drive. It is possible that we have already sensed a change, @@ -185,8 +208,7 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot) } sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); - retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, - sshdr); + retval = sr_test_unit_ready(cd->device, sshdr); if (retval || (scsi_sense_valid(sshdr) && /* 0x3a is medium not present */ sshdr->asc == 0x3a)) { @@ -733,10 +755,8 @@ static void get_capabilities(struct scsi_cd *cd) { unsigned char *buffer; struct scsi_mode_data data; - unsigned char cmd[MAX_COMMAND_SIZE]; struct scsi_sense_hdr sshdr; - unsigned int the_result; - int retries, rc, n; + int rc, n; static const char *loadmech[] = { @@ -758,23 +778,8 @@ static void get_capabilities(struct scsi_cd *cd) return; } - /* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION - * conditions are gone, or a timeout happens - */ - retries = 0; - do { - memset((void *)cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - the_result = scsi_execute_req (cd->device, cmd, DMA_NONE, NULL, - 0, &sshdr, SR_TIMEOUT, - MAX_RETRIES); - - retries++; - } while (retries < 5 && - (!scsi_status_is_good(the_result) || - (scsi_sense_valid(&sshdr) && - sshdr.sense_key == UNIT_ATTENTION))); + /* eat unit attentions */ + sr_test_unit_ready(cd->device, &sshdr); /* ask for mode page 0x2a */ rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h index 81fbc0b78a52..1e144dfdbd4b 100644 --- a/drivers/scsi/sr.h +++ b/drivers/scsi/sr.h @@ -61,6 +61,7 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed); int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); int sr_is_xa(Scsi_CD *); +int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr); /* sr_vendor.c */ void sr_vendor_init(Scsi_CD *); diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index d5cebff1d646..ae87d08df588 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -306,8 +306,7 @@ int sr_drive_status(struct cdrom_device_info *cdi, int slot) /* we have no changer support */ return -EINVAL; } - if (0 == scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, - &sshdr)) + if (0 == sr_test_unit_ready(cd->device, &sshdr)) return CDS_DISC_OK; if (!cdrom_get_media_event(cdi, &med)) { diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index 1bc41907a038..06152c7fa689 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -1,392 +1,316 @@ -/* sun3x_esp.c: EnhancedScsiProcessor Sun3x SCSI driver code. +/* sun3x_esp.c: ESP front-end for Sun3x systems. * - * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de) - * - * Based on David S. Miller's esp driver + * Copyright (C) 2007,2008 Thomas Bogendoerfer (tsbogend@alpha.franken.de) */ #include <linux/kernel.h> #include <linux/types.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/blkdev.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> #include <linux/delay.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> #include <linux/interrupt.h> -#include "scsi.h" -#include <scsi/scsi_host.h> -#include "NCR53C9x.h" - #include <asm/sun3x.h> +#include <asm/io.h> +#include <asm/dma.h> #include <asm/dvma.h> -#include <asm/irq.h> - -static void dma_barrier(struct NCR_ESP *esp); -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_drain(struct NCR_ESP *esp); -static void dma_invalidate(struct NCR_ESP *esp); -static void dma_dump_state(struct NCR_ESP *esp); -static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); -static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); -static void dma_ints_off(struct NCR_ESP *esp); -static void dma_ints_on(struct NCR_ESP *esp); -static int dma_irq_p(struct NCR_ESP *esp); -static void dma_poll(struct NCR_ESP *esp, unsigned char *vaddr); -static int dma_ports_p(struct NCR_ESP *esp); -static void dma_reset(struct NCR_ESP *esp); -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); -static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp); -static void dma_advance_sg (Scsi_Cmnd *sp); - -/* Detecting ESP chips on the machine. This is the simple and easy - * version. - */ -int sun3x_esp_detect(struct scsi_host_template *tpnt) -{ - struct NCR_ESP *esp; - struct ConfigDev *esp_dev; - - esp_dev = 0; - esp = esp_allocate(tpnt, esp_dev, 0); - - /* Do command transfer with DMA */ - esp->do_pio_cmds = 0; - - /* Required functions */ - esp->dma_bytes_sent = &dma_bytes_sent; - esp->dma_can_transfer = &dma_can_transfer; - esp->dma_dump_state = &dma_dump_state; - esp->dma_init_read = &dma_init_read; - esp->dma_init_write = &dma_init_write; - esp->dma_ints_off = &dma_ints_off; - esp->dma_ints_on = &dma_ints_on; - esp->dma_irq_p = &dma_irq_p; - esp->dma_ports_p = &dma_ports_p; - esp->dma_setup = &dma_setup; - - /* Optional functions */ - esp->dma_barrier = &dma_barrier; - esp->dma_invalidate = &dma_invalidate; - esp->dma_drain = &dma_drain; - esp->dma_irq_entry = 0; - esp->dma_irq_exit = 0; - esp->dma_led_on = 0; - esp->dma_led_off = 0; - esp->dma_poll = &dma_poll; - esp->dma_reset = &dma_reset; - - /* virtual DMA functions */ - esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; - esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; - esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one; - esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl; - esp->dma_advance_sg = &dma_advance_sg; - - /* SCSI chip speed */ - esp->cfreq = 20000000; - esp->eregs = (struct ESP_regs *)(SUN3X_ESP_BASE); - esp->dregs = (void *)SUN3X_ESP_DMA; - esp->esp_command = (volatile unsigned char *)dvma_malloc(DVMA_PAGE_SIZE); - esp->esp_command_dvma = dvma_vtob((unsigned long)esp->esp_command); - - esp->irq = 2; - if (request_irq(esp->irq, esp_intr, IRQF_DISABLED, - "SUN3X SCSI", esp->ehost)) { - esp_deallocate(esp); - return 0; - } +/* DMA controller reg offsets */ +#define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */ +#define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */ +#define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */ +#define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */ - esp->scsi_id = 7; - esp->diff = 0; +#include <scsi/scsi_host.h> - esp_initialize(esp); +#include "esp_scsi.h" - /* for reasons beyond my knowledge (and which should likely be fixed) - sync mode doesn't work on a 3/80 at 5mhz. but it does at 4. */ - esp->sync_defp = 0x3f; +#define DRV_MODULE_NAME "sun3x_esp" +#define PFX DRV_MODULE_NAME ": " +#define DRV_VERSION "1.000" +#define DRV_MODULE_RELDATE "Nov 1, 2007" - printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, - esps_in_use); - esps_running = esps_in_use; - return esps_in_use; +/* + * m68k always assumes readl/writel operate on little endian + * mmio space; this is wrong at least for Sun3x, so we + * need to workaround this until a proper way is found + */ +#if 0 +#define dma_read32(REG) \ + readl(esp->dma_regs + (REG)) +#define dma_write32(VAL, REG) \ + writel((VAL), esp->dma_regs + (REG)) +#else +#define dma_read32(REG) \ + *(volatile u32 *)(esp->dma_regs + (REG)) +#define dma_write32(VAL, REG) \ + do { *(volatile u32 *)(esp->dma_regs + (REG)) = (VAL); } while (0) +#endif + +static void sun3x_esp_write8(struct esp *esp, u8 val, unsigned long reg) +{ + writeb(val, esp->regs + (reg * 4UL)); } -static void dma_do_drain(struct NCR_ESP *esp) +static u8 sun3x_esp_read8(struct esp *esp, unsigned long reg) { - struct sparc_dma_registers *dregs = - (struct sparc_dma_registers *) esp->dregs; - - int count = 500000; - - while((dregs->cond_reg & DMA_PEND_READ) && (--count > 0)) - udelay(1); - - if(!count) { - printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); - } - - dregs->cond_reg |= DMA_FIFO_STDRAIN; - - count = 500000; - - while((dregs->cond_reg & DMA_FIFO_ISDRAIN) && (--count > 0)) - udelay(1); - - if(!count) { - printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); - } - + return readb(esp->regs + (reg * 4UL)); } - -static void dma_barrier(struct NCR_ESP *esp) + +static dma_addr_t sun3x_esp_map_single(struct esp *esp, void *buf, + size_t sz, int dir) { - struct sparc_dma_registers *dregs = - (struct sparc_dma_registers *) esp->dregs; - int count = 500000; - - while((dregs->cond_reg & DMA_PEND_READ) && (--count > 0)) - udelay(1); - - if(!count) { - printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); - } - - dregs->cond_reg &= ~(DMA_ENABLE); + return dma_map_single(esp->dev, buf, sz, dir); } -/* This uses various DMA csr fields and the fifo flags count value to - * determine how many bytes were successfully sent/received by the ESP. - */ -static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +static int sun3x_esp_map_sg(struct esp *esp, struct scatterlist *sg, + int num_sg, int dir) { - struct sparc_dma_registers *dregs = - (struct sparc_dma_registers *) esp->dregs; - - int rval = dregs->st_addr - esp->esp_command_dvma; - - return rval - fifo_count; + return dma_map_sg(esp->dev, sg, num_sg, dir); } -static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) +static void sun3x_esp_unmap_single(struct esp *esp, dma_addr_t addr, + size_t sz, int dir) { - return sp->SCp.this_residual; + dma_unmap_single(esp->dev, addr, sz, dir); } -static void dma_drain(struct NCR_ESP *esp) +static void sun3x_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, + int num_sg, int dir) { - struct sparc_dma_registers *dregs = - (struct sparc_dma_registers *) esp->dregs; - int count = 500000; - - if(dregs->cond_reg & DMA_FIFO_ISDRAIN) { - dregs->cond_reg |= DMA_FIFO_STDRAIN; - while((dregs->cond_reg & DMA_FIFO_ISDRAIN) && (--count > 0)) - udelay(1); - if(!count) { - printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); - } - - } + dma_unmap_sg(esp->dev, sg, num_sg, dir); } -static void dma_invalidate(struct NCR_ESP *esp) +static int sun3x_esp_irq_pending(struct esp *esp) { - struct sparc_dma_registers *dregs = - (struct sparc_dma_registers *) esp->dregs; - - __u32 tmp; - int count = 500000; - - while(((tmp = dregs->cond_reg) & DMA_PEND_READ) && (--count > 0)) - udelay(1); + if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) + return 1; + return 0; +} - if(!count) { - printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); - } +static void sun3x_esp_reset_dma(struct esp *esp) +{ + u32 val; - dregs->cond_reg = tmp | DMA_FIFO_INV; - dregs->cond_reg &= ~DMA_FIFO_INV; + val = dma_read32(DMA_CSR); + dma_write32(val | DMA_RST_SCSI, DMA_CSR); + dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); + /* Enable interrupts. */ + val = dma_read32(DMA_CSR); + dma_write32(val | DMA_INT_ENAB, DMA_CSR); } -static void dma_dump_state(struct NCR_ESP *esp) +static void sun3x_esp_dma_drain(struct esp *esp) { - struct sparc_dma_registers *dregs = - (struct sparc_dma_registers *) esp->dregs; + u32 csr; + int lim; - ESPLOG(("esp%d: dma -- cond_reg<%08lx> addr<%08lx>\n", - esp->esp_id, dregs->cond_reg, dregs->st_addr)); -} + csr = dma_read32(DMA_CSR); + if (!(csr & DMA_FIFO_ISDRAIN)) + return; -static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) -{ - struct sparc_dma_registers *dregs = - (struct sparc_dma_registers *) esp->dregs; + dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR); - dregs->st_addr = vaddress; - dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE); + lim = 1000; + while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) { + if (--lim == 0) { + printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n", + esp->host->unique_id); + break; + } + udelay(1); + } } -static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length) +static void sun3x_esp_dma_invalidate(struct esp *esp) { - struct sparc_dma_registers *dregs = - (struct sparc_dma_registers *) esp->dregs; - - /* Set up the DMA counters */ + u32 val; + int lim; + + lim = 1000; + while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) { + if (--lim == 0) { + printk(KERN_ALERT PFX "esp%d: DMA will not " + "invalidate!\n", esp->host->unique_id); + break; + } + udelay(1); + } - dregs->st_addr = vaddress; - dregs->cond_reg = ((dregs->cond_reg & ~(DMA_ST_WRITE)) | DMA_ENABLE); + val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); + val |= DMA_FIFO_INV; + dma_write32(val, DMA_CSR); + val &= ~DMA_FIFO_INV; + dma_write32(val, DMA_CSR); } -static void dma_ints_off(struct NCR_ESP *esp) +static void sun3x_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, + u32 dma_count, int write, u8 cmd) { - DMA_INTSOFF((struct sparc_dma_registers *) esp->dregs); + u32 csr; + + BUG_ON(!(cmd & ESP_CMD_DMA)); + + sun3x_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); + sun3x_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); + csr = dma_read32(DMA_CSR); + csr |= DMA_ENABLE; + if (write) + csr |= DMA_ST_WRITE; + else + csr &= ~DMA_ST_WRITE; + dma_write32(csr, DMA_CSR); + dma_write32(addr, DMA_ADDR); + + scsi_esp_cmd(esp, cmd); } -static void dma_ints_on(struct NCR_ESP *esp) +static int sun3x_esp_dma_error(struct esp *esp) { - DMA_INTSON((struct sparc_dma_registers *) esp->dregs); -} + u32 csr = dma_read32(DMA_CSR); -static int dma_irq_p(struct NCR_ESP *esp) -{ - return DMA_IRQ_P((struct sparc_dma_registers *) esp->dregs); + if (csr & DMA_HNDL_ERROR) + return 1; + + return 0; } -static void dma_poll(struct NCR_ESP *esp, unsigned char *vaddr) +static const struct esp_driver_ops sun3x_esp_ops = { + .esp_write8 = sun3x_esp_write8, + .esp_read8 = sun3x_esp_read8, + .map_single = sun3x_esp_map_single, + .map_sg = sun3x_esp_map_sg, + .unmap_single = sun3x_esp_unmap_single, + .unmap_sg = sun3x_esp_unmap_sg, + .irq_pending = sun3x_esp_irq_pending, + .reset_dma = sun3x_esp_reset_dma, + .dma_drain = sun3x_esp_dma_drain, + .dma_invalidate = sun3x_esp_dma_invalidate, + .send_dma_cmd = sun3x_esp_send_dma_cmd, + .dma_error = sun3x_esp_dma_error, +}; + +static int __devinit esp_sun3x_probe(struct platform_device *dev) { - int count = 50; - dma_do_drain(esp); + struct scsi_host_template *tpnt = &scsi_esp_template; + struct Scsi_Host *host; + struct esp *esp; + struct resource *res; + int err = -ENOMEM; - /* Wait till the first bits settle. */ - while((*(volatile unsigned char *)vaddr == 0xff) && (--count > 0)) - udelay(1); + host = scsi_host_alloc(tpnt, sizeof(struct esp)); + if (!host) + goto fail; - if(!count) { -// printk("%s:%d timeout expire (data %02x)\n", __FILE__, __LINE__, -// esp_read(esp->eregs->esp_fdata)); - //mach_halt(); - vaddr[0] = esp_read(esp->eregs->esp_fdata); - vaddr[1] = esp_read(esp->eregs->esp_fdata); - } + host->max_id = 8; + esp = shost_priv(host); -} + esp->host = host; + esp->dev = dev; + esp->ops = &sun3x_esp_ops; -static int dma_ports_p(struct NCR_ESP *esp) -{ - return (((struct sparc_dma_registers *) esp->dregs)->cond_reg - & DMA_INT_ENAB); -} + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res && !res->start) + goto fail_unlink; -/* Resetting various pieces of the ESP scsi driver chipset/buses. */ -static void dma_reset(struct NCR_ESP *esp) -{ - struct sparc_dma_registers *dregs = - (struct sparc_dma_registers *)esp->dregs; + esp->regs = ioremap_nocache(res->start, 0x20); + if (!esp->regs) + goto fail_unmap_regs; - /* Punt the DVMA into a known state. */ - dregs->cond_reg |= DMA_RST_SCSI; - dregs->cond_reg &= ~(DMA_RST_SCSI); - DMA_INTSON(dregs); -} + res = platform_get_resource(dev, IORESOURCE_MEM, 1); + if (!res && !res->start) + goto fail_unmap_regs; -static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) -{ - struct sparc_dma_registers *dregs = - (struct sparc_dma_registers *) esp->dregs; - unsigned long nreg = dregs->cond_reg; + esp->dma_regs = ioremap_nocache(res->start, 0x10); -// printk("dma_setup %c addr %08x cnt %08x\n", -// write ? 'W' : 'R', addr, count); + esp->command_block = dma_alloc_coherent(esp->dev, 16, + &esp->command_block_dma, + GFP_KERNEL); + if (!esp->command_block) + goto fail_unmap_regs_dma; - dma_do_drain(esp); + host->irq = platform_get_irq(dev, 0); + err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, + "SUN3X ESP", esp); + if (err < 0) + goto fail_unmap_command_block; - if(write) - nreg |= DMA_ST_WRITE; - else { - nreg &= ~(DMA_ST_WRITE); - } - - nreg |= DMA_ENABLE; - dregs->cond_reg = nreg; - dregs->st_addr = addr; -} + esp->scsi_id = 7; + esp->host->this_id = esp->scsi_id; + esp->scsi_id_mask = (1 << esp->scsi_id); + esp->cfreq = 20000000; -static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - sp->SCp.have_data_in = dvma_map((unsigned long)sp->SCp.buffer, - sp->SCp.this_residual); - sp->SCp.ptr = (char *)((unsigned long)sp->SCp.have_data_in); + dev_set_drvdata(&dev->dev, esp); + + err = scsi_esp_register(esp, &dev->dev); + if (err) + goto fail_free_irq; + + return 0; + +fail_free_irq: + free_irq(host->irq, esp); +fail_unmap_command_block: + dma_free_coherent(esp->dev, 16, + esp->command_block, + esp->command_block_dma); +fail_unmap_regs_dma: + iounmap(esp->dma_regs); +fail_unmap_regs: + iounmap(esp->regs); +fail_unlink: + scsi_host_put(host); +fail: + return err; } -static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp) +static int __devexit esp_sun3x_remove(struct platform_device *dev) { - int sz = sp->SCp.buffers_residual; - struct scatterlist *sg = sp->SCp.buffer; - - while (sz >= 0) { - sg[sz].dma_address = dvma_map((unsigned long)sg_virt(&sg[sz]), - sg[sz].length); - sz--; - } - sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dma_address); -} + struct esp *esp = dev_get_drvdata(&dev->dev); + unsigned int irq = esp->host->irq; + u32 val; -static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - dvma_unmap((char *)sp->SCp.have_data_in); -} + scsi_esp_unregister(esp); -static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp) -{ - int sz = sp->use_sg - 1; - struct scatterlist *sg = (struct scatterlist *)sp->request_buffer; - - while(sz >= 0) { - dvma_unmap((char *)sg[sz].dma_address); - sz--; - } -} + /* Disable interrupts. */ + val = dma_read32(DMA_CSR); + dma_write32(val & ~DMA_INT_ENAB, DMA_CSR); -static void dma_advance_sg (Scsi_Cmnd *sp) -{ - sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dma_address); -} + free_irq(irq, esp); + dma_free_coherent(esp->dev, 16, + esp->command_block, + esp->command_block_dma); -static int sun3x_esp_release(struct Scsi_Host *instance) -{ - /* this code does not support being compiled as a module */ - return 1; + scsi_host_put(esp->host); + return 0; } -static struct scsi_host_template driver_template = { - .proc_name = "sun3x_esp", - .proc_info = &esp_proc_info, - .name = "Sun ESP 100/100a/200", - .detect = sun3x_esp_detect, - .release = sun3x_esp_release, - .slave_alloc = esp_slave_alloc, - .slave_destroy = esp_slave_destroy, - .info = esp_info, - .queuecommand = esp_queue, - .eh_abort_handler = esp_abort, - .eh_bus_reset_handler = esp_reset, - .can_queue = 7, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, +static struct platform_driver esp_sun3x_driver = { + .probe = esp_sun3x_probe, + .remove = __devexit_p(esp_sun3x_remove), + .driver = { + .name = "sun3x_esp", + }, }; +static int __init sun3x_esp_init(void) +{ + return platform_driver_register(&esp_sun3x_driver); +} -#include "scsi_module.c" +static void __exit sun3x_esp_exit(void) +{ + platform_driver_unregister(&esp_sun3x_driver); +} +MODULE_DESCRIPTION("Sun3x ESP SCSI driver"); +MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)"); MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(sun3x_esp_init); +module_exit(sun3x_esp_exit); diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index 254bdaeb35ff..35142b5341b5 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -3842,7 +3842,7 @@ int sym_compute_residual(struct sym_hcb *np, struct sym_ccb *cp) if (cp->startp == cp->phys.head.lastp || sym_evaluate_dp(np, cp, scr_to_cpu(cp->phys.head.lastp), &dp_ofs) < 0) { - return cp->data_len; + return cp->data_len - cp->odd_byte_adjustment; } /* diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 662c00451be4..58d7eee4fe81 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -1216,7 +1216,7 @@ static void scsi_to_dev_dir(unsigned int i, unsigned int j) { cpp->xdir = DTD_IN; return; } - else if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) { + else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) { cpp->xdir = DTD_OUT; return; } diff --git a/fs/Kconfig b/fs/Kconfig index 3bf6ace1720c..d7312825592b 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1778,12 +1778,9 @@ config SUNRPC_GSS tristate config SUNRPC_XPRT_RDMA - tristate "RDMA transport for sunrpc (EXPERIMENTAL)" + tristate depends on SUNRPC && INFINIBAND && EXPERIMENTAL - default m - help - Adds a client RPC transport for supporting kernel NFS over RDMA - mounts, including Infiniband and iWARP. Experimental. + default SUNRPC && INFINIBAND config SUNRPC_BIND34 bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)" diff --git a/fs/nfs/write.c b/fs/nfs/write.c index b144b1957dd9..f55c437124a2 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -697,6 +697,17 @@ int nfs_flush_incompatible(struct file *file, struct page *page) } /* + * 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. * * XXX: Keep an eye on generic_file_read to make sure it doesn't do bad @@ -717,10 +728,13 @@ 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 entirely in cache, it may be more efficient to avoid - * fragmenting write requests. + * is up to date, it may be more efficient to extend the write + * to cover the entire page in order to avoid fragmentation + * inefficiencies. */ - if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & O_SYNC)) { + if (nfs_write_pageuptodate(page, inode) && + inode->i_flock == NULL && + !(file->f_mode & O_SYNC)) { count = max(count + offset, nfs_page_length(page)); offset = 0; } diff --git a/fs/xfs/Makefile-linux-2.6 b/fs/xfs/Makefile-linux-2.6 index d1491aa7a0e2..97316451fc6d 100644 --- a/fs/xfs/Makefile-linux-2.6 +++ b/fs/xfs/Makefile-linux-2.6 @@ -70,7 +70,6 @@ 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/fs/xfs/linux-2.6/spin.h b/fs/xfs/linux-2.6/spin.h deleted file mode 100644 index 50a6191178f4..000000000000 --- a/fs/xfs/linux-2.6/spin.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 <linux/sched.h> /* preempt needs this */ -#include <linux/spinlock.h> - -/* - * 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/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 2e34b104107c..e0519529c26c 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -107,6 +107,18 @@ 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, @@ -151,7 +163,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 io_new_size will be the intended file size until i_size is + * eof i_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. */ @@ -173,7 +185,7 @@ xfs_setfilesize( xfs_ilock(ip, XFS_ILOCK_EXCL); - isize = MAX(ip->i_size, ip->i_iocore.io_new_size); + isize = MAX(ip->i_size, ip->i_new_size); isize = MIN(isize, bsize); if (ip->i_d.di_size < isize) { @@ -226,12 +238,13 @@ 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)) { - xfs_bmap(XFS_I(ioend->io_inode), offset, size, - BMAPI_UNWRITTEN, NULL, NULL); + if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) + xfs_iomap_write_unwritten(ip, offset, size); xfs_setfilesize(ioend); } xfs_destroy_ioend(ioend); @@ -304,7 +317,7 @@ xfs_map_blocks( xfs_inode_t *ip = XFS_I(inode); int error, nmaps = 1; - error = xfs_bmap(ip, offset, count, + error = xfs_iomap(ip, offset, count, flags, mapp, &nmaps); if (!error && (flags & (BMAPI_WRITE|BMAPI_ALLOCATE))) xfs_iflags_set(ip, XFS_IMODIFIED); @@ -1323,7 +1336,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_bmap(XFS_I(inode), offset, size, + error = xfs_iomap(XFS_I(inode), offset, size, create ? flags : BMAPI_READ, &iomap, &niomap); if (error) return -error; @@ -1471,28 +1484,21 @@ xfs_vm_direct_IO( { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - xfs_iomap_t iomap; - int maps = 1; - int error; + struct block_device *bdev; ssize_t ret; - error = xfs_bmap(XFS_I(inode), offset, 0, - BMAPI_DEVICE, &iomap, &maps); - if (error) - return -error; + bdev = xfs_find_bdev_for_inode(XFS_I(inode)); if (rw == WRITE) { iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN); ret = blockdev_direct_IO_own_locking(rw, iocb, inode, - iomap.iomap_target->bt_bdev, - iov, offset, nr_segs, + 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, - iomap.iomap_target->bt_bdev, - iov, offset, nr_segs, + bdev, iov, offset, nr_segs, xfs_get_blocks_direct, xfs_end_io_direct); } @@ -1525,8 +1531,7 @@ xfs_vm_bmap( struct inode *inode = (struct inode *)mapping->host; struct xfs_inode *ip = XFS_I(inode); - vn_trace_entry(XFS_I(inode), __FUNCTION__, - (inst_t *)__return_address); + xfs_itrace_entry(XFS_I(inode)); 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/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 0382c19d6523..e347bfd47c91 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -387,8 +387,6 @@ _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; } @@ -418,24 +416,17 @@ _xfs_buf_lookup_pages( ASSERT(!PagePrivate(page)); if (!PageUptodate(page)) { page_count--; - if (blocksize >= PAGE_CACHE_SIZE) { - if (flags & XBF_READ) - bp->b_locked = 1; - } else if (!PagePrivate(page)) { + if (blocksize < PAGE_CACHE_SIZE && !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; @@ -751,7 +742,6 @@ 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; @@ -1098,25 +1088,13 @@ 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) { - bp->b_locked = 0; + if (atomic_dec_and_test(&bp->b_io_remaining) == 1) xfs_buf_ioend(bp, schedule); - } } STATIC void @@ -1147,10 +1125,6 @@ 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); @@ -1161,13 +1135,12 @@ STATIC void _xfs_buf_ioapply( xfs_buf_t *bp) { - int i, rw, map_i, total_nr_pages, nr_pages; + int 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; @@ -1190,7 +1163,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) && locking && + (bp->b_flags & XBF_READ) && (blocksize >= PAGE_CACHE_SIZE)) { bio = bio_alloc(GFP_NOIO, 1); @@ -1207,24 +1180,6 @@ _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); @@ -1571,7 +1526,7 @@ xfs_alloc_delwrite_queue( INIT_LIST_HEAD(&btp->bt_list); INIT_LIST_HEAD(&btp->bt_delwrite_queue); - spinlock_init(&btp->bt_delwrite_lock, "delwri_lock"); + spin_lock_init(&btp->bt_delwrite_lock); btp->bt_flags = 0; btp->bt_task = kthread_run(xfsbufd, btp, "xfsbufd"); if (IS_ERR(btp->bt_task)) { diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index b5908a34b15d..a3d207de48b8 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -143,7 +143,6 @@ 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/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c index 15bd4948832c..ca4f66c4de16 100644 --- a/fs/xfs/linux-2.6/xfs_export.c +++ b/fs/xfs/linux-2.6/xfs_export.c @@ -118,20 +118,29 @@ xfs_nfs_get_inode( u64 ino, u32 generation) { - xfs_fid_t xfid; - bhv_vnode_t *vp; + xfs_mount_t *mp = XFS_M(sb); + xfs_inode_t *ip; int error; - xfid.fid_len = sizeof(xfs_fid_t) - sizeof(xfid.fid_len); - xfid.fid_pad = 0; - xfid.fid_ino = ino; - xfid.fid_gen = generation; + /* + * NFS can sometimes send requests for ino 0. Fail them gracefully. + */ + if (ino == 0) + return ERR_PTR(-ESTALE); - error = xfs_vget(XFS_M(sb), &vp, &xfid); + error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0); 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); + } - return vp ? vn_to_inode(vp) : NULL; + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return ip->i_vnode; } STATIC struct dentry * diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 21a1c2b1c5fc..edab1ffbb163 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/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,7 +362,6 @@ xfs_file_readdir( sizeof(u64)); size -= reclen; de = (struct hack_dirent *)((char *)de + reclen); - curr_offset = de->offset /* & 0x7fffffff */; } } diff --git a/fs/xfs/linux-2.6/xfs_globals.c b/fs/xfs/linux-2.6/xfs_globals.c index 9febf9dc999d..ef90e64641e6 100644 --- a/fs/xfs/linux-2.6/xfs_globals.c +++ b/fs/xfs/linux-2.6/xfs_globals.c @@ -47,5 +47,6 @@ xfs_param_t xfs_params = { /* * Global system credential structure. */ -cred_t sys_cred_val, *sys_cred = &sys_cred_val; +static cred_t sys_cred_val; +cred_t *sys_cred = &sys_cred_val; diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 98a56568bb24..4c82a050a3a8 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -75,7 +75,6 @@ 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); @@ -134,21 +133,16 @@ 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_inode_t *ip = XFS_I(inode); 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 */ @@ -176,21 +170,19 @@ xfs_find_handle( /* - * 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. + * 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. * - * If no error, caller must always VN_RELE the returned vp. + * If no error, caller must always iput the returned inode. */ 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; @@ -199,8 +191,6 @@ 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; @@ -241,7 +231,7 @@ xfs_vget_fsop_handlereq( } /* - * Get the XFS inode, building a vnode to go with it. + * Get the XFS inode, building a Linux inode to go with it. */ error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0); if (error) @@ -253,12 +243,9 @@ xfs_vget_fsop_handlereq( return XFS_ERROR(ENOENT); } - vpp = XFS_ITOV(ip); - inodep = vn_to_inode(vpp); xfs_iunlock(ip, XFS_ILOCK_SHARED); - *vp = vpp; - *inode = inodep; + *inode = XFS_ITOV(ip); return 0; } @@ -275,7 +262,6 @@ 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)) @@ -283,7 +269,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, &vp, &inode); + error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &inode); if (error) return -error; @@ -385,7 +371,6 @@ xfs_readlink_by_handle( { struct inode *inode; xfs_fsop_handlereq_t hreq; - bhv_vnode_t *vp; __u32 olen; void *link; int error; @@ -395,7 +380,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, &vp, &inode); + error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &inode); if (error) return -error; @@ -438,34 +423,32 @@ 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, &vp, &inode); + error = xfs_vget_fsop_handlereq(mp, parinode, &dmhreq.hreq, &inode); if (error) return -error; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { - VN_RELE(vp); - return -XFS_ERROR(EPERM); + error = -XFS_ERROR(EPERM); + goto out; } if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) { - VN_RELE(vp); - return -XFS_ERROR(EFAULT); + error = -XFS_ERROR(EFAULT); + goto out; } - error = xfs_set_dmattrs(xfs_vtoi(vp), - fsd.fsd_dmevmask, fsd.fsd_dmstate); + error = -xfs_set_dmattrs(XFS_I(inode), fsd.fsd_dmevmask, + fsd.fsd_dmstate); - VN_RELE(vp); - if (error) - return -error; - return 0; + out: + iput(inode); + return error; } STATIC int @@ -478,7 +461,6 @@ 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)) @@ -488,8 +470,7 @@ 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, - &vp, &inode); + error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq, &inode); if (error) goto out; @@ -509,7 +490,7 @@ xfs_attrlist_by_handle( out_kfree: kfree(kbuf); out_vn_rele: - VN_RELE(vp); + iput(inode); out: return -error; } @@ -531,7 +512,7 @@ xfs_attrmulti_attr_get( if (!kbuf) return ENOMEM; - error = xfs_attr_get(XFS_I(inode), name, kbuf, len, flags, NULL); + error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags, NULL); if (error) goto out_kfree; @@ -598,7 +579,6 @@ 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; @@ -607,7 +587,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, &vp, &inode); + error = xfs_vget_fsop_handlereq(mp, parinode, &am_hreq.hreq, &inode); if (error) goto out; @@ -666,7 +646,7 @@ xfs_attrmulti_by_handle( out_kfree_ops: kfree(ops); out_vn_rele: - VN_RELE(vp); + iput(inode); out: return -error; } @@ -702,7 +682,6 @@ xfs_ioc_fsgeometry( STATIC int xfs_ioc_xattr( - bhv_vnode_t *vp, xfs_inode_t *ip, struct file *filp, unsigned int cmd, @@ -735,12 +714,10 @@ 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; - vn_trace_entry(XFS_I(inode), "xfs_ioctl", (inst_t *)__return_address); - + xfs_itrace_entry(XFS_I(inode)); switch (cmd) { case XFS_IOC_ALLOCSP: @@ -764,7 +741,7 @@ xfs_ioctl( case XFS_IOC_DIOINFO: { struct dioattr da; xfs_buftarg_t *target = - (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? + XFS_IS_REALTIME_INODE(ip) ? mp->m_rtdev_targp : mp->m_ddev_targp; da.d_mem = da.d_miniosz = 1 << target->bt_sshift; @@ -796,7 +773,7 @@ xfs_ioctl( case XFS_IOC_GETXFLAGS: case XFS_IOC_SETXFLAGS: case XFS_IOC_FSSETXATTR: - return xfs_ioc_xattr(vp, ip, filp, cmd, arg); + return xfs_ioc_xattr(ip, filp, cmd, arg); case XFS_IOC_FSSETDM: { struct fsdmidata dmi; @@ -1203,7 +1180,6 @@ xfs_ioc_fsgetxattr( STATIC int xfs_ioc_xattr( - bhv_vnode_t *vp, xfs_inode_t *ip, struct file *filp, unsigned int cmd, @@ -1237,7 +1213,7 @@ xfs_ioc_xattr( error = xfs_setattr(ip, vattr, attr_flags, NULL); if (likely(!error)) - __vn_revalidate(vp, vattr); /* update flags */ + vn_revalidate(XFS_ITOV(ip)); /* update flags */ error = -error; break; } @@ -1272,7 +1248,7 @@ xfs_ioc_xattr( error = xfs_setattr(ip, vattr, attr_flags, NULL); if (likely(!error)) - __vn_revalidate(vp, vattr); /* update flags */ + vn_revalidate(XFS_ITOV(ip)); /* update flags */ error = -error; break; } diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index bf2a956b63c2..a4b254eb43b2 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -44,6 +44,7 @@ #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)) @@ -379,9 +380,6 @@ 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: @@ -407,6 +405,11 @@ 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/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 5e8bb7f71b5a..cc4abd3daa49 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -52,6 +52,7 @@ #include <linux/xattr.h> #include <linux/namei.h> #include <linux/security.h> +#include <linux/falloc.h> /* * Bring the atime in the XFS inode uptodate. @@ -71,6 +72,22 @@ 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 * we do record the fact that there is dirty information in core. @@ -184,10 +201,6 @@ 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) @@ -542,12 +555,31 @@ 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 mode, - struct nameidata *nd) + struct inode *inode, + int mask, + struct nameidata *nd) { - return -xfs_access(XFS_I(inode), mode << 6, NULL); + return generic_permission(inode, mask, xfs_check_acl); } #else #define xfs_vn_permission NULL @@ -555,33 +587,61 @@ 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; - bhv_vattr_t vattr = { .va_mask = XFS_AT_STAT }; - int error; - - 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; + 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; } - return -error; + + return 0; } STATIC int @@ -636,7 +696,7 @@ xfs_vn_setattr( error = xfs_setattr(XFS_I(inode), &vattr, flags, NULL); if (likely(!error)) - __vn_revalidate(vn_from_inode(inode), &vattr); + vn_revalidate(vn_from_inode(inode)); return -error; } @@ -750,6 +810,47 @@ 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, @@ -760,6 +861,7 @@ 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/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index dc3752de22da..3ca39c4e5d2a 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h @@ -43,7 +43,6 @@ #include <kmem.h> #include <mrlock.h> -#include <spin.h> #include <sv.h> #include <mutex.h> #include <sema.h> @@ -75,6 +74,7 @@ #include <linux/notifier.h> #include <linux/delay.h> #include <linux/log2.h> +#include <linux/spinlock.h> #include <asm/page.h> #include <asm/div64.h> @@ -136,43 +136,19 @@ #define current_restore_flags_nested(sp, f) \ (current->flags = ((current->flags & ~(f)) | (*(sp) & (f)))) -#define NBPP PAGE_SIZE -#define NDPP (1 << (PAGE_SHIFT - 9)) +#define spinlock_destroy(lock) #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 BPCSHIFT +#define BLKDEV_IOSHIFT PAGE_CACHE_SHIFT #define BLKDEV_IOSIZE (1<<BLKDEV_IOSHIFT) /* number of BB's per block device block */ #define BLKDEV_BB BTOBB(BLKDEV_IOSIZE) -/* bytes to clicks */ -#define btoc(x) (((__psunsigned_t)(x)+(NBPC-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) - -/* clicks to bytes */ -#define ctob(x) ((__psunsigned_t)(x)<<BPCSHIFT) -#define btoct(x) ((__psunsigned_t)(x)>>BPCSHIFT) -#define ctob64(x) ((__uint64_t)(x)<<BPCSHIFT) - -/* bytes to clicks */ -#define btoc(x) (((__psunsigned_t)(x)+(NBPC-1))>>BPCSHIFT) - #define ENOATTR ENODATA /* Attribute not found */ #define EWRONGFS EINVAL /* Mount with wrong filesystem type */ #define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ @@ -205,10 +181,6 @@ #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/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 6f614f35f650..166353388490 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c @@ -58,14 +58,12 @@ void xfs_rw_enter_trace( int tag, - xfs_iocore_t *io, + xfs_inode_t *ip, 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, @@ -78,8 +76,8 @@ xfs_rw_enter_trace( (void *)((unsigned long)((offset >> 32) & 0xffffffff)), (void *)((unsigned long)(offset & 0xffffffff)), (void *)((unsigned long)ioflags), - (void *)((unsigned long)((io->io_new_size >> 32) & 0xffffffff)), - (void *)((unsigned long)(io->io_new_size & 0xffffffff)), + (void *)((unsigned long)((ip->i_new_size >> 32) & 0xffffffff)), + (void *)((unsigned long)(ip->i_new_size & 0xffffffff)), (void *)((unsigned long)current_pid()), (void *)NULL, (void *)NULL, @@ -89,13 +87,12 @@ xfs_rw_enter_trace( void xfs_inval_cached_trace( - xfs_iocore_t *io, + xfs_inode_t *ip, 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; @@ -131,7 +128,7 @@ xfs_inval_cached_trace( */ STATIC int xfs_iozero( - struct inode *ip, /* inode */ + struct xfs_inode *ip, /* inode */ loff_t pos, /* offset in file */ size_t count) /* size of data to zero */ { @@ -139,7 +136,7 @@ xfs_iozero( struct address_space *mapping; int status; - mapping = ip->i_mapping; + mapping = ip->i_vnode->i_mapping; do { unsigned offset, bytes; void *fsdata; @@ -205,7 +202,7 @@ xfs_read( if (unlikely(ioflags & IO_ISDIRECT)) { xfs_buftarg_t *target = - (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? + XFS_IS_REALTIME_INODE(ip) ? mp->m_rtdev_targp : mp->m_ddev_targp; if ((*offset & target->bt_smask) || (size & target->bt_smask)) { @@ -246,9 +243,8 @@ xfs_read( if (unlikely(ioflags & IO_ISDIRECT)) { if (VN_CACHED(vp)) - ret = xfs_flushinval_pages(ip, - ctooff(offtoct(*offset)), - -1, FI_REMAPF_LOCKED); + ret = xfs_flushinval_pages(ip, (*offset & PAGE_CACHE_MASK), + -1, FI_REMAPF_LOCKED); mutex_unlock(&inode->i_mutex); if (ret) { xfs_iunlock(ip, XFS_IOLOCK_SHARED); @@ -256,7 +252,7 @@ xfs_read( } } - xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore, + xfs_rw_enter_trace(XFS_READ_ENTER, ip, (void *)iovp, segs, *offset, ioflags); iocb->ki_pos = *offset; @@ -301,7 +297,7 @@ xfs_splice_read( return -error; } } - xfs_rw_enter_trace(XFS_SPLICE_READ_ENTER, &ip->i_iocore, + xfs_rw_enter_trace(XFS_SPLICE_READ_ENTER, ip, pipe, count, *ppos, ioflags); ret = generic_file_splice_read(infilp, ppos, pipe, count, flags); if (ret > 0) @@ -323,7 +319,6 @@ 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; @@ -350,10 +345,10 @@ xfs_splice_write( xfs_ilock(ip, XFS_ILOCK_EXCL); if (new_size > ip->i_size) - io->io_new_size = new_size; + ip->i_new_size = new_size; xfs_iunlock(ip, XFS_ILOCK_EXCL); - xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore, + xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, ip, pipe, count, *ppos, ioflags); ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags); if (ret > 0) @@ -370,9 +365,9 @@ xfs_splice_write( xfs_iunlock(ip, XFS_ILOCK_EXCL); } - if (io->io_new_size) { + if (ip->i_new_size) { xfs_ilock(ip, XFS_ILOCK_EXCL); - io->io_new_size = 0; + ip->i_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); @@ -389,20 +384,19 @@ xfs_splice_write( */ STATIC int /* error (positive) */ xfs_zero_last_block( - struct inode *ip, - xfs_iocore_t *io, + xfs_inode_t *ip, xfs_fsize_t offset, xfs_fsize_t isize) { xfs_fileoff_t last_fsb; - xfs_mount_t *mp = io->io_mount; + xfs_mount_t *mp = ip->i_mount; int nimaps; int zero_offset; int zero_len; int error = 0; xfs_bmbt_irec_t imap; - ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0); zero_offset = XFS_B_FSB_OFFSET(mp, isize); if (zero_offset == 0) { @@ -415,7 +409,7 @@ xfs_zero_last_block( last_fsb = XFS_B_TO_FSBT(mp, isize); nimaps = 1; - error = XFS_BMAPI(mp, NULL, io, last_fsb, 1, 0, NULL, 0, &imap, + error = xfs_bmapi(NULL, ip, last_fsb, 1, 0, NULL, 0, &imap, &nimaps, NULL, NULL); if (error) { return error; @@ -433,14 +427,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(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD); + xfs_iunlock(ip, 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(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + xfs_ilock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); ASSERT(error >= 0); return error; } @@ -458,35 +452,33 @@ xfs_zero_last_block( int /* error (positive) */ xfs_zero_eof( - bhv_vnode_t *vp, - xfs_iocore_t *io, + xfs_inode_t *ip, xfs_off_t offset, /* starting I/O offset */ xfs_fsize_t isize) /* current inode size */ { - struct inode *ip = vn_to_inode(vp); + xfs_mount_t *mp = ip->i_mount; 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(io->io_lock, MR_UPDATE)); - ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT(ismrlocked(&ip->i_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, io, offset, isize); + error = xfs_zero_last_block(ip, offset, isize); if (error) { - ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); - ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); return error; } @@ -514,11 +506,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(mp, NULL, io, start_zero_fsb, zero_count_fsb, + error = xfs_bmapi(NULL, ip, start_zero_fsb, zero_count_fsb, 0, NULL, 0, &imap, &nimaps, NULL, NULL); if (error) { - ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); - ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); return error; } ASSERT(nimaps > 0); @@ -542,7 +534,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(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + xfs_iunlock(ip, 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); @@ -558,14 +550,13 @@ xfs_zero_eof( start_zero_fsb = imap.br_startoff + imap.br_blockcount; ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); - XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + xfs_ilock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); } return 0; out_lock: - - XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + xfs_ilock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); ASSERT(error >= 0); return error; } @@ -587,7 +578,6 @@ 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; @@ -607,8 +597,7 @@ xfs_write( if (count == 0) return 0; - io = &xip->i_iocore; - mp = io->io_mount; + mp = xip->i_mount; xfs_wait_for_freeze(mp, SB_FREEZE_WRITE); @@ -667,7 +656,7 @@ start: if (ioflags & IO_ISDIRECT) { xfs_buftarg_t *target = - (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? + XFS_IS_REALTIME_INODE(xip) ? mp->m_rtdev_targp : mp->m_ddev_targp; if ((pos & target->bt_smask) || (count & target->bt_smask)) { @@ -688,7 +677,7 @@ start: new_size = pos + count; if (new_size > xip->i_size) - io->io_new_size = new_size; + xip->i_new_size = new_size; if (likely(!(ioflags & IO_INVIS))) { file_update_time(file); @@ -706,7 +695,7 @@ start: */ if (pos > xip->i_size) { - error = xfs_zero_eof(vp, io, pos, xip->i_size); + error = xfs_zero_eof(xip, pos, xip->i_size); if (error) { xfs_iunlock(xip, XFS_ILOCK_EXCL); goto out_unlock_internal; @@ -740,10 +729,10 @@ retry: if ((ioflags & IO_ISDIRECT)) { if (VN_CACHED(vp)) { WARN_ON(need_i_mutex == 0); - xfs_inval_cached_trace(io, pos, -1, - ctooff(offtoct(pos)), -1); + xfs_inval_cached_trace(xip, pos, -1, + (pos & PAGE_CACHE_MASK), -1); error = xfs_flushinval_pages(xip, - ctooff(offtoct(pos)), + (pos & PAGE_CACHE_MASK), -1, FI_REMAPF_LOCKED); if (error) goto out_unlock_internal; @@ -751,7 +740,7 @@ retry: if (need_i_mutex) { /* demote the lock now the cached pages are gone */ - XFS_ILOCK_DEMOTE(mp, io, XFS_IOLOCK_EXCL); + xfs_ilock_demote(xip, XFS_IOLOCK_EXCL); mutex_unlock(&inode->i_mutex); iolock = XFS_IOLOCK_SHARED; @@ -759,7 +748,7 @@ retry: need_i_mutex = 0; } - xfs_rw_enter_trace(XFS_DIOWR_ENTER, io, (void *)iovp, segs, + xfs_rw_enter_trace(XFS_DIOWR_ENTER, xip, (void *)iovp, segs, *offset, ioflags); ret = generic_file_direct_write(iocb, iovp, &segs, pos, offset, count, ocount); @@ -779,7 +768,7 @@ retry: goto relock; } } else { - xfs_rw_enter_trace(XFS_WRITE_ENTER, io, (void *)iovp, segs, + xfs_rw_enter_trace(XFS_WRITE_ENTER, xip, (void *)iovp, segs, *offset, ioflags); ret = generic_file_buffered_write(iocb, iovp, segs, pos, offset, count, ret); @@ -843,9 +832,9 @@ retry: } out_unlock_internal: - if (io->io_new_size) { + if (xip->i_new_size) { xfs_ilock(xip, XFS_ILOCK_EXCL); - io->io_new_size = 0; + xip->i_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 @@ -894,25 +883,6 @@ 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/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h index 4b7747a828d9..e200253139cf 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.h +++ b/fs/xfs/linux-2.6/xfs_lrw.h @@ -19,7 +19,6 @@ #define __XFS_LRW_H__ struct xfs_mount; -struct xfs_iocore; struct xfs_inode; struct xfs_bmbt_irec; struct xfs_buf; @@ -60,20 +59,19 @@ 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_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); +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); #else -#define xfs_rw_enter_trace(tag, io, data, size, offset, ioflags) -#define xfs_inval_cached_trace(io, offset, len, first, last) +#define xfs_rw_enter_trace(tag, ip, data, size, offset, ioflags) +#define xfs_inval_cached_trace(ip, 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 inode *, struct xfs_iocore *, xfs_off_t, - xfs_fsize_t); +extern int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t); #endif /* __XFS_LRW_H__ */ diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 8cb63c60c048..21dfc9da235e 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -41,6 +41,7 @@ #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" @@ -49,6 +50,8 @@ #include "xfs_vnodeops.h" #include "xfs_vfsops.h" #include "xfs_version.h" +#include "xfs_log_priv.h" +#include "xfs_trans_priv.h" #include <linux/namei.h> #include <linux/init.h> @@ -87,6 +90,435 @@ 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) @@ -137,7 +569,7 @@ xfs_set_inodeops( break; case S_IFLNK: inode->i_op = &xfs_symlink_inode_operations; - if (inode->i_blocks) + if (!(XFS_I(inode)->i_df.if_flags & XFS_IFINLINE)) inode->i_mapping->a_ops = &xfs_address_space_operations; break; default: @@ -174,8 +606,6 @@ 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; @@ -334,6 +764,64 @@ 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) @@ -361,7 +849,7 @@ xfs_fs_inode_init_once( inode_init_once(vn_to_inode((bhv_vnode_t *)vnode)); } -STATIC int +STATIC int __init xfs_init_zones(void) { xfs_vnode_zone = kmem_zone_init_flags(sizeof(bhv_vnode_t), "xfs_vnode", @@ -410,8 +898,7 @@ xfs_fs_write_inode( { int error = 0, flags = FLUSH_INODE; - vn_trace_entry(XFS_I(inode), __FUNCTION__, - (inst_t *)__return_address); + xfs_itrace_entry(XFS_I(inode)); if (sync) { filemap_fdatawait(inode->i_mapping); flags |= FLUSH_SYNC; @@ -438,8 +925,7 @@ xfs_fs_clear_inode( * find an inode with di_mode == 0 but without IGET_CREATE set. */ if (ip) { - vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); - + xfs_itrace_entry(ip); XFS_STATS_INC(vn_rele); XFS_STATS_INC(vn_remove); XFS_STATS_INC(vn_reclaim); @@ -683,8 +1169,44 @@ xfs_fs_statfs( struct dentry *dentry, struct kstatfs *statp) { - return -xfs_statvfs(XFS_M(dentry->d_sb), statp, - vn_from_inode(dentry->d_inode)); + 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; } STATIC int @@ -704,11 +1226,19 @@ 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) { - xfs_freeze(XFS_M(sb)); + struct xfs_mount *mp = XFS_M(sb); + + xfs_attr_quiesce(mp); + xfs_fs_log_dummy(mp); } STATIC int @@ -779,7 +1309,6 @@ 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(); @@ -807,21 +1336,19 @@ 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 = statvfs.f_type; - sb->s_blocksize = statvfs.f_bsize; - sb->s_blocksize_bits = ffs(statvfs.f_bsize) - 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_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits); sb->s_time_gran = 1; set_posix_acl_flag(sb); - error = xfs_root(mp, &rootvp); - if (error) + rootvp = igrab(mp->m_rootip->i_vnode); + if (!rootvp) { + error = ENOENT; goto fail_unmount; + } sb->s_root = d_alloc_root(vn_to_inode(rootvp)); if (!sb->s_root) { @@ -841,8 +1368,7 @@ xfs_fs_fill_super( goto fail_vnrele; } - vn_trace_exit(XFS_I(sb->s_root->d_inode), __FUNCTION__, - (inst_t *)__return_address); + xfs_itrace_exit(XFS_I(sb->s_root->d_inode)); kmem_free(args, sizeof(*args)); return 0; diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c index 814169fd7e1e..bc7afe007338 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.c +++ b/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 +void __init vn_init(void) { int i; @@ -82,84 +82,55 @@ 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 vattr. + * Revalidate the Linux inode from the XFS inode. * Note: i_size _not_ updated; we must hold the inode * semaphore when doing that - callers responsibility. */ -void -vn_revalidate_core( - bhv_vnode_t *vp, - bhv_vattr_t *vap) +int +vn_revalidate( + bhv_vnode_t *vp) { - 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) + 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) inode->i_flags |= S_IMMUTABLE; else inode->i_flags &= ~S_IMMUTABLE; - if (vap->va_xflags & XFS_XFLAG_APPEND) + if (xflags & XFS_XFLAG_APPEND) inode->i_flags |= S_APPEND; else inode->i_flags &= ~S_APPEND; - if (vap->va_xflags & XFS_XFLAG_SYNC) + if (xflags & XFS_XFLAG_SYNC) inode->i_flags |= S_SYNC; else inode->i_flags &= ~S_SYNC; - if (vap->va_xflags & XFS_XFLAG_NOATIME) + if (xflags & XFS_XFLAG_NOATIME) inode->i_flags |= S_NOATIME; else inode->i_flags &= ~S_NOATIME; -} - -/* - * 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_iunlock(ip, XFS_ILOCK_SHARED); - return __vn_revalidate(vp, &vattr); + xfs_iflags_clear(ip, XFS_IMODIFIED); + return 0; } /* @@ -179,7 +150,7 @@ vn_hold( return vp; } -#ifdef XFS_VNODE_TRACE +#ifdef XFS_INODE_TRACE /* * Reference count of Linux inode if present, -1 if the xfs_inode @@ -211,32 +182,32 @@ static inline int xfs_icount(struct xfs_inode *ip) * Vnode tracing code. */ void -vn_trace_entry(xfs_inode_t *ip, const char *func, inst_t *ra) +_xfs_itrace_entry(xfs_inode_t *ip, const char *func, inst_t *ra) { - KTRACE_ENTER(ip, VNODE_KTRACE_ENTRY, func, 0, ra); + KTRACE_ENTER(ip, INODE_KTRACE_ENTRY, func, 0, ra); } void -vn_trace_exit(xfs_inode_t *ip, const char *func, inst_t *ra) +_xfs_itrace_exit(xfs_inode_t *ip, const char *func, inst_t *ra) { - KTRACE_ENTER(ip, VNODE_KTRACE_EXIT, func, 0, ra); + KTRACE_ENTER(ip, INODE_KTRACE_EXIT, func, 0, ra); } void -vn_trace_hold(xfs_inode_t *ip, char *file, int line, inst_t *ra) +xfs_itrace_hold(xfs_inode_t *ip, char *file, int line, inst_t *ra) { - KTRACE_ENTER(ip, VNODE_KTRACE_HOLD, file, line, ra); + KTRACE_ENTER(ip, INODE_KTRACE_HOLD, file, line, ra); } void -vn_trace_ref(xfs_inode_t *ip, char *file, int line, inst_t *ra) +_xfs_itrace_ref(xfs_inode_t *ip, char *file, int line, inst_t *ra) { - KTRACE_ENTER(ip, VNODE_KTRACE_REF, file, line, ra); + KTRACE_ENTER(ip, INODE_KTRACE_REF, file, line, ra); } void -vn_trace_rele(xfs_inode_t *ip, char *file, int line, inst_t *ra) +xfs_itrace_rele(xfs_inode_t *ip, char *file, int line, inst_t *ra) { - KTRACE_ENTER(ip, VNODE_KTRACE_RELE, file, line, ra); + KTRACE_ENTER(ip, INODE_KTRACE_RELE, file, line, ra); } -#endif /* XFS_VNODE_TRACE */ +#endif /* XFS_INODE_TRACE */ diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 55fb46948589..b5ea418693b1 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h @@ -187,10 +187,7 @@ 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 @@ -210,12 +207,12 @@ static inline int vn_count(bhv_vnode_t *vp) */ extern bhv_vnode_t *vn_hold(bhv_vnode_t *); -#if defined(XFS_VNODE_TRACE) +#if defined(XFS_INODE_TRACE) #define VN_HOLD(vp) \ ((void)vn_hold(vp), \ - vn_trace_hold(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address)) + xfs_itrace_hold(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address)) #define VN_RELE(vp) \ - (vn_trace_rele(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address), \ + (xfs_itrace_rele(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address), \ iput(vn_to_inode(vp))) #else #define VN_HOLD(vp) ((void)vn_hold(vp)) @@ -238,11 +235,6 @@ 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)); @@ -296,26 +288,36 @@ static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt) /* * Tracking vnode activity. */ -#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 *); +#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) + #else -#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) +#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) #endif #endif /* __XFS_VNODE_H__ */ diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index cfdd35ee9f7a..665babcca6a6 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c @@ -1209,7 +1209,6 @@ 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)); @@ -1270,9 +1269,9 @@ xfs_qm_dqflush( mp = dqp->q_mount; /* lsn is 64 bits */ - AIL_LOCK(mp, s); + spin_lock(&mp->m_ail_lock); dqp->q_logitem.qli_flush_lsn = dqp->q_logitem.qli_item.li_lsn; - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); /* * Attach an iodone routine so that we can remove this dquot from the @@ -1318,7 +1317,6 @@ xfs_qm_dqflush_done( xfs_dq_logitem_t *qip) { xfs_dquot_t *dqp; - SPLDECL(s); dqp = qip->qli_dquot; @@ -1333,15 +1331,15 @@ xfs_qm_dqflush_done( if ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && qip->qli_item.li_lsn == qip->qli_flush_lsn) { - AIL_LOCK(dqp->q_mount, s); + spin_lock(&dqp->q_mount->m_ail_lock); /* * 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, s); + (xfs_log_item_t*)qip); else - AIL_UNLOCK(dqp->q_mount, s); + spin_unlock(&dqp->q_mount->m_ail_lock); } /* diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/quota/xfs_dquot.h index 78d3ab95c5fd..5c371a92e3e2 100644 --- a/fs/xfs/quota/xfs_dquot.h +++ b/fs/xfs/quota/xfs_dquot.h @@ -123,11 +123,6 @@ 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/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c index ddb61fe22a5c..1800e8d1f646 100644 --- a/fs/xfs/quota/xfs_dquot_item.c +++ b/fs/xfs/quota/xfs_dquot_item.c @@ -94,14 +94,13 @@ 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)); - s = XFS_DQ_PINLOCK(dqp); + spin_lock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); dqp->q_pincount++; - XFS_DQ_PINUNLOCK(dqp, s); + spin_unlock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); } /* @@ -115,17 +114,16 @@ 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); - s = XFS_DQ_PINLOCK(dqp); + spin_lock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); dqp->q_pincount--; if (dqp->q_pincount == 0) { sv_broadcast(&dqp->q_pinwait); } - XFS_DQ_PINUNLOCK(dqp, s); + spin_unlock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); } /* ARGSUSED */ @@ -189,8 +187,6 @@ void xfs_qm_dqunpin_wait( xfs_dquot_t *dqp) { - SPLDECL(s); - ASSERT(XFS_DQ_IS_LOCKED(dqp)); if (dqp->q_pincount == 0) { return; @@ -200,9 +196,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); - s = XFS_DQ_PINLOCK(dqp); + spin_lock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); if (dqp->q_pincount == 0) { - XFS_DQ_PINUNLOCK(dqp, s); + spin_unlock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); return; } sv_wait(&(dqp->q_pinwait), PINOD, @@ -216,8 +212,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 @@ -322,7 +318,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. @@ -562,15 +558,14 @@ xfs_qm_qoffend_logitem_committed( xfs_lsn_t lsn) { xfs_qoff_logitem_t *qfs; - SPLDECL(s); qfs = qfe->qql_start_lip; - AIL_LOCK(qfs->qql_item.li_mountp,s); + spin_lock(&qfs->qql_item.li_mountp->m_ail_lock); /* * 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, s); + xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs); kmem_free(qfs, sizeof(xfs_qoff_logitem_t)); kmem_free(qfe, sizeof(xfs_qoff_logitem_t)); return (xfs_lsn_t)-1; diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index d488645f833d..35582fe9d648 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -310,7 +310,6 @@ xfs_qm_mount_quotas( xfs_mount_t *mp, int mfsi_flags) { - unsigned long s; int error = 0; uint sbf; @@ -367,13 +366,13 @@ xfs_qm_mount_quotas( write_changes: /* - * We actually don't have to acquire the SB_LOCK at all. + * We actually don't have to acquire the m_sb_lock at all. * This can only be called from mount, and that's single threaded. XXX */ - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); sbf = mp->m_sb.sb_qflags; mp->m_sb.sb_qflags = mp->m_qflags & XFS_MOUNT_QUOTA_ALL; - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); if (sbf != (mp->m_qflags & XFS_MOUNT_QUOTA_ALL)) { if (xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS)) { @@ -1139,7 +1138,7 @@ xfs_qm_init_quotainfo( return error; } - spinlock_init(&qinf->qi_pinlock, "xfs_qinf_pin"); + spin_lock_init(&qinf->qi_pinlock); xfs_qm_list_init(&qinf->qi_dqlist, "mpdqlist", 0); qinf->qi_dqreclaims = 0; @@ -1370,7 +1369,6 @@ xfs_qm_qino_alloc( { xfs_trans_t *tp; int error; - unsigned long s; int committed; tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QINOCREATE); @@ -1402,7 +1400,7 @@ xfs_qm_qino_alloc( * sbfields arg may contain fields other than *QUOTINO; * VERSIONNUM for example. */ - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); if (flags & XFS_QMOPT_SBVERSION) { #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) unsigned oldv = mp->m_sb.sb_versionnum; @@ -1429,7 +1427,7 @@ xfs_qm_qino_alloc( mp->m_sb.sb_uquotino = (*ip)->i_ino; else mp->m_sb.sb_gquotino = (*ip)->i_ino; - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); xfs_mod_sb(tp, sbfields); if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES))) { diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h index 23ccaa5fceaf..baf537c1c177 100644 --- a/fs/xfs/quota/xfs_qm.h +++ b/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 (NBPP / sizeof(xfs_dqhash_t)) -#define XFS_QM_HASHSIZE_HIGH ((NBPP * 4) / sizeof(xfs_dqhash_t)) +#define XFS_QM_HASHSIZE_LOW (PAGE_SIZE / sizeof(xfs_dqhash_t)) +#define XFS_QM_HASHSIZE_HIGH ((PAGE_SIZE * 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 */ - lock_t qi_pinlock; /* dquot pinning mutex */ + spinlock_t qi_pinlock; /* dquot pinning lock */ xfs_dqlist_t qi_dqlist; /* all dquots in filesys */ int qi_dqreclaims; /* a change here indicates a removal in the dqlist */ diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index ad5579d4eac4..2cc5886cfe85 100644 --- a/fs/xfs/quota/xfs_qm_syscalls.c +++ b/fs/xfs/quota/xfs_qm_syscalls.c @@ -200,7 +200,6 @@ xfs_qm_scall_quotaoff( boolean_t force) { uint dqtype; - unsigned long s; int error; uint inactivate_flags; xfs_qoff_logitem_t *qoffstart; @@ -237,9 +236,9 @@ xfs_qm_scall_quotaoff( if ((flags & XFS_ALL_QUOTA_ACCT) == 0) { mp->m_qflags &= ~(flags); - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); mp->m_sb.sb_qflags = mp->m_qflags; - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); /* XXX what to do if error ? Revert back to old vals incore ? */ @@ -415,7 +414,6 @@ xfs_qm_scall_quotaon( uint flags) { int error; - unsigned long s; uint qf; uint accflags; __int64_t sbflags; @@ -468,10 +466,10 @@ xfs_qm_scall_quotaon( * Change sb_qflags on disk but not incore mp->qflags * if this is the root filesystem. */ - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); qf = mp->m_sb.sb_qflags; mp->m_sb.sb_qflags = qf | flags; - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); /* * There's nothing to change if it's the same. @@ -815,7 +813,6 @@ xfs_qm_log_quotaoff( { xfs_trans_t *tp; int error; - unsigned long s; xfs_qoff_logitem_t *qoffi=NULL; uint oldsbqflag=0; @@ -832,10 +829,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); - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); oldsbqflag = mp->m_sb.sb_qflags; mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL; - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); xfs_mod_sb(tp, XFS_SB_QFLAGS); @@ -854,9 +851,9 @@ error0: * No one else is modifying sb_qflags, so this is OK. * We still hold the quotaofflock. */ - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); mp->m_sb.sb_qflags = oldsbqflag; - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); } *qoffstartp = qoffi; return (error); diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c index f45a49ffd3a3..c27abef7b84f 100644 --- a/fs/xfs/support/debug.c +++ b/fs/xfs/support/debug.c @@ -17,7 +17,6 @@ */ #include <xfs.h> #include "debug.h" -#include "spin.h" static char message[1024]; /* keep it off the stack */ static DEFINE_SPINLOCK(xfs_err_lock); @@ -81,3 +80,9 @@ 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/fs/xfs/support/ktrace.c b/fs/xfs/support/ktrace.c index 5cf2e86caa71..129067cfcb86 100644 --- a/fs/xfs/support/ktrace.c +++ b/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 +void __init ktrace_init(int zentries) { ktrace_zentries = zentries; @@ -36,7 +36,7 @@ ktrace_init(int zentries) ASSERT(ktrace_ent_zone); } -void +void __exit ktrace_uninit(void) { kmem_zone_destroy(ktrace_hdr_zone); @@ -90,8 +90,6 @@ 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; @@ -114,8 +112,6 @@ 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/fs/xfs/support/ktrace.h b/fs/xfs/support/ktrace.h index 0d73216287c0..56e72b40a859 100644 --- a/fs/xfs/support/ktrace.h +++ b/fs/xfs/support/ktrace.h @@ -18,8 +18,6 @@ #ifndef __XFS_SUPPORT_KTRACE_H__ #define __XFS_SUPPORT_KTRACE_H__ -#include <spin.h> - /* * Trace buffer entry structure. */ @@ -31,7 +29,6 @@ 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/fs/xfs/support/uuid.c b/fs/xfs/support/uuid.c index e157015c70ff..493a6ecf8590 100644 --- a/fs/xfs/support/uuid.c +++ b/fs/xfs/support/uuid.c @@ -133,7 +133,7 @@ uuid_table_remove(uuid_t *uuid) mutex_unlock(&uuid_monitor); } -void +void __init uuid_init(void) { mutex_init(&uuid_monitor); diff --git a/fs/xfs/xfs.h b/fs/xfs/xfs.h index b5a7d92c6843..540e4c989825 100644 --- a/fs/xfs/xfs.h +++ b/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_VNODE_TRACE 1 +#define XFS_INODE_TRACE 1 #define XFS_FILESTREAMS_TRACE 1 #endif diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 5bfb66f33caf..7272fe39a92d 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -392,32 +392,6 @@ xfs_acl_allow_set( } /* - * 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 * done in IRIX. It is assumed that the uid and groups for the current @@ -438,7 +412,6 @@ 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++) { /* @@ -520,7 +493,8 @@ xfs_acl_access( break; } - return xfs_acl_capability_check(md, cr); + /* EACCES tells generic_permission to check for capability overrides */ + return EACCES; } /* diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h index 34b7d3391299..332a772461c4 100644 --- a/fs/xfs/xfs_acl.h +++ b/fs/xfs/xfs_acl.h @@ -75,7 +75,6 @@ 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) @@ -95,7 +94,6 @@ 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/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index 9381b0360c4b..61b292a9fb41 100644 --- a/fs/xfs/xfs_ag.h +++ b/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__ - lock_t pagb_lock; /* lock for pagb_list */ + spinlock_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/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 012a649a19c3..ea6aa60ace06 100644 --- a/fs/xfs/xfs_alloc.c +++ b/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]); - spinlock_init(&pag->pagb_lock, "xfspagb"); + spin_lock_init(&pag->pagb_lock); pag->pagb_list = kmem_zalloc(XFS_PAGB_NUM_SLOTS * sizeof(xfs_perag_busy_t), KM_SLEEP); pag->pagf_init = 1; @@ -2500,10 +2500,9 @@ 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; - s = mutex_spinlock(&mp->m_perag[agno].pagb_lock); + spin_lock(&mp->m_perag[agno].pagb_lock); /* search pagb_list for an open slot */ for (bsy = mp->m_perag[agno].pagb_list, n = 0; @@ -2533,7 +2532,7 @@ xfs_alloc_mark_busy(xfs_trans_t *tp, xfs_trans_set_sync(tp); } - mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s); + spin_unlock(&mp->m_perag[agno].pagb_lock); } void @@ -2543,11 +2542,10 @@ xfs_alloc_clear_busy(xfs_trans_t *tp, { xfs_mount_t *mp; xfs_perag_busy_t *list; - SPLDECL(s); mp = tp->t_mountp; - s = mutex_spinlock(&mp->m_perag[agno].pagb_lock); + spin_lock(&mp->m_perag[agno].pagb_lock); list = mp->m_perag[agno].pagb_list; ASSERT(idx < XFS_PAGB_NUM_SLOTS); @@ -2559,7 +2557,7 @@ xfs_alloc_clear_busy(xfs_trans_t *tp, TRACE_UNBUSY("xfs_alloc_clear_busy", "missing", agno, idx, tp); } - mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s); + spin_unlock(&mp->m_perag[agno].pagb_lock); } @@ -2578,11 +2576,10 @@ 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; - s = mutex_spinlock(&mp->m_perag[agno].pagb_lock); + spin_lock(&mp->m_perag[agno].pagb_lock); cnt = mp->m_perag[agno].pagb_count; uend = bno + len - 1; @@ -2615,12 +2612,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; - mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s); + spin_unlock(&mp->m_perag[agno].pagb_lock); 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; - mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s); + spin_unlock(&mp->m_perag[agno].pagb_lock); } return n; diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index 93fa64dd1be6..e58f321fdae9 100644 --- a/fs/xfs/xfs_attr.c +++ b/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). */ -int +STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args) { xfs_inode_t *dp; diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index 81f45dae1c57..eb3815ebb7aa 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c @@ -226,17 +226,15 @@ 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))) { - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); if (!XFS_SB_VERSION_HASATTR2(&mp->m_sb)) { XFS_SB_VERSION_ADDATTR2(&mp->m_sb); - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); xfs_mod_sb(tp, XFS_SB_VERSIONNUM | XFS_SB_FEATURES2); } else - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); } } diff --git a/fs/xfs/xfs_bit.c b/fs/xfs/xfs_bit.c index fab0b6d5a41b..48228848f5ae 100644 --- a/fs/xfs/xfs_bit.c +++ b/fs/xfs/xfs_bit.c @@ -25,109 +25,6 @@ * 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/fs/xfs/xfs_bit.h b/fs/xfs/xfs_bit.h index 082641a9782c..325a007dec91 100644 --- a/fs/xfs/xfs_bit.h +++ b/fs/xfs/xfs_bit.h @@ -47,13 +47,30 @@ static inline __uint64_t xfs_mask64lo(int n) } /* Get high bit set out of 32-bit argument, -1 if none set */ -extern int xfs_highbit32(__uint32_t v); - -/* Get low bit set out of 64-bit argument, -1 if none set */ -extern int xfs_lowbit64(__uint64_t v); +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 */ -extern int xfs_highbit64(__uint64_t); +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; +} + +/* 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; +} /* Return whether bitmap is empty (1 == empty) */ extern int xfs_bitmap_empty(uint *map, uint size); diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 2e9b34b7344b..1c0a5a585a82 100644 --- a/fs/xfs/xfs_bmap.c +++ b/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 >= NBPP) { + } else if (mp->m_sb.sb_blocksize >= PAGE_CACHE_SIZE) { args.prod = 1; args.mod = 0; } else { - args.prod = NBPP >> mp->m_sb.sb_blocklog; + args.prod = PAGE_CACHE_SIZE >> 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 ((ap->ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && ap->userdata) + if (XFS_IS_REALTIME_INODE(ap->ip) && ap->userdata) return xfs_bmap_rtalloc(ap); return xfs_bmap_btalloc(ap); } @@ -3096,8 +3096,7 @@ xfs_bmap_del_extent( /* * Realtime allocation. Free it and record di_nblocks update. */ - if (whichfork == XFS_DATA_FORK && - (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { + if (whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip)) { xfs_fsblock_t bno; xfs_filblks_t len; @@ -3956,7 +3955,6 @@ 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 */ @@ -4053,7 +4051,7 @@ xfs_bmap_add_attrfork( (!XFS_SB_VERSION_HASATTR2(&mp->m_sb) && version == 2)) { __int64_t sbfields = 0; - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); if (!XFS_SB_VERSION_HASATTR(&mp->m_sb)) { XFS_SB_VERSION_ADDATTR(&mp->m_sb); sbfields |= XFS_SB_VERSIONNUM; @@ -4063,10 +4061,10 @@ xfs_bmap_add_attrfork( sbfields |= (XFS_SB_VERSIONNUM | XFS_SB_FEATURES2); } if (sbfields) { - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); xfs_mod_sb(tp, sbfields); } else - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); } if ((error = xfs_bmap_finish(&tp, &flist, &committed))) goto error2; @@ -6394,7 +6392,7 @@ xfs_bmap_count_blocks( * Recursively walks each level of a btree * to count total fsblocks is use. */ -int /* error */ +STATIC int /* error */ xfs_bmap_count_tree( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ @@ -6470,7 +6468,7 @@ xfs_bmap_count_tree( /* * Count leaf blocks given a range of extent records. */ -int +STATIC int xfs_bmap_count_leaves( xfs_ifork_t *ifp, xfs_extnum_t idx, @@ -6490,7 +6488,7 @@ xfs_bmap_count_leaves( * Count leaf blocks given a range of extent records originally * in btree format. */ -int +STATIC int xfs_bmap_disk_count_leaves( xfs_extnum_t idx, xfs_bmbt_block_t *block, diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h index 68267d75ff19..87224b7d7984 100644 --- a/fs/xfs/xfs_bmap.h +++ b/fs/xfs/xfs_bmap.h @@ -25,6 +25,8 @@ 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/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 32b49ec00fb5..c4181d85605c 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c @@ -2062,8 +2062,7 @@ xfs_bmbt_insert( pcur->bc_private.b.allocated; pcur->bc_private.b.allocated = 0; ASSERT((cur->bc_private.b.firstblock != NULLFSBLOCK) || - (cur->bc_private.b.ip->i_d.di_flags & - XFS_DIFLAG_REALTIME)); + XFS_IS_REALTIME_INODE(cur->bc_private.b.ip)); cur->bc_private.b.firstblock = pcur->bc_private.b.firstblock; ASSERT(cur->bc_private.b.flist == diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h index 6e40a0a198ff..7440b78f9cec 100644 --- a/fs/xfs/xfs_btree.h +++ b/fs/xfs/xfs_btree.h @@ -24,6 +24,8 @@ 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/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index c8f2c2886fe4..63debd147eb5 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -378,7 +378,6 @@ xfs_buf_item_unpin( xfs_mount_t *mp; xfs_buf_t *bp; int freed; - SPLDECL(s); bp = bip->bli_buf; ASSERT(bp != NULL); @@ -409,8 +408,8 @@ xfs_buf_item_unpin( XFS_BUF_SET_FSPRIVATE(bp, NULL); XFS_BUF_CLR_IODONE_FUNC(bp); } else { - AIL_LOCK(mp,s); - xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip, s); + spin_lock(&mp->m_ail_lock); + xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip); xfs_buf_item_relse(bp); ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL); } @@ -1113,7 +1112,6 @@ xfs_buf_iodone( xfs_buf_log_item_t *bip) { struct xfs_mount *mp; - SPLDECL(s); ASSERT(bip->bli_buf == bp); @@ -1128,11 +1126,11 @@ xfs_buf_iodone( * * Either way, AIL is useless if we're forcing a shutdown. */ - AIL_LOCK(mp,s); + spin_lock(&mp->m_ail_lock); /* * xfs_trans_delete_ail() drops the AIL lock. */ - xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip, s); + xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip); #ifdef XFS_TRANS_DEBUG kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp)); diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h index d7e136143066..5a41c348bb1c 100644 --- a/fs/xfs/xfs_buf_item.h +++ b/fs/xfs/xfs_buf_item.h @@ -18,6 +18,8 @@ #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/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index 26d09e2e1a7f..1b446849fb3d 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/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; -lock_t xfs_dabuf_global_lock; +spinlock_t xfs_dabuf_global_lock; #endif /* @@ -2264,10 +2264,9 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra) } #ifdef XFS_DABUF_DEBUG { - SPLDECL(s); xfs_dabuf_t *p; - s = mutex_spinlock(&xfs_dabuf_global_lock); + spin_lock(&xfs_dabuf_global_lock); for (p = xfs_dabuf_global_list; p; p = p->next) { ASSERT(p->blkno != dabuf->blkno || p->target != dabuf->target); @@ -2277,7 +2276,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; - mutex_spinunlock(&xfs_dabuf_global_lock, s); + spin_unlock(&xfs_dabuf_global_lock); } #endif return dabuf; @@ -2319,16 +2318,14 @@ xfs_da_buf_done(xfs_dabuf_t *dabuf) kmem_free(dabuf->data, BBTOB(dabuf->bbcount)); #ifdef XFS_DABUF_DEBUG { - SPLDECL(s); - - s = mutex_spinlock(&xfs_dabuf_global_lock); + spin_lock(&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; - mutex_spinunlock(&xfs_dabuf_global_lock, s); + spin_unlock(&xfs_dabuf_global_lock); } memset(dabuf, 0, XFS_DA_BUF_SIZE(dabuf->nbuf)); #endif diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h index 44dabf02f2a3..7facf86f74f9 100644 --- a/fs/xfs/xfs_da_btree.h +++ b/fs/xfs/xfs_da_btree.h @@ -260,6 +260,7 @@ 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/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 584f1ae85cd9..3f53fad356a3 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c @@ -52,76 +52,72 @@ xfs_swapext( xfs_swapext_t __user *sxu) { xfs_swapext_t *sxp; - xfs_inode_t *ip=NULL, *tip=NULL; - xfs_mount_t *mp; - struct file *fp = NULL, *tfp = NULL; - bhv_vnode_t *vp, *tvp; + xfs_inode_t *ip, *tip; + struct file *file, *target_file; int error = 0; sxp = kmem_alloc(sizeof(xfs_swapext_t), KM_MAYFAIL); if (!sxp) { error = XFS_ERROR(ENOMEM); - goto error0; + goto out; } if (copy_from_user(sxp, sxu, sizeof(xfs_swapext_t))) { error = XFS_ERROR(EFAULT); - goto error0; + goto out_free_sxp; } /* Pull information for the target fd */ - if (((fp = fget((int)sxp->sx_fdtarget)) == NULL) || - ((vp = vn_from_inode(fp->f_path.dentry->d_inode)) == NULL)) { + file = fget((int)sxp->sx_fdtarget); + if (!file) { error = XFS_ERROR(EINVAL); - goto error0; + goto out_free_sxp; } - ip = xfs_vtoi(vp); - if (ip == NULL) { + if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) { error = XFS_ERROR(EBADF); - goto error0; + goto out_put_file; } - if (((tfp = fget((int)sxp->sx_fdtmp)) == NULL) || - ((tvp = vn_from_inode(tfp->f_path.dentry->d_inode)) == NULL)) { + target_file = fget((int)sxp->sx_fdtmp); + if (!target_file) { error = XFS_ERROR(EINVAL); - goto error0; + goto out_put_file; } - tip = xfs_vtoi(tvp); - if (tip == NULL) { + if (!(target_file->f_mode & FMODE_WRITE) || + (target_file->f_flags & O_APPEND)) { error = XFS_ERROR(EBADF); - goto error0; + goto out_put_target_file; } + 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 error0; + error = XFS_ERROR(EINVAL); + goto out_put_target_file; } if (ip->i_ino == tip->i_ino) { - error = XFS_ERROR(EINVAL); - goto error0; + error = XFS_ERROR(EINVAL); + goto out_put_target_file; } - mp = ip->i_mount; - - if (XFS_FORCED_SHUTDOWN(mp)) { - error = XFS_ERROR(EIO); - goto error0; + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { + error = XFS_ERROR(EIO); + goto out_put_target_file; } - 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)); + error = xfs_swap_extents(ip, tip, sxp); + 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; } @@ -169,15 +165,6 @@ 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); @@ -185,8 +172,7 @@ xfs_swap_extents( } /* Verify both files are either real-time or non-realtime */ - if ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != - (tip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { + if (XFS_IS_REALTIME_INODE(ip) != XFS_IS_REALTIME_INODE(tip)) { error = XFS_ERROR(EINVAL); goto error0; } @@ -199,7 +185,7 @@ xfs_swap_extents( } if (VN_CACHED(tvp) != 0) { - xfs_inval_cached_trace(&tip->i_iocore, 0, -1, 0, -1); + xfs_inval_cached_trace(tip, 0, -1, 0, -1); error = xfs_flushinval_pages(tip, 0, -1, FI_REMAPF_LOCKED); if (error) diff --git a/fs/xfs/xfs_dinode.h b/fs/xfs/xfs_dinode.h index dedd713574e1..c9065eaf2a4d 100644 --- a/fs/xfs/xfs_dinode.h +++ b/fs/xfs/xfs_dinode.h @@ -171,69 +171,35 @@ typedef enum xfs_dinode_fmt /* * Inode data & attribute fork sizes, per inode. */ -#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_Q(dip) ((dip)->di_core.di_forkoff != 0) +#define XFS_DFORK_BOFF(dip) ((int)((dip)->di_core.di_forkoff << 3)) #define XFS_DFORK_DSIZE(dip,mp) \ - XFS_CFORK_DSIZE_DISK(&(dip)->di_core, mp) -#define XFS_DFORK_DSIZE_HOST(dip,mp) \ - XFS_CFORK_DSIZE(&(dip)->di_core, mp) + (XFS_DFORK_Q(dip) ? \ + XFS_DFORK_BOFF(dip) : \ + XFS_LITINO(mp)) #define 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) + (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)) -#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) \ +#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_CFORK_FORMAT(dcp,w) \ - ((w) == XFS_DATA_FORK ? (dcp)->di_format : (dcp)->di_aformat) -#define XFS_CFORK_FMT_SET(dcp,w,n) \ +#define XFS_DFORK_FORMAT(dip,w) \ ((w) == XFS_DATA_FORK ? \ - ((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) \ + (dip)->di_core.di_format : \ + (dip)->di_core.di_aformat) +#define XFS_DFORK_NEXTENTS(dip,w) \ ((w) == XFS_DATA_FORK ? \ - 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))) + be32_to_cpu((dip)->di_core.di_nextents) : \ + be16_to_cpu((dip)->di_core.di_anextents)) #define XFS_BUF_TO_DINODE(bp) ((xfs_dinode_t *)XFS_BUF_PTR(bp)) @@ -273,6 +239,12 @@ 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/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index b0f1ee8fcb90..be7c4251fa61 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c @@ -42,6 +42,7 @@ #include "xfs_dir2_node.h" #include "xfs_dir2_trace.h" #include "xfs_error.h" +#include "xfs_vnodeops.h" void @@ -301,7 +302,7 @@ xfs_readdir( int rval; /* return value */ int v; /* type-checking value */ - vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(dp); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return XFS_ERROR(EIO); diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c index a4634d94e561..05e5365d3c31 100644 --- a/fs/xfs/xfs_error.c +++ b/fs/xfs/xfs_error.c @@ -230,37 +230,6 @@ 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; i<length; i++, uip++) { - if ((i % 16) == 0) { - if (*s != '\0') - cmn_err(CE_ALERT, "%s\n", sbuf); - s = sbuf; - sprintf(s, "0x%x: ", i); - while( *s != '\0') - s++; - } - sprintf(s, "%02x ", *uip); - - /* - * the kernel sprintf is a void; user sprintf returns - * the sprintf'ed string's length. Find the new end- - * of-string - */ - while( *s != '\0') - s++; - } - cmn_err(CE_ALERT, "%s\n", sbuf); -} - void xfs_corruption_error( char *tag, diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h index 10e9d9619ae5..6490d2a9f8e1 100644 --- a/fs/xfs/xfs_error.h +++ b/fs/xfs/xfs_error.h @@ -174,6 +174,8 @@ extern void xfs_cmn_err(int panic_tag, int level, struct xfs_mount *mp, /* PRINTFLIKE3 */ extern void xfs_fs_cmn_err(int level, struct xfs_mount *mp, char *fmt, ...); +extern void xfs_hex_dump(void *p, int length); + #define xfs_fs_repair_cmn_err(level, mp, fmt, args...) \ xfs_fs_cmn_err(level, mp, fmt " Unmount and run xfs_repair.", ## args) diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index f938a51be81b..132bd07b9bb8 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -110,19 +110,18 @@ STATIC void xfs_efi_item_unpin(xfs_efi_log_item_t *efip, int stale) { xfs_mount_t *mp; - SPLDECL(s); mp = efip->efi_item.li_mountp; - AIL_LOCK(mp, s); + spin_lock(&mp->m_ail_lock); 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, s); + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip); xfs_efi_item_free(efip); } else { efip->efi_flags |= XFS_EFI_COMMITTED; - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); } } @@ -138,10 +137,9 @@ 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; - AIL_LOCK(mp, s); + spin_lock(&mp->m_ail_lock); if (efip->efi_flags & XFS_EFI_CANCELED) { /* * free the xaction descriptor pointing to this item @@ -152,11 +150,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, s); + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip); xfs_efi_item_free(efip); } else { efip->efi_flags |= XFS_EFI_COMMITTED; - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); } } @@ -350,13 +348,12 @@ 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); - AIL_LOCK(mp, s); + spin_lock(&mp->m_ail_lock); ASSERT(efip->efi_next_extent >= nextents); efip->efi_next_extent -= nextents; extents_left = efip->efi_next_extent; @@ -364,10 +361,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, s); + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip); xfs_efi_item_free(efip); } else { - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); } } diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c index 36d8f6aa11af..eb03eab5ca52 100644 --- a/fs/xfs/xfs_filestream.c +++ b/fs/xfs/xfs_filestream.c @@ -348,7 +348,7 @@ _xfs_filestream_update_ag( } /* xfs_fstrm_free_func(): callback for freeing cached stream items. */ -void +STATIC void xfs_fstrm_free_func( unsigned long ino, void *data) diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index aab966276517..3bed6433d050 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h @@ -419,9 +419,13 @@ typedef struct xfs_handle { /* * ioctl commands that are used by Linux filesystems */ -#define XFS_IOC_GETXFLAGS _IOR('f', 1, long) -#define XFS_IOC_SETXFLAGS _IOW('f', 2, long) -#define XFS_IOC_GETVERSION _IOR('v', 1, long) +#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 /* * ioctl commands that replace IRIX fcntl()'s diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index c92d5b821029..b8de7f3cc17e 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -462,15 +462,13 @@ 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); - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); 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; - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); return 0; } @@ -497,7 +495,6 @@ 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) { @@ -515,7 +512,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 XFS_SB_LOCK so that if we are near + * We do this under the m_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 @@ -526,7 +523,7 @@ xfs_reserve_blocks( * enabled, disabled or even compiled in.... */ retry: - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); xfs_icsb_sync_counters_flags(mp, XFS_ICSB_SB_LOCKED); /* @@ -569,7 +566,7 @@ out: outval->resblks = mp->m_resblks; outval->resblks_avail = mp->m_resblks_avail; } - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); if (fdblks_delta) { /* diff --git a/fs/xfs/xfs_ialloc_btree.h b/fs/xfs/xfs_ialloc_btree.h index bf8e9aff272e..8efc4a5b8b92 100644 --- a/fs/xfs/xfs_ialloc_btree.h +++ b/fs/xfs/xfs_ialloc_btree.h @@ -81,8 +81,6 @@ 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/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index fb69ef180b27..f01b07687faf 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -65,7 +65,7 @@ */ STATIC int xfs_iget_core( - bhv_vnode_t *vp, + struct inode *inode, 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 @@ again: goto again; } - inode_vp = XFS_ITOV_NULL(ip); - if (inode_vp == NULL) { + old_inode = ip->i_vnode; + if (old_inode == NULL) { /* * If IRECLAIM is set this inode is * on its way out of the system, @@ -140,28 +140,9 @@ again: return ENOENT; } - /* - * 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_itrace_exit_tag(ip, "xfs_iget.alloc"); XFS_STATS_INC(xs_ig_found); - xfs_iflags_clear(ip, XFS_IRECLAIMABLE); read_unlock(&pag->pag_ici_lock); @@ -171,13 +152,11 @@ again: goto finish_inode; - } else if (vp != inode_vp) { - struct inode *inode = vn_to_inode(inode_vp); - + } else if (inode != old_inode) { /* The inode is being torn down, pause and * try again. */ - if (inode->i_state & (I_FREEING | I_CLEAR)) { + if (old_inode->i_state & (I_FREEING | I_CLEAR)) { read_unlock(&pag->pag_ici_lock); delay(1); XFS_STATS_INC(xs_ig_frecycle); @@ -190,7 +169,7 @@ again: */ cmn_err(CE_PANIC, "xfs_iget_core: ambiguous vns: vp/0x%p, invp/0x%p", - inode_vp, vp); + old_inode, inode); } /* @@ -200,20 +179,16 @@ again: XFS_STATS_INC(xs_ig_found); finish_inode: - 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 (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) { + xfs_put_perag(mp, pag); + return ENOENT; } if (lock_flags != 0) xfs_ilock(ip, lock_flags); xfs_iflags_clear(ip, XFS_ISTALE); - vn_trace_exit(ip, "xfs_iget.found", - (inst_t *)__return_address); + xfs_itrace_exit_tag(ip, "xfs_iget.found"); goto return_ip; } @@ -234,10 +209,16 @@ finish_inode: return error; } - vn_trace_exit(ip, "xfs_iget.alloc", (inst_t *)__return_address); + 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"); - xfs_inode_lock_init(ip, vp); - xfs_iocore_inode_init(ip); if (lock_flags) xfs_ilock(ip, lock_flags); @@ -333,9 +314,6 @@ finish_inode: 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; @@ -343,7 +321,7 @@ finish_inode: * 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, vp, ip); + xfs_initialize_vnode(mp, inode, ip); return 0; } @@ -363,69 +341,58 @@ xfs_iget( xfs_daddr_t bno) { struct inode *inode; - bhv_vnode_t *vp = NULL; + xfs_inode_t *ip; int error; XFS_STATS_INC(xs_ig_attempts); retry: inode = iget_locked(mp->m_super, ino); - 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 (lock_flags != 0) - xfs_ilock(ip, lock_flags); - XFS_STATS_INC(xs_ig_found); - *ipp = ip; - error = 0; + 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); } - } else - error = ENOMEM; /* If we got no inode we are out of memory */ + return error; + } - return error; -} + /* + * 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; + } -/* - * 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"); + ip = XFS_I(inode); + if (!ip) { + iput(inode); + delay(1); + goto retry; + } + + if (lock_flags != 0) + xfs_ilock(ip, lock_flags); + XFS_STATS_INC(xs_ig_found); + *ipp = ip; + return 0; } /* @@ -465,11 +432,9 @@ void xfs_iput(xfs_inode_t *ip, uint lock_flags) { - bhv_vnode_t *vp = XFS_ITOV(ip); - - vn_trace_entry(ip, "xfs_iput", (inst_t *)__return_address); + xfs_itrace_entry(ip); xfs_iunlock(ip, lock_flags); - VN_RELE(vp); + IRELE(ip); } /* @@ -479,20 +444,19 @@ void xfs_iput_new(xfs_inode_t *ip, uint lock_flags) { - bhv_vnode_t *vp = XFS_ITOV(ip); - struct inode *inode = vn_to_inode(vp); + struct inode *inode = ip->i_vnode; - vn_trace_entry(ip, "xfs_iput_new", (inst_t *)__return_address); + xfs_itrace_entry(ip); if ((ip->i_d.di_mode == 0)) { ASSERT(!xfs_iflags_test(ip, XFS_IRECLAIMABLE)); - vn_mark_bad(vp); + make_bad_inode(inode); } if (inode->i_state & I_NEW) unlock_new_inode(inode); if (lock_flags) xfs_iunlock(ip, lock_flags); - VN_RELE(vp); + IRELE(ip); } @@ -505,8 +469,6 @@ 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. */ @@ -535,9 +497,8 @@ xfs_ireclaim(xfs_inode_t *ip) /* * Pull our behavior descriptor from the vnode chain. */ - vp = XFS_ITOV_NULL(ip); - if (vp) { - vn_to_inode(vp)->i_private = NULL; + if (ip->i_vnode) { + ip->i_vnode->i_private = NULL; ip->i_vnode = NULL; } diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 344948082819..a550546a7083 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -15,6 +15,8 @@ * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <linux/log2.h> + #include "xfs.h" #include "xfs_fs.h" #include "xfs_types.h" @@ -826,15 +828,17 @@ xfs_ip2xflags( xfs_icdinode_t *dic = &ip->i_d; return _xfs_dic2xflags(dic->di_flags) | - (XFS_CFORK_Q(dic) ? XFS_XFLAG_HASATTR : 0); + (XFS_IFORK_Q(ip) ? XFS_XFLAG_HASATTR : 0); } uint xfs_dic2xflags( - xfs_dinode_core_t *dic) + xfs_dinode_t *dip) { + xfs_dinode_core_t *dic = &dip->di_core; + return _xfs_dic2xflags(be16_to_cpu(dic->di_flags)) | - (XFS_CFORK_Q_DISK(dic) ? XFS_XFLAG_HASATTR : 0); + (XFS_DFORK_Q(dip) ? XFS_XFLAG_HASATTR : 0); } /* @@ -884,8 +888,8 @@ xfs_iread( * Initialize inode's trace buffers. * Do this before xfs_iformat in case it adds entries. */ -#ifdef XFS_VNODE_TRACE - ip->i_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP); +#ifdef XFS_INODE_TRACE + ip->i_trace = ktrace_alloc(INODE_TRACE_SIZE, KM_SLEEP); #endif #ifdef XFS_BMAP_TRACE ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, KM_SLEEP); @@ -1220,10 +1224,8 @@ 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; @@ -1298,7 +1300,10 @@ xfs_isize_check( if ((ip->i_d.di_mode & S_IFMT) != S_IFREG) return; - if (ip->i_d.di_flags & (XFS_DIFLAG_REALTIME | XFS_DIFLAG_EXTSIZE)) + if (XFS_IS_REALTIME_INODE(ip)) + return; + + if (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) return; nimaps = 2; @@ -1711,7 +1716,7 @@ xfs_itruncate_finish( * runs. */ XFS_BMAP_INIT(&free_list, &first_block); - error = XFS_BUNMAPI(mp, ntp, &ip->i_iocore, + error = xfs_bunmapi(ntp, ip, first_unmap_block, unmap_len, XFS_BMAPI_AFLAG(fork) | (sync ? 0 : XFS_BMAPI_ASYNC), @@ -1844,8 +1849,6 @@ 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); @@ -1855,9 +1858,7 @@ xfs_igrow_start( * xfs_write_file() beyond the end of the file * and any blocks between the old and new file sizes. */ - error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size, - ip->i_size); - return error; + return xfs_zero_eof(ip, new_size, ip->i_size); } /* @@ -1959,24 +1960,6 @@ 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 @@ -1984,6 +1967,10 @@ 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]; @@ -2209,7 +2196,6 @@ 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; @@ -2311,9 +2297,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; - AIL_LOCK(mp,s); + spin_lock(&mp->m_ail_lock); iip->ili_flush_lsn = iip->ili_item.li_lsn; - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); xfs_iflags_set(iip->ili_inode, XFS_ISTALE); pre_flushed++; } @@ -2334,9 +2320,9 @@ xfs_ifree_cluster( iip->ili_last_fields = iip->ili_format.ilf_fields; iip->ili_format.ilf_fields = 0; iip->ili_logged = 1; - AIL_LOCK(mp,s); + spin_lock(&mp->m_ail_lock); iip->ili_flush_lsn = iip->ili_item.li_lsn; - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t*,xfs_log_item_t*)) @@ -2374,6 +2360,8 @@ 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); @@ -2409,8 +2397,27 @@ 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); } @@ -2735,7 +2742,6 @@ void xfs_idestroy( xfs_inode_t *ip) { - switch (ip->i_d.di_mode & S_IFMT) { case S_IFREG: case S_IFDIR: @@ -2749,7 +2755,7 @@ xfs_idestroy( mrfree(&ip->i_iolock); freesema(&ip->i_flock); -#ifdef XFS_VNODE_TRACE +#ifdef XFS_INODE_TRACE ktrace_free(ip->i_trace); #endif #ifdef XFS_BMAP_TRACE @@ -2775,16 +2781,15 @@ 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) { - AIL_LOCK(mp, s); + spin_lock(&mp->m_ail_lock); if (lip->li_flags & XFS_LI_IN_AIL) - xfs_trans_delete_ail(mp, lip, s); + xfs_trans_delete_ail(mp, lip); else - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); } xfs_inode_item_destroy(ip); } @@ -2816,40 +2821,8 @@ xfs_iunpin( { ASSERT(atomic_read(&ip->i_pincount) > 0); - 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); + if (atomic_dec_and_test(&ip->i_pincount)) wake_up(&ip->i_ipin_wait); - } } /* @@ -3338,7 +3311,6 @@ 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))); @@ -3533,9 +3505,9 @@ xfs_iflush_int( iip->ili_logged = 1; ASSERT(sizeof(xfs_lsn_t) == 8); /* don't lock if it shrinks */ - AIL_LOCK(mp,s); + spin_lock(&mp->m_ail_lock); iip->ili_flush_lsn = iip->ili_item.li_lsn; - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); /* * Attach the function xfs_iflush_done to the inode's @@ -3611,95 +3583,6 @@ 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; @@ -4206,7 +4089,7 @@ xfs_iext_realloc_direct( return; } if (!is_power_of_2(new_size)){ - rnew_size = xfs_iroundup(new_size); + rnew_size = roundup_pow_of_two(new_size); } if (rnew_size != ifp->if_real_bytes) { ifp->if_u1.if_extents = @@ -4229,7 +4112,7 @@ xfs_iext_realloc_direct( else { new_size += ifp->if_bytes; if (!is_power_of_2(new_size)) { - rnew_size = xfs_iroundup(new_size); + rnew_size = roundup_pow_of_two(new_size); } xfs_iext_inline_to_direct(ifp, rnew_size); } diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index e5aff929cc65..bfcd72cbaeea 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -132,45 +132,6 @@ 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 @@ -181,7 +142,7 @@ typedef struct xfs_icluster { xfs_daddr_t icl_blkno; /* starting block number of * the cluster */ struct xfs_buf *icl_buf; /* the inode buffer */ - lock_t icl_lock; /* inode list lock */ + spinlock_t icl_lock; /* inode list lock */ } xfs_icluster_t; /* @@ -283,9 +244,6 @@ 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 */ @@ -298,9 +256,10 @@ 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_VNODE_TRACE +#ifdef XFS_INODE_TRACE struct ktrace *i_trace; /* general inode trace */ #endif #ifdef XFS_BMAP_TRACE @@ -382,17 +341,42 @@ 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__ @@ -509,7 +493,6 @@ 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); @@ -545,7 +528,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_core *); +uint xfs_dic2xflags(struct xfs_dinode *); int xfs_ifree(struct xfs_trans *, xfs_inode_t *, struct xfs_bmap_free *); int xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t); @@ -567,13 +550,12 @@ 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/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 565d470a6b4a..034ca7202295 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c @@ -274,6 +274,11 @@ 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); @@ -615,7 +620,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); @@ -749,7 +754,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 @@ -792,7 +797,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. @@ -968,7 +973,6 @@ xfs_iflush_done( xfs_inode_log_item_t *iip) { xfs_inode_t *ip; - SPLDECL(s); ip = iip->ili_inode; @@ -983,15 +987,15 @@ xfs_iflush_done( */ if (iip->ili_logged && (iip->ili_item.li_lsn == iip->ili_flush_lsn)) { - AIL_LOCK(ip->i_mount, s); + spin_lock(&ip->i_mount->m_ail_lock); 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, s); + (xfs_log_item_t*)iip); } else { - AIL_UNLOCK(ip->i_mount, s); + spin_unlock(&ip->i_mount->m_ail_lock); } } @@ -1025,21 +1029,19 @@ 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) { - AIL_LOCK(mp, s); + spin_lock(&mp->m_ail_lock); 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, - s); + xfs_trans_delete_ail(mp, (xfs_log_item_t *)iip); } else - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); } iip->ili_logged = 0; /* diff --git a/fs/xfs/xfs_iocore.c b/fs/xfs/xfs_iocore.c deleted file mode 100644 index b27b5d5be841..000000000000 --- a/fs/xfs/xfs_iocore.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 72786e356d56..fde37f87d52f 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -53,12 +53,10 @@ void xfs_iomap_enter_trace( int tag, - xfs_iocore_t *io, + xfs_inode_t *ip, xfs_off_t offset, ssize_t count) { - xfs_inode_t *ip = XFS_IO_INODE(io); - if (!ip->i_rwtrace) return; @@ -70,8 +68,8 @@ xfs_iomap_enter_trace( (void *)((unsigned long)((offset >> 32) & 0xffffffff)), (void *)((unsigned long)(offset & 0xffffffff)), (void *)((unsigned long)count), - (void *)((unsigned long)((io->io_new_size >> 32) & 0xffffffff)), - (void *)((unsigned long)(io->io_new_size & 0xffffffff)), + (void *)((unsigned long)((ip->i_new_size >> 32) & 0xffffffff)), + (void *)((unsigned long)(ip->i_new_size & 0xffffffff)), (void *)((unsigned long)current_pid()), (void *)NULL, (void *)NULL, @@ -84,15 +82,13 @@ xfs_iomap_enter_trace( void xfs_iomap_map_trace( int tag, - xfs_iocore_t *io, + xfs_inode_t *ip, 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; @@ -126,7 +122,7 @@ xfs_iomap_map_trace( STATIC int xfs_imap_to_bmap( - xfs_iocore_t *io, + xfs_inode_t *ip, xfs_off_t offset, xfs_bmbt_irec_t *imap, xfs_iomap_t *iomapp, @@ -134,11 +130,10 @@ xfs_imap_to_bmap( int iomaps, /* Number of iomap entries */ int flags) { - xfs_mount_t *mp; + xfs_mount_t *mp = ip->i_mount; 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); @@ -146,7 +141,7 @@ xfs_imap_to_bmap( iomapp->iomap_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount); iomapp->iomap_flags = flags; - if (io->io_flags & XFS_IOCORE_RT) { + if (XFS_IS_REALTIME_INODE(ip)) { iomapp->iomap_flags |= IOMAP_REALTIME; iomapp->iomap_target = mp->m_rtdev_targp; } else { @@ -160,7 +155,7 @@ xfs_imap_to_bmap( iomapp->iomap_bn = IOMAP_DADDR_NULL; iomapp->iomap_flags |= IOMAP_DELAY; } else { - iomapp->iomap_bn = XFS_FSB_TO_DB_IO(io, start_block); + iomapp->iomap_bn = XFS_FSB_TO_DB(ip, start_block); if (ISUNWRITTEN(imap)) iomapp->iomap_flags |= IOMAP_UNWRITTEN; } @@ -172,14 +167,14 @@ xfs_imap_to_bmap( int xfs_iomap( - xfs_iocore_t *io, + xfs_inode_t *ip, xfs_off_t offset, ssize_t count, int flags, xfs_iomap_t *iomapp, int *niomaps) { - xfs_mount_t *mp = io->io_mount; + xfs_mount_t *mp = ip->i_mount; xfs_fileoff_t offset_fsb, end_fsb; int error = 0; int lockmode = 0; @@ -188,45 +183,37 @@ 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 | - BMAPI_UNWRITTEN | BMAPI_DEVICE)) { + switch (flags & (BMAPI_READ | BMAPI_WRITE | BMAPI_ALLOCATE)) { case BMAPI_READ: - xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, io, offset, count); - lockmode = XFS_LCK_MAP_SHARED(mp, io); + xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, ip, offset, count); + lockmode = xfs_ilock_map_shared(ip); bmapi_flags = XFS_BMAPI_ENTIRE; break; case BMAPI_WRITE: - xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, io, offset, count); + xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, ip, offset, count); lockmode = XFS_ILOCK_EXCL|XFS_EXTSIZE_WR; if (flags & BMAPI_IGNSTATE) bmapi_flags |= XFS_BMAPI_IGSTATE|XFS_BMAPI_ENTIRE; - XFS_ILOCK(mp, io, lockmode); + xfs_ilock(ip, lockmode); break; case BMAPI_ALLOCATE: - xfs_iomap_enter_trace(XFS_IOMAP_ALLOC_ENTER, io, offset, count); + xfs_iomap_enter_trace(XFS_IOMAP_ALLOC_ENTER, ip, 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(mp, io, lockmode)) + if (!xfs_ilock_nowait(ip, lockmode)) return XFS_ERROR(EAGAIN); } else { - XFS_ILOCK(mp, io, lockmode); + xfs_ilock(ip, 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(); } @@ -237,7 +224,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(mp, NULL, io, offset_fsb, + error = xfs_bmapi(NULL, ip, offset_fsb, (xfs_filblks_t)(end_fsb - offset_fsb), bmapi_flags, NULL, 0, &imap, &nimaps, NULL, NULL); @@ -245,54 +232,48 @@ xfs_iomap( if (error) goto out; -phase2: - switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE|BMAPI_UNWRITTEN)) { + switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE)) { 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, io, + xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, ip, offset, count, iomapp, &imap, flags); break; } if (flags & (BMAPI_DIRECT|BMAPI_MMAP)) { - error = XFS_IOMAP_WRITE_DIRECT(mp, io, offset, - count, flags, &imap, &nimaps, nimaps); + error = xfs_iomap_write_direct(ip, offset, count, flags, + &imap, &nimaps, nimaps); } else { - error = XFS_IOMAP_WRITE_DELAY(mp, io, offset, count, - flags, &imap, &nimaps); + error = xfs_iomap_write_delay(ip, offset, count, flags, + &imap, &nimaps); } if (!error) { - xfs_iomap_map_trace(XFS_IOMAP_ALLOC_MAP, io, + xfs_iomap_map_trace(XFS_IOMAP_ALLOC_MAP, ip, offset, count, iomapp, &imap, flags); } iomap_flags = IOMAP_NEW; break; case BMAPI_ALLOCATE: /* If we found an extent, return it */ - XFS_IUNLOCK(mp, io, lockmode); + xfs_iunlock(ip, lockmode); lockmode = 0; if (nimaps && !ISNULLSTARTBLOCK(imap.br_startblock)) { - xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io, + xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, ip, offset, count, iomapp, &imap, flags); break; } - error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, offset, count, + error = xfs_iomap_write_allocate(ip, 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(io, offset, &imap, + *niomaps = xfs_imap_to_bmap(ip, offset, &imap, iomapp, nimaps, *niomaps, iomap_flags); } else if (niomaps) { *niomaps = 0; @@ -300,14 +281,15 @@ phase2: out: if (lockmode) - XFS_IUNLOCK(mp, io, lockmode); + xfs_iunlock(ip, lockmode); return XFS_ERROR(error); } + STATIC int xfs_iomap_eof_align_last_fsb( xfs_mount_t *mp, - xfs_iocore_t *io, + xfs_inode_t *ip, xfs_fsize_t isize, xfs_extlen_t extsize, xfs_fileoff_t *last_fsb) @@ -316,7 +298,7 @@ xfs_iomap_eof_align_last_fsb( xfs_extlen_t align; int eof, error; - if (io->io_flags & XFS_IOCORE_RT) + if (XFS_IS_REALTIME_INODE(ip)) ; /* * If mounted with the "-o swalloc" option, roundup the allocation @@ -347,7 +329,7 @@ xfs_iomap_eof_align_last_fsb( } if (new_last_fsb) { - error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof); + error = xfs_bmap_eof(ip, new_last_fsb, XFS_DATA_FORK, &eof); if (error) return error; if (eof) @@ -416,7 +398,6 @@ 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; @@ -446,13 +427,13 @@ xfs_iomap_write_direct( extsz = xfs_get_extsz_hint(ip); isize = ip->i_size; - if (io->io_new_size > isize) - isize = io->io_new_size; + if (ip->i_new_size > isize) + isize = ip->i_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, io, isize, extsz, + error = xfs_iomap_eof_align_last_fsb(mp, ip, isize, extsz, &last_fsb); if (error) goto error_out; @@ -519,7 +500,7 @@ xfs_iomap_write_direct( */ XFS_BMAP_INIT(&free_list, &firstfsb); nimaps = 1; - error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb, bmapi_flag, + error = xfs_bmapi(tp, ip, offset_fsb, count_fsb, bmapi_flag, &firstfsb, 0, &imap, &nimaps, &free_list, NULL); if (error) goto error0; @@ -542,7 +523,8 @@ xfs_iomap_write_direct( goto error_out; } - if (unlikely(!imap.br_startblock && !(io->io_flags & XFS_IOCORE_RT))) { + if (unlikely(!imap.br_startblock && + !(XFS_IS_REALTIME_INODE(ip)))) { error = xfs_cmn_err_fsblock_zero(ip, &imap); goto error_out; } @@ -577,7 +559,7 @@ error_out: STATIC int xfs_iomap_eof_want_preallocate( xfs_mount_t *mp, - xfs_iocore_t *io, + xfs_inode_t *ip, xfs_fsize_t isize, xfs_off_t offset, size_t count, @@ -604,7 +586,7 @@ xfs_iomap_eof_want_preallocate( while (count_fsb > 0) { imaps = nimaps; firstblock = NULLFSBLOCK; - error = XFS_BMAPI(mp, NULL, io, start_fsb, count_fsb, 0, + error = xfs_bmapi(NULL, ip, start_fsb, count_fsb, 0, &firstblock, 0, imap, &imaps, NULL, NULL); if (error) return error; @@ -630,7 +612,6 @@ 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; @@ -658,10 +639,10 @@ xfs_iomap_write_delay( retry: isize = ip->i_size; - if (io->io_new_size > isize) - isize = io->io_new_size; + if (ip->i_new_size > isize) + isize = ip->i_new_size; - error = xfs_iomap_eof_want_preallocate(mp, io, isize, offset, count, + error = xfs_iomap_eof_want_preallocate(mp, ip, isize, offset, count, ioflag, imap, XFS_WRITE_IMAPS, &prealloc); if (error) return error; @@ -675,7 +656,7 @@ retry: } if (prealloc || extsz) { - error = xfs_iomap_eof_align_last_fsb(mp, io, isize, extsz, + error = xfs_iomap_eof_align_last_fsb(mp, ip, isize, extsz, &last_fsb); if (error) return error; @@ -683,7 +664,7 @@ retry: nimaps = XFS_WRITE_IMAPS; firstblock = NULLFSBLOCK; - error = XFS_BMAPI(mp, NULL, io, offset_fsb, + error = xfs_bmapi(NULL, ip, offset_fsb, (xfs_filblks_t)(last_fsb - offset_fsb), XFS_BMAPI_DELAY | XFS_BMAPI_WRITE | XFS_BMAPI_ENTIRE, &firstblock, 1, imap, @@ -697,7 +678,7 @@ retry: */ if (nimaps == 0) { xfs_iomap_enter_trace(XFS_IOMAP_WRITE_NOSPACE, - io, offset, count); + ip, offset, count); if (xfs_flush_space(ip, &fsynced, &ioflag)) return XFS_ERROR(ENOSPC); @@ -705,7 +686,8 @@ retry: goto retry; } - if (unlikely(!imap[0].br_startblock && !(io->io_flags & XFS_IOCORE_RT))) + if (unlikely(!imap[0].br_startblock && + !(XFS_IS_REALTIME_INODE(ip)))) return xfs_cmn_err_fsblock_zero(ip, &imap[0]); *ret_imap = imap[0]; @@ -720,6 +702,9 @@ retry: * 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( @@ -730,15 +715,14 @@ 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_STRAT_WRITE_IMAPS]; + xfs_bmbt_irec_t imap; xfs_trans_t *tp; - int i, nimaps, committed; + int nimaps, committed; int error = 0; int nres; @@ -785,13 +769,38 @@ xfs_iomap_write_allocate( XFS_BMAP_INIT(&free_list, &first_block); - nimaps = XFS_STRAT_WRITE_IMAPS; /* - * 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. + * 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.... */ - + nimaps = 1; end_fsb = XFS_B_TO_FSB(mp, ip->i_size); xfs_bmap_last_offset(NULL, ip, &last_block, XFS_DATA_FORK); @@ -805,9 +814,9 @@ xfs_iomap_write_allocate( } /* Go get the actual blocks */ - error = XFS_BMAPI(mp, tp, io, map_start_fsb, count_fsb, + error = xfs_bmapi(tp, ip, 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; @@ -826,27 +835,24 @@ xfs_iomap_write_allocate( * See if we were able to allocate an extent that * covers at least part of the callers request */ - 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; + 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; } - /* 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. */ - nimaps--; - map_start_fsb = imap[nimaps].br_startoff + - imap[nimaps].br_blockcount; + count_fsb -= imap.br_blockcount; + map_start_fsb = imap.br_startoff + imap.br_blockcount; } trans_cancel: @@ -864,7 +870,6 @@ 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; @@ -877,8 +882,7 @@ xfs_iomap_write_unwritten( int committed; int error; - xfs_iomap_enter_trace(XFS_IOMAP_UNWRITTEN, - &ip->i_iocore, offset, count); + xfs_iomap_enter_trace(XFS_IOMAP_UNWRITTEN, ip, offset, count); offset_fsb = XFS_B_TO_FSBT(mp, offset); count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); @@ -912,7 +916,7 @@ xfs_iomap_write_unwritten( */ XFS_BMAP_INIT(&free_list, &firstfsb); nimaps = 1; - error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb, + error = xfs_bmapi(tp, ip, offset_fsb, count_fsb, XFS_BMAPI_WRITE|XFS_BMAPI_CONVERT, &firstfsb, 1, &imap, &nimaps, &free_list, NULL); if (error) @@ -928,7 +932,7 @@ xfs_iomap_write_unwritten( return XFS_ERROR(error); if (unlikely(!imap.br_startblock && - !(io->io_flags & XFS_IOCORE_RT))) + !(XFS_IS_REALTIME_INODE(ip)))) return xfs_cmn_err_fsblock_zero(ip, &imap); if ((numblks_fsb = imap.br_blockcount) == 0) { diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h index f5c09887fe93..ee1a0c134cc2 100644 --- a/fs/xfs/xfs_iomap.h +++ b/fs/xfs/xfs_iomap.h @@ -36,14 +36,12 @@ 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; @@ -73,11 +71,10 @@ 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_iocore *, xfs_off_t, ssize_t, int, +extern int xfs_iomap(struct xfs_inode *, 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/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 9fc4c2886529..658aab6b1bbf 100644 --- a/fs/xfs/xfs_itable.c +++ b/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(dic); + buf->bs_xflags = xfs_dic2xflags(dip); 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_nlink == 0. + * Check the buffer containing the on-disk inode for di_mode == 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_nlink) + !dip->di_core.di_mode) 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_CFORK_Q(&dip->di_core) == 0) || + if ((XFS_DFORK_Q(dip) == 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, NBPC, NBPC * 4, + irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 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)(NBPP / sizeof(*buffer))); + bcount = MIN(left, (int)(PAGE_SIZE / sizeof(*buffer))); buffer = kmem_alloc(bcount * sizeof(*buffer), KM_SLEEP); error = bufidx = 0; cur = NULL; diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 77c12715a7d0..b3ac3805d3c4 100644 --- a/fs/xfs/xfs_log.c +++ b/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, spl; + int abortflg; cb->cb_next = NULL; - spl = LOG_LOCK(log); + spin_lock(&log->l_icloglock); 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); } - LOG_UNLOCK(log, spl); + spin_unlock(&log->l_icloglock); return abortflg; } /* xfs_log_notify */ @@ -498,11 +498,14 @@ 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 { @@ -515,11 +518,21 @@ xfs_log_mount(xfs_mount_t *mp, 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 error, readonly = (mp->m_flags & XFS_MOUNT_RDONLY); + int readonly = (mp->m_flags & XFS_MOUNT_RDONLY); if (readonly) mp->m_flags &= ~XFS_MOUNT_RDONLY; @@ -530,8 +543,7 @@ xfs_log_mount(xfs_mount_t *mp, mp->m_flags |= XFS_MOUNT_RDONLY; if (error) { cmn_err(CE_WARN, "XFS: log mount/recovery failed: error %d", error); - xlog_dealloc_log(mp->m_log); - return error; + goto error; } } @@ -540,6 +552,9 @@ xfs_log_mount(xfs_mount_t *mp, /* End mounting message in xfs_log_mount_finish */ return 0; +error: + xfs_log_unmount_dealloc(mp); + return error; } /* xfs_log_mount */ /* @@ -606,7 +621,6 @@ 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 { @@ -659,24 +673,24 @@ xfs_log_unmount_write(xfs_mount_t *mp) } - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); iclog = log->l_iclog; iclog->ic_refcnt++; - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); xlog_state_want_sync(log, iclog); (void) xlog_state_release_iclog(log, iclog); - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); 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 { - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); } } else { - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); } if (tic) { xlog_trace_loggrant(log, tic, "unmount rec"); @@ -697,15 +711,15 @@ xfs_log_unmount_write(xfs_mount_t *mp) * a file system that went into forced_shutdown as * the result of an unmount.. */ - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); iclog = log->l_iclog; iclog->ic_refcnt++; - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); xlog_state_want_sync(log, iclog); (void) xlog_state_release_iclog(log, iclog); - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); if ( ! ( iclog->ic_state == XLOG_STATE_ACTIVE || iclog->ic_state == XLOG_STATE_DIRTY @@ -714,7 +728,7 @@ xfs_log_unmount_write(xfs_mount_t *mp) sv_wait(&iclog->ic_forcesema, PMEM, &log->l_icloglock, s); } else { - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); } } @@ -723,10 +737,14 @@ 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); } @@ -762,20 +780,18 @@ 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 */ - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); tail_lsn = log->l_last_sync_lsn; - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); } - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); /* Also an invalid lsn. 1 implies that we aren't passing in a valid * tail_lsn. @@ -824,7 +840,7 @@ xfs_log_move_tail(xfs_mount_t *mp, tic = tic->t_next; } while (tic != log->l_reserve_headq); } - GRANT_UNLOCK(log, s); + spin_unlock(&log->l_grant_lock); } /* xfs_log_move_tail */ /* @@ -836,14 +852,13 @@ 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; - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); if (((log->l_covered_state == XLOG_STATE_COVER_NEED) || (log->l_covered_state == XLOG_STATE_COVER_NEED2)) && !xfs_trans_first_ail(mp, &gen) @@ -856,7 +871,7 @@ xfs_log_need_covered(xfs_mount_t *mp) } needed = 1; } - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); return needed; } @@ -881,17 +896,16 @@ 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); - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); if (tail_lsn != 0) { log->l_tail_lsn = tail_lsn; } else { tail_lsn = log->l_tail_lsn = log->l_last_sync_lsn; } - GRANT_UNLOCK(log, s); + spin_unlock(&log->l_grant_lock); return tail_lsn; } /* xlog_assign_tail_lsn */ @@ -911,7 +925,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. */ -int +STATIC int xlog_space_left(xlog_t *log, int cycle, int bytes) { int free_bytes; @@ -1165,7 +1179,7 @@ xlog_alloc_log(xfs_mount_t *mp, log->l_flags |= XLOG_ACTIVE_RECOVERY; log->l_prev_block = -1; - ASSIGN_ANY_LSN_HOST(log->l_tail_lsn, 1, 0); + log->l_tail_lsn = xlog_assign_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 */ @@ -1193,8 +1207,8 @@ xlog_alloc_log(xfs_mount_t *mp, ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); log->l_xbuf = bp; - spinlock_init(&log->l_icloglock, "iclog"); - spinlock_init(&log->l_grant_lock, "grhead_iclog"); + spin_lock_init(&log->l_icloglock); + spin_lock_init(&log->l_grant_lock); initnsema(&log->l_flushsema, 0, "ic-flush"); xlog_state_ticket_alloc(log); /* wait until after icloglock inited */ @@ -1231,12 +1245,12 @@ xlog_alloc_log(xfs_mount_t *mp, head = &iclog->ic_header; memset(head, 0, sizeof(xlog_rec_header_t)); - INT_SET(head->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM); - INT_SET(head->h_version, ARCH_CONVERT, + head->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM); + head->h_version = cpu_to_be32( XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? 2 : 1); - INT_SET(head->h_size, ARCH_CONVERT, log->l_iclog_size); + head->h_size = cpu_to_be32(log->l_iclog_size); /* new fields */ - INT_SET(head->h_fmt, ARCH_CONVERT, XLOG_FMT); + head->h_fmt = cpu_to_be32(XLOG_FMT); memcpy(&head->h_fs_uuid, &mp->m_sb.sb_uuid, sizeof(uuid_t)); @@ -1293,7 +1307,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. */ -void +STATIC void xlog_grant_push_ail(xfs_mount_t *mp, int need_bytes) { @@ -1305,11 +1319,10 @@ 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); - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); free_bytes = xlog_space_left(log, log->l_grant_reserve_cycle, log->l_grant_reserve_bytes); @@ -1331,8 +1344,7 @@ xlog_grant_push_ail(xfs_mount_t *mp, threshold_block -= log->l_logBBsize; threshold_cycle += 1; } - ASSIGN_ANY_LSN_HOST(threshold_lsn, threshold_cycle, - threshold_block); + threshold_lsn = xlog_assign_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. @@ -1340,7 +1352,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; } - GRANT_UNLOCK(log, s); + spin_unlock(&log->l_grant_lock); /* * Get the transaction layer to kick the dirty buffers out to @@ -1378,19 +1390,18 @@ xlog_grant_push_ail(xfs_mount_t *mp, * is added immediately before calling bwrite(). */ -int +STATIC 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, ops; + int i; 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); @@ -1415,30 +1426,26 @@ xlog_sync(xlog_t *log, roundoff < BBTOB(1))); /* move grant heads by roundoff in sync */ - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); xlog_grant_add_space(log, roundoff); - GRANT_UNLOCK(log, s); + spin_unlock(&log->l_grant_lock); /* put cycle number in every block */ xlog_pack_data(log, iclog, roundoff); /* real byte length */ if (v2) { - INT_SET(iclog->ic_header.h_len, - ARCH_CONVERT, - iclog->ic_offset + roundoff); + iclog->ic_header.h_len = + cpu_to_be32(iclog->ic_offset + roundoff); } else { - INT_SET(iclog->ic_header.h_len, ARCH_CONVERT, iclog->ic_offset); + iclog->ic_header.h_len = + cpu_to_be32(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(INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT))); + XFS_BUF_SET_ADDR(bp, BLOCK_LSN(be64_to_cpu(iclog->ic_header.h_lsn))); XFS_STATS_ADD(xs_log_blocks, BTOBB(count)); @@ -1501,10 +1508,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) { - INT_MOD(*(uint *)dptr, ARCH_CONVERT, +1); - if (INT_GET(*(uint *)dptr, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) - INT_MOD(*(uint *)dptr, ARCH_CONVERT, +1); + 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); dptr += BBSIZE; } @@ -1527,14 +1534,13 @@ xlog_sync(xlog_t *log, /* * Deallocate a log structure */ -void +STATIC void xlog_dealloc_log(xlog_t *log) { xlog_in_core_t *iclog, *next_iclog; xlog_ticket_t *tic, *next_tic; int i; - iclog = log->l_iclog; for (i=0; i<log->l_iclog_bufs; i++) { sv_destroy(&iclog->ic_forcesema); @@ -1565,7 +1571,7 @@ xlog_dealloc_log(xlog_t *log) tic = log->l_unmount_free; while (tic) { next_tic = tic->t_next; - kmem_free(tic, NBPP); + kmem_free(tic, PAGE_SIZE); tic = next_tic; } } @@ -1592,14 +1598,12 @@ xlog_state_finish_copy(xlog_t *log, int record_cnt, int copy_bytes) { - SPLDECL(s); + spin_lock(&log->l_icloglock); - s = LOG_LOCK(log); - - iclog->ic_header.h_num_logops += record_cnt; + be32_add(&iclog->ic_header.h_num_logops, record_cnt); iclog->ic_offset += copy_bytes; - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); } /* xlog_state_finish_copy */ @@ -1752,7 +1756,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. */ -int +STATIC int xlog_write(xfs_mount_t * mp, xfs_log_iovec_t reg[], int nentries, @@ -1823,7 +1827,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 = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT); + *start_lsn = be64_to_cpu(iclog->ic_header.h_lsn); /* This loop writes out as many regions as can fit in the amount * of space which was allocated by xlog_state_get_iclog_space(). @@ -1839,7 +1843,7 @@ xlog_write(xfs_mount_t * mp, */ if (ticket->t_flags & XLOG_TIC_INITED) { logop_head = (xlog_op_header_t *)ptr; - INT_SET(logop_head->oh_tid, ARCH_CONVERT, ticket->t_tid); + logop_head->oh_tid = cpu_to_be32(ticket->t_tid); logop_head->oh_clientid = ticket->t_clientid; logop_head->oh_len = 0; logop_head->oh_flags = XLOG_START_TRANS; @@ -1853,7 +1857,7 @@ xlog_write(xfs_mount_t * mp, /* Copy log operation header directly into data section */ logop_head = (xlog_op_header_t *)ptr; - INT_SET(logop_head->oh_tid, ARCH_CONVERT, ticket->t_tid); + logop_head->oh_tid = cpu_to_be32(ticket->t_tid); logop_head->oh_clientid = ticket->t_clientid; logop_head->oh_res2 = 0; @@ -1888,13 +1892,14 @@ xlog_write(xfs_mount_t * mp, copy_off = partial_copy_len; if (need_copy <= iclog->ic_size - log_offset) { /*complete write */ - INT_SET(logop_head->oh_len, ARCH_CONVERT, copy_len = need_copy); + copy_len = need_copy; + logop_head->oh_len = cpu_to_be32(copy_len); 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; - INT_SET(logop_head->oh_len, ARCH_CONVERT, copy_len); + logop_head->oh_len = cpu_to_be32(copy_len); logop_head->oh_flags |= XLOG_CONTINUE_TRANS; if (partial_copy) logop_head->oh_flags |= XLOG_WAS_CONT_TRANS; @@ -1992,7 +1997,8 @@ xlog_state_clean_log(xlog_t *log) * We don't need to cover the dummy. */ if (!changed && - (INT_GET(iclog->ic_header.h_num_logops, ARCH_CONVERT) == XLOG_COVER_OPS)) { + (be32_to_cpu(iclog->ic_header.h_num_logops) == + XLOG_COVER_OPS)) { changed = 1; } else { /* @@ -2060,7 +2066,7 @@ xlog_get_lowest_lsn( lowest_lsn = 0; do { if (!(lsn_log->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_DIRTY))) { - lsn = INT_GET(lsn_log->ic_header.h_lsn, ARCH_CONVERT); + lsn = be64_to_cpu(lsn_log->ic_header.h_lsn); if ((lsn && !lowest_lsn) || (XFS_LSN_CMP(lsn, lowest_lsn) < 0)) { lowest_lsn = lsn; @@ -2089,9 +2095,8 @@ xlog_state_do_callback( int funcdidcallbacks; /* flag: function did callbacks */ int repeats; /* for issuing console warnings if * looping too many times */ - SPLDECL(s); - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); first_iclog = iclog = log->l_iclog; ioerrors = 0; funcdidcallbacks = 0; @@ -2136,7 +2141,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 LOG_LOCK. + * we are holding the l_icloglock. */ if (!(iclog->ic_state & (XLOG_STATE_DONE_SYNC | @@ -2162,11 +2167,9 @@ xlog_state_do_callback( */ lowest_lsn = xlog_get_lowest_lsn(log); - if (lowest_lsn && ( - XFS_LSN_CMP( - lowest_lsn, - INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT) - )<0)) { + if (lowest_lsn && + XFS_LSN_CMP(lowest_lsn, + be64_to_cpu(iclog->ic_header.h_lsn)) < 0) { iclog = iclog->ic_next; continue; /* Leave this iclog for * another thread */ @@ -2174,19 +2177,18 @@ xlog_state_do_callback( iclog->ic_state = XLOG_STATE_CALLBACK; - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); /* l_last_sync_lsn field protected by - * GRANT_LOCK. Don't worry about iclog's lsn. + * l_grant_lock. Don't worry about iclog's lsn. * No one else can be here except us. */ - 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); + 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); /* * Keep processing entries in the callback list @@ -2195,7 +2197,7 @@ xlog_state_do_callback( * empty and change the state to DIRTY so that * we don't miss any more callbacks being added. */ - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); } else { ioerrors++; } @@ -2204,14 +2206,14 @@ xlog_state_do_callback( while (cb) { iclog->ic_callback_tail = &(iclog->ic_callback); iclog->ic_callback = NULL; - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); /* perform callbacks in the order given */ for (; cb; cb = cb_next) { cb_next = cb->cb_next; cb->cb_func(cb->cb_arg, aborted); } - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); cb = iclog->ic_callback; } @@ -2258,7 +2260,7 @@ xlog_state_do_callback( * * SYNCING - i/o completion will go through logs * DONE_SYNC - interrupt thread should be waiting for - * LOG_LOCK + * l_icloglock * IOERROR - give up hope all ye who enter here */ if (iclog->ic_state == XLOG_STATE_WANT_SYNC || @@ -2276,7 +2278,7 @@ xlog_state_do_callback( flushcnt = log->l_flushcnt; log->l_flushcnt = 0; } - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); while (flushcnt--) vsema(&log->l_flushsema); } /* xlog_state_do_callback */ @@ -2296,15 +2298,14 @@ 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. */ -void +STATIC void xlog_state_done_syncing( xlog_in_core_t *iclog, int aborted) { xlog_t *log = iclog->ic_log; - SPLDECL(s); - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); ASSERT(iclog->ic_state == XLOG_STATE_SYNCING || iclog->ic_state == XLOG_STATE_IOERROR); @@ -2320,7 +2321,7 @@ xlog_state_done_syncing( */ if (iclog->ic_state != XLOG_STATE_IOERROR) { if (--iclog->ic_bwritecnt == 1) { - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); return; } iclog->ic_state = XLOG_STATE_DONE_SYNC; @@ -2332,7 +2333,7 @@ xlog_state_done_syncing( * I/O, the others get to wait for the result. */ sv_broadcast(&iclog->ic_writesema); - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); xlog_state_do_callback(log, aborted, iclog); /* also cleans log */ } /* xlog_state_done_syncing */ @@ -2357,7 +2358,7 @@ xlog_state_done_syncing( * needs to be incremented, depending on the amount of data which * is copied. */ -int +STATIC int xlog_state_get_iclog_space(xlog_t *log, int len, xlog_in_core_t **iclogp, @@ -2365,23 +2366,22 @@ 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: - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); if (XLOG_FORCED_SHUTDOWN(log)) { - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); return XFS_ERROR(EIO); } iclog = log->l_iclog; if (! (iclog->ic_state == XLOG_STATE_ACTIVE)) { log->l_flushcnt++; - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); xlog_trace_iclog(iclog, XLOG_TRACE_SLEEP_FLUSH); XFS_STATS_INC(xs_log_noiclogs); /* Ensure that log writes happen */ @@ -2404,8 +2404,9 @@ restart: xlog_tic_add_region(ticket, log->l_iclog_hsize, XLOG_REG_TYPE_LRHEADER); - INT_SET(head->h_cycle, ARCH_CONVERT, log->l_curr_cycle); - ASSIGN_LSN(head->h_lsn, log); + 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)); ASSERT(log->l_curr_block >= 0); } @@ -2423,12 +2424,12 @@ restart: /* If I'm the only one writing to this iclog, sync it to disk */ if (iclog->ic_refcnt == 1) { - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); if ((error = xlog_state_release_iclog(log, iclog))) return error; } else { iclog->ic_refcnt--; - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); } goto restart; } @@ -2449,7 +2450,7 @@ restart: *iclogp = iclog; ASSERT(iclog->ic_offset <= iclog->ic_size); - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); *logoffsetp = log_offset; return 0; @@ -2467,7 +2468,6 @@ 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? */ - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); 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"); - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); } if (tic->t_flags & XFS_LOG_PERM_RESERV) need_bytes = tic->t_unit_res*tic->t_ocnt; @@ -2524,14 +2524,14 @@ redo: sv_wait(&tic->t_sema, PINOD|PLTWAIT, &log->l_grant_lock, s); if (XLOG_FORCED_SHUTDOWN(log)) { - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); goto error_return; } xlog_trace_loggrant(log, tic, "xlog_grant_log_space: wake 2"); xlog_grant_push_ail(log->l_mp, need_bytes); - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); goto redo; } else if (tic->t_flags & XLOG_TIC_IN_Q) xlog_del_ticketq(&log->l_reserve_headq, tic); @@ -2553,7 +2553,7 @@ redo: #endif xlog_trace_loggrant(log, tic, "xlog_grant_log_space: exit"); xlog_verify_grant_head(log, 1); - GRANT_UNLOCK(log, s); + spin_unlock(&log->l_grant_lock); return 0; error_return: @@ -2567,7 +2567,7 @@ redo: */ tic->t_curr_res = 0; tic->t_cnt = 0; /* ungrant will give back unit_res * t_cnt. */ - GRANT_UNLOCK(log, s); + spin_unlock(&log->l_grant_lock); return XFS_ERROR(EIO); } /* xlog_grant_log_space */ @@ -2581,7 +2581,6 @@ 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 @@ -2599,7 +2598,7 @@ xlog_regrant_write_log_space(xlog_t *log, panic("regrant Recovery problem"); #endif - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); xlog_trace_loggrant(log, tic, "xlog_regrant_write_log_space: enter"); if (XLOG_FORCED_SHUTDOWN(log)) @@ -2638,14 +2637,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)) { - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); 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); - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); } } @@ -2665,14 +2664,14 @@ redo: /* If we're shutting down, this tic is already off the queue */ if (XLOG_FORCED_SHUTDOWN(log)) { - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); goto error_return; } xlog_trace_loggrant(log, tic, "xlog_regrant_write_log_space: wake 2"); xlog_grant_push_ail(log->l_mp, need_bytes); - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); goto redo; } else if (tic->t_flags & XLOG_TIC_IN_Q) xlog_del_ticketq(&log->l_write_headq, tic); @@ -2689,7 +2688,7 @@ redo: xlog_trace_loggrant(log, tic, "xlog_regrant_write_log_space: exit"); xlog_verify_grant_head(log, 1); - GRANT_UNLOCK(log, s); + spin_unlock(&log->l_grant_lock); return 0; @@ -2704,7 +2703,7 @@ redo: */ tic->t_curr_res = 0; tic->t_cnt = 0; /* ungrant will give back unit_res * t_cnt. */ - GRANT_UNLOCK(log, s); + spin_unlock(&log->l_grant_lock); return XFS_ERROR(EIO); } /* xlog_regrant_write_log_space */ @@ -2720,14 +2719,12 @@ 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--; - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); xlog_grant_sub_space(log, ticket->t_curr_res); ticket->t_curr_res = ticket->t_unit_res; xlog_tic_reset_res(ticket); @@ -2737,7 +2734,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) { - GRANT_UNLOCK(log, s); + spin_unlock(&log->l_grant_lock); return; } @@ -2745,7 +2742,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); - GRANT_UNLOCK(log, s); + spin_unlock(&log->l_grant_lock); ticket->t_curr_res = ticket->t_unit_res; xlog_tic_reset_res(ticket); } /* xlog_regrant_reserve_log_space */ @@ -2769,12 +2766,10 @@ STATIC void xlog_ungrant_log_space(xlog_t *log, xlog_ticket_t *ticket) { - SPLDECL(s); - if (ticket->t_cnt > 0) ticket->t_cnt--; - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); xlog_trace_loggrant(log, ticket, "xlog_ungrant_log_space: enter"); xlog_grant_sub_space(log, ticket->t_curr_res); @@ -2791,7 +2786,7 @@ xlog_ungrant_log_space(xlog_t *log, xlog_trace_loggrant(log, ticket, "xlog_ungrant_log_space: exit"); xlog_verify_grant_head(log, 1); - GRANT_UNLOCK(log, s); + spin_unlock(&log->l_grant_lock); xfs_log_move_tail(log->l_mp, 1); } /* xlog_ungrant_log_space */ @@ -2799,15 +2794,13 @@ xlog_ungrant_log_space(xlog_t *log, /* * Atomically put back used ticket. */ -void +STATIC void xlog_state_put_ticket(xlog_t *log, xlog_ticket_t *tic) { - unsigned long s; - - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); xlog_ticket_put(log, tic); - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); } /* xlog_state_put_ticket */ /* @@ -2819,19 +2812,18 @@ xlog_state_put_ticket(xlog_t *log, * * */ -int +STATIC 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); - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); if (iclog->ic_state & XLOG_STATE_IOERROR) { - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); return XFS_ERROR(EIO); } @@ -2843,12 +2835,12 @@ xlog_state_release_iclog(xlog_t *log, iclog->ic_state == XLOG_STATE_WANT_SYNC) { sync++; iclog->ic_state = XLOG_STATE_SYNCING; - INT_SET(iclog->ic_header.h_tail_lsn, ARCH_CONVERT, log->l_tail_lsn); + iclog->ic_header.h_tail_lsn = cpu_to_be64(log->l_tail_lsn); xlog_verify_tail_lsn(log, iclog, log->l_tail_lsn); /* cycle incremented when incrementing curr_block */ } - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); /* * We let the log lock go, so it's possible that we hit a log I/O @@ -2881,7 +2873,7 @@ xlog_state_switch_iclogs(xlog_t *log, if (!eventual_size) eventual_size = iclog->ic_offset; iclog->ic_state = XLOG_STATE_WANT_SYNC; - INT_SET(iclog->ic_header.h_prev_block, ARCH_CONVERT, log->l_prev_block); + iclog->ic_header.h_prev_block = cpu_to_be32(log->l_prev_block); log->l_prev_block = log->l_curr_block; log->l_prev_cycle = log->l_curr_cycle; @@ -2939,13 +2931,12 @@ xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed) { xlog_in_core_t *iclog; xfs_lsn_t lsn; - SPLDECL(s); - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); iclog = log->l_iclog; if (iclog->ic_state & XLOG_STATE_IOERROR) { - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); return XFS_ERROR(EIO); } @@ -2978,15 +2969,15 @@ xlog_state_sync_all(xlog_t *log, uint flags, int *log_flushed) * the previous sync. */ iclog->ic_refcnt++; - lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT); + lsn = be64_to_cpu(iclog->ic_header.h_lsn); xlog_state_switch_iclogs(log, iclog, 0); - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); if (xlog_state_release_iclog(log, iclog)) return XFS_ERROR(EIO); *log_flushed = 1; - s = LOG_LOCK(log); - if (INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT) == lsn && + spin_lock(&log->l_icloglock); + if (be64_to_cpu(iclog->ic_header.h_lsn) == lsn && iclog->ic_state != XLOG_STATE_DIRTY) goto maybe_sleep; else @@ -3011,12 +3002,12 @@ maybe_sleep: if (flags & XFS_LOG_SYNC) { /* * We must check if we're shutting down here, before - * we wait, while we're holding the LOG_LOCK. + * we wait, while we're holding the l_icloglock. * Then we check again after waking up, in case our * sleep was disturbed by a bad news. */ if (iclog->ic_state & XLOG_STATE_IOERROR) { - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); return XFS_ERROR(EIO); } XFS_STATS_INC(xs_log_force_sleep); @@ -3033,7 +3024,7 @@ maybe_sleep: } else { no_sleep: - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); } return 0; } /* xlog_state_sync_all */ @@ -3051,7 +3042,7 @@ no_sleep: * If filesystem activity goes to zero, the iclog will get flushed only by * bdflush(). */ -int +STATIC int xlog_state_sync(xlog_t *log, xfs_lsn_t lsn, uint flags, @@ -3059,26 +3050,24 @@ xlog_state_sync(xlog_t *log, { xlog_in_core_t *iclog; int already_slept = 0; - SPLDECL(s); - try_again: - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); iclog = log->l_iclog; if (iclog->ic_state & XLOG_STATE_IOERROR) { - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); return XFS_ERROR(EIO); } do { - if (INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT) != lsn) { - iclog = iclog->ic_next; - continue; + if (be64_to_cpu(iclog->ic_header.h_lsn) != lsn) { + iclog = iclog->ic_next; + continue; } if (iclog->ic_state == XLOG_STATE_DIRTY) { - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); return 0; } @@ -3113,11 +3102,11 @@ try_again: } else { iclog->ic_refcnt++; xlog_state_switch_iclogs(log, iclog, 0); - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); if (xlog_state_release_iclog(log, iclog)) return XFS_ERROR(EIO); *log_flushed = 1; - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); } } @@ -3129,7 +3118,7 @@ try_again: * gotten a log write error. */ if (iclog->ic_state & XLOG_STATE_IOERROR) { - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); return XFS_ERROR(EIO); } XFS_STATS_INC(xs_log_force_sleep); @@ -3143,13 +3132,13 @@ try_again: return XFS_ERROR(EIO); *log_flushed = 1; } else { /* just return */ - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); } return 0; } while (iclog != log->l_iclog); - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); return 0; } /* xlog_state_sync */ @@ -3158,12 +3147,10 @@ try_again: * Called when we want to mark the current iclog as being ready to sync to * disk. */ -void +STATIC void xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog) { - SPLDECL(s); - - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); if (iclog->ic_state == XLOG_STATE_ACTIVE) { xlog_state_switch_iclogs(log, iclog, 0); @@ -3172,7 +3159,7 @@ xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog) (XLOG_STATE_WANT_SYNC|XLOG_STATE_IOERROR)); } - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); } /* xlog_state_want_sync */ @@ -3193,16 +3180,15 @@ xlog_state_ticket_alloc(xlog_t *log) xlog_ticket_t *t_list; xlog_ticket_t *next; xfs_caddr_t buf; - uint i = (NBPP / sizeof(xlog_ticket_t)) - 2; - SPLDECL(s); + uint i = (PAGE_SIZE / sizeof(xlog_ticket_t)) - 2; /* * 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(NBPP, KM_SLEEP); + buf = (xfs_caddr_t) kmem_zalloc(PAGE_SIZE, KM_SLEEP); - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); /* Attach 1st ticket to Q, so we can keep track of allocated memory */ t_list = (xlog_ticket_t *)buf; @@ -3231,7 +3217,7 @@ xlog_state_ticket_alloc(xlog_t *log) } t_list->t_next = NULL; log->l_tail = t_list; - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); } /* xlog_state_ticket_alloc */ @@ -3273,7 +3259,7 @@ xlog_ticket_put(xlog_t *log, /* * Grab ticket off freelist or allocation some more */ -xlog_ticket_t * +STATIC xlog_ticket_t * xlog_ticket_get(xlog_t *log, int unit_bytes, int cnt, @@ -3282,15 +3268,14 @@ 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 */ - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); if (log->l_freelist == NULL) { - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); goto alloc; } tic = log->l_freelist; @@ -3298,7 +3283,7 @@ xlog_ticket_get(xlog_t *log, if (log->l_freelist == NULL) log->l_tail = NULL; log->l_ticket_cnt--; - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); /* * Permanent reservations have up to 'cnt'-1 active log operations @@ -3473,10 +3458,9 @@ 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 */ - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); icptr = log->l_iclog; for (i=0; i < log->l_iclog_bufs; i++) { if (icptr == NULL) @@ -3485,21 +3469,21 @@ xlog_verify_iclog(xlog_t *log, } if (icptr != log->l_iclog) xlog_panic("xlog_verify_iclog: corrupt iclog ring"); - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); /* check log magic numbers */ - ptr = (xfs_caddr_t) &(iclog->ic_header); - if (INT_GET(*(uint *)ptr, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) + if (be32_to_cpu(iclog->ic_header.h_magicno) != XLOG_HEADER_MAGIC_NUM) xlog_panic("xlog_verify_iclog: invalid magic num"); - for (ptr += BBSIZE; ptr < ((xfs_caddr_t)&(iclog->ic_header))+count; + ptr = (xfs_caddr_t) &iclog->ic_header; + for (ptr += BBSIZE; ptr < ((xfs_caddr_t)&iclog->ic_header) + count; ptr += BBSIZE) { - if (INT_GET(*(uint *)ptr, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) + if (be32_to_cpu(*(__be32 *)ptr) == XLOG_HEADER_MAGIC_NUM) xlog_panic("xlog_verify_iclog: unexpected magic num"); } /* check fields */ - len = INT_GET(iclog->ic_header.h_num_logops, ARCH_CONVERT); + len = be32_to_cpu(iclog->ic_header.h_num_logops); ptr = iclog->ic_datap; base_ptr = ptr; ophead = (xlog_op_header_t *)ptr; @@ -3517,9 +3501,11 @@ 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 = GET_CLIENT_ID(xhdr[j].hic_xheader.xh_cycle_data[k], ARCH_CONVERT); + clientid = xlog_get_client_id( + xhdr[j].hic_xheader.xh_cycle_data[k]); } else { - clientid = GET_CLIENT_ID(iclog->ic_header.h_cycle_data[idx], ARCH_CONVERT); + clientid = xlog_get_client_id( + iclog->ic_header.h_cycle_data[idx]); } } if (clientid != XFS_TRANSACTION && clientid != XFS_LOG) @@ -3531,16 +3517,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 = INT_GET(ophead->oh_len, ARCH_CONVERT); + op_len = be32_to_cpu(ophead->oh_len); } 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 = INT_GET(xhdr[j].hic_xheader.xh_cycle_data[k], ARCH_CONVERT); + op_len = be32_to_cpu(xhdr[j].hic_xheader.xh_cycle_data[k]); } else { - op_len = INT_GET(iclog->ic_header.h_cycle_data[idx], ARCH_CONVERT); + op_len = be32_to_cpu(iclog->ic_header.h_cycle_data[idx]); } } ptr += sizeof(xlog_op_header_t) + op_len; @@ -3549,7 +3535,7 @@ xlog_verify_iclog(xlog_t *log, #endif /* - * Mark all iclogs IOERROR. LOG_LOCK is held by the caller. + * Mark all iclogs IOERROR. l_icloglock is held by the caller. */ STATIC int xlog_state_ioerror( @@ -3597,8 +3583,6 @@ xfs_log_force_umount( xlog_t *log; int retval; int dummy; - SPLDECL(s); - SPLDECL(s2); log = mp->m_log; @@ -3627,8 +3611,8 @@ xfs_log_force_umount( * before we mark the filesystem SHUTDOWN and wake * everybody up to tell the bad news. */ - s = GRANT_LOCK(log); - s2 = LOG_LOCK(log); + spin_lock(&log->l_grant_lock); + spin_lock(&log->l_icloglock); mp->m_flags |= XFS_MOUNT_FS_SHUTDOWN; XFS_BUF_DONE(mp->m_sb_bp); /* @@ -3644,7 +3628,7 @@ xfs_log_force_umount( */ if (logerror) retval = xlog_state_ioerror(log); - LOG_UNLOCK(log, s2); + spin_unlock(&log->l_icloglock); /* * We don't want anybody waiting for log reservations @@ -3667,7 +3651,7 @@ xfs_log_force_umount( tic = tic->t_next; } while (tic != log->l_write_headq); } - GRANT_UNLOCK(log, s); + spin_unlock(&log->l_grant_lock); if (! (log->l_iclog->ic_state & XLOG_STATE_IOERROR)) { ASSERT(!logerror); @@ -3676,9 +3660,9 @@ xfs_log_force_umount( * log down completely. */ xlog_state_sync_all(log, XFS_LOG_FORCE|XFS_LOG_SYNC, &dummy); - s2 = LOG_LOCK(log); + spin_lock(&log->l_icloglock); retval = xlog_state_ioerror(log); - LOG_UNLOCK(log, s2); + spin_unlock(&log->l_icloglock); } /* * Wake up everybody waiting on xfs_log_force. @@ -3691,13 +3675,13 @@ xfs_log_force_umount( { xlog_in_core_t *iclog; - s = LOG_LOCK(log); + spin_lock(&log->l_icloglock); iclog = log->l_iclog; do { ASSERT(iclog->ic_callback == 0); iclog = iclog->ic_next; } while (iclog != log->l_iclog); - LOG_UNLOCK(log, s); + spin_unlock(&log->l_icloglock); } #endif /* return non-zero if log IOERROR transition had already happened */ diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h index ebbe93f4f97b..4cdac048df5e 100644 --- a/fs/xfs/xfs_log.h +++ b/fs/xfs/xfs_log.h @@ -22,8 +22,9 @@ #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) (((uint *)&(lsn))[0]) +#define CYCLE_LSN_DISK(lsn) (((__be32 *)&(lsn))[0]) #ifdef __KERNEL__ /* diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index 752f964b3699..e008233ee249 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h @@ -55,32 +55,21 @@ 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 - */ -#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) \ - ) +static inline xfs_lsn_t xlog_assign_lsn(uint cycle, uint block) +{ + return ((xfs_lsn_t)cycle << 32) | block; +} -#define BLK_AVG(blk1, blk2) ((blk1+blk2) >> 1) +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 BLK_AVG(blk1, blk2) ((blk1+blk2) >> 1) #ifdef __KERNEL__ @@ -96,19 +85,10 @@ struct xfs_mount; * * this has endian issues, of course. */ - -#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) +static inline uint xlog_get_client_id(__be32 i) +{ + return be32_to_cpu(i) >> 24; +} #define xlog_panic(args...) cmn_err(CE_PANIC, ## args) #define xlog_exit(args...) cmn_err(CE_PANIC, ## args) @@ -285,11 +265,11 @@ typedef struct xlog_ticket { typedef struct xlog_op_header { - 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 */ + __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_op_header_t; @@ -307,25 +287,25 @@ typedef struct xlog_op_header { #endif typedef struct xlog_rec_header { - 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]; + __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]; /* new fields */ - int h_fmt; /* format of log record : 4 */ - uuid_t h_fs_uuid; /* uuid of FS : 16 */ - int h_size; /* iclog size : 4 */ + __be32 h_fmt; /* format of log record : 4 */ + uuid_t h_fs_uuid; /* uuid of FS : 16 */ + __be32 h_size; /* iclog size : 4 */ } xlog_rec_header_t; typedef struct xlog_rec_ext_header { - uint xh_cycle; /* write cycle of log : 4 */ - uint xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* : 256 */ + __be32 xh_cycle; /* write cycle of log : 4 */ + __be32 xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* : 256 */ } xlog_rec_ext_header_t; #ifdef __KERNEL__ @@ -415,7 +395,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 */ - lock_t l_icloglock; /* grab to change iclog state */ + spinlock_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 */ @@ -439,7 +419,7 @@ typedef struct log { char *l_iclog_bak[XLOG_MAX_ICLOGS]; /* The following block of fields are changed while holding grant_lock */ - lock_t l_grant_lock; + spinlock_t l_grant_lock; xlog_ticket_t *l_reserve_headq; xlog_ticket_t *l_write_headq; int l_grant_reserve_cycle; diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 851eca8a7150..b82d5d4d2462 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/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", INT_GET(head->h_fmt, ARCH_CONVERT)); + cmn_err(CE_DEBUG, ", fmt = %d\n", be32_to_cpu(head->h_fmt)); } #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(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + ASSERT(be32_to_cpu(head->h_magicno) == 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(INT_GET(head->h_fmt, ARCH_CONVERT) != XLOG_FMT)) { + if (unlikely(be32_to_cpu(head->h_fmt) != 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(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + ASSERT(be32_to_cpu(head->h_magicno) == 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. */ -int +STATIC 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 = GET_CYCLE(offset, ARCH_CONVERT); + mid_cycle = xlog_get_cycle(offset); 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 = GET_CYCLE(buf, ARCH_CONVERT); + cycle = xlog_get_cycle(buf); if (cycle == stop_on_cycle_no) { *new_blk = i+j; goto out; @@ -447,8 +447,7 @@ xlog_find_verify_log_record( head = (xlog_rec_header_t *)offset; - if (XLOG_HEADER_MAGIC_NUM == - INT_GET(head->h_magicno, ARCH_CONVERT)) + if (XLOG_HEADER_MAGIC_NUM == be32_to_cpu(head->h_magicno)) break; if (!smallmem) @@ -480,7 +479,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 = INT_GET(head->h_size, ARCH_CONVERT); + uint h_size = be32_to_cpu(head->h_size); xhdrs = h_size / XLOG_HEADER_CYCLE_SIZE; if (h_size % XLOG_HEADER_CYCLE_SIZE) @@ -489,8 +488,8 @@ xlog_find_verify_log_record( xhdrs = 1; } - if (*last_blk - i + extra_bblks - != BTOBB(INT_GET(head->h_len, ARCH_CONVERT)) + xhdrs) + if (*last_blk - i + extra_bblks != + BTOBB(be32_to_cpu(head->h_len)) + xhdrs) *last_blk = i; out: @@ -550,13 +549,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 = GET_CYCLE(offset, ARCH_CONVERT); + first_half_cycle = xlog_get_cycle(offset); 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 = GET_CYCLE(offset, ARCH_CONVERT); + last_half_cycle = xlog_get_cycle(offset); ASSERT(last_half_cycle != 0); /* @@ -808,7 +807,7 @@ xlog_find_tail( if ((error = xlog_bread(log, 0, 1, bp))) goto bread_err; offset = xlog_align(log, 0, 1, bp); - if (GET_CYCLE(offset, ARCH_CONVERT) == 0) { + if (xlog_get_cycle(offset) == 0) { *tail_blk = 0; /* leave all other log inited values alone */ goto exit; @@ -823,8 +822,7 @@ 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 == - INT_GET(*(uint *)offset, ARCH_CONVERT)) { + if (XLOG_HEADER_MAGIC_NUM == be32_to_cpu(*(__be32 *)offset)) { found = 1; break; } @@ -841,7 +839,7 @@ xlog_find_tail( goto bread_err; offset = xlog_align(log, i, 1, bp); if (XLOG_HEADER_MAGIC_NUM == - INT_GET(*(uint*)offset, ARCH_CONVERT)) { + be32_to_cpu(*(__be32 *)offset)) { found = 2; break; } @@ -855,7 +853,7 @@ xlog_find_tail( /* find blk_no of tail of log */ rhead = (xlog_rec_header_t *)offset; - *tail_blk = BLOCK_LSN(INT_GET(rhead->h_tail_lsn, ARCH_CONVERT)); + *tail_blk = BLOCK_LSN(be64_to_cpu(rhead->h_tail_lsn)); /* * Reset log values according to the state of the log when we @@ -869,11 +867,11 @@ xlog_find_tail( */ log->l_prev_block = i; log->l_curr_block = (int)*head_blk; - log->l_curr_cycle = INT_GET(rhead->h_cycle, ARCH_CONVERT); + log->l_curr_cycle = be32_to_cpu(rhead->h_cycle); if (found == 2) log->l_curr_cycle++; - 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_tail_lsn = be64_to_cpu(rhead->h_tail_lsn); + log->l_last_sync_lsn = be64_to_cpu(rhead->h_lsn); 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; @@ -891,8 +889,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 = INT_GET(rhead->h_size, ARCH_CONVERT); - int h_version = INT_GET(rhead->h_version, ARCH_CONVERT); + int h_size = be32_to_cpu(rhead->h_size); + int h_version = be32_to_cpu(rhead->h_version); if ((h_version & XLOG_VERSION_2) && (h_size > XLOG_HEADER_CYCLE_SIZE)) { @@ -906,10 +904,10 @@ xlog_find_tail( hblks = 1; } after_umount_blk = (i + hblks + (int) - BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT))) % log->l_logBBsize; + BTOBB(be32_to_cpu(rhead->h_len))) % log->l_logBBsize; tail_lsn = log->l_tail_lsn; if (*head_blk == after_umount_blk && - INT_GET(rhead->h_num_logops, ARCH_CONVERT) == 1) { + be32_to_cpu(rhead->h_num_logops) == 1) { umount_data_blk = (i + hblks) % log->l_logBBsize; if ((error = xlog_bread(log, umount_data_blk, 1, bp))) { goto bread_err; @@ -922,10 +920,12 @@ xlog_find_tail( * log records will point recovery to after the * current unmount record. */ - 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); + 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); *tail_blk = after_umount_blk; /* @@ -986,7 +986,7 @@ exit: * -1 => use *blk_no as the first block of the log * >0 => error has occurred */ -int +STATIC 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 = GET_CYCLE(offset, ARCH_CONVERT); + first_cycle = xlog_get_cycle(offset); 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 = GET_CYCLE(offset, ARCH_CONVERT); + last_cycle = xlog_get_cycle(offset); 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); - 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, + recp->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM); + recp->h_cycle = cpu_to_be32(cycle); + recp->h_version = cpu_to_be32( XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? 2 : 1); - 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); + 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); 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 == - INT_GET(*((__uint16_t *)(xfs_buf_offset(bp, 0))), ARCH_CONVERT) && + be16_to_cpu(*((__be16 *)xfs_buf_offset(bp, 0))) && (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,8 +2581,7 @@ xlog_recover_do_dquot_trans( /* * This type of quotas was turned off, so ignore this record. */ - type = INT_GET(recddq->d_flags, ARCH_CONVERT) & - (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP); + type = recddq->d_flags & (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP); ASSERT(type); if (log->l_quotaoffs_flag & type) return (0); @@ -2660,7 +2659,6 @@ 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; @@ -2678,11 +2676,11 @@ xlog_recover_do_efi_trans( efip->efi_next_extent = efi_formatp->efi_nextents; efip->efi_flags |= XFS_EFI_COMMITTED; - AIL_LOCK(mp,s); + spin_lock(&mp->m_ail_lock); /* * xfs_trans_update_ail() drops the AIL lock. */ - xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn, s); + xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn); return 0; } @@ -2707,7 +2705,6 @@ xlog_recover_do_efd_trans( xfs_log_item_t *lip; int gen; __uint64_t efi_id; - SPLDECL(s); if (pass == XLOG_RECOVER_PASS1) { return; @@ -2725,7 +2722,7 @@ xlog_recover_do_efd_trans( * in the AIL. */ mp = log->l_mp; - AIL_LOCK(mp,s); + spin_lock(&mp->m_ail_lock); lip = xfs_trans_first_ail(mp, &gen); while (lip != NULL) { if (lip->li_type == XFS_LI_EFI) { @@ -2735,22 +2732,14 @@ xlog_recover_do_efd_trans( * xfs_trans_delete_ail() drops the * AIL lock. */ - xfs_trans_delete_ail(mp, lip, s); - break; + xfs_trans_delete_ail(mp, lip); + xfs_efi_item_free(efip); + return; } } lip = xfs_trans_next_ail(mp, lip, &gen, NULL); } - - /* - * 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); - } + spin_unlock(&mp->m_ail_lock); } /* @@ -2897,8 +2886,8 @@ xlog_recover_process_data( unsigned long hash; uint flags; - lp = dp + INT_GET(rhead->h_len, ARCH_CONVERT); - num_logops = INT_GET(rhead->h_num_logops, ARCH_CONVERT); + lp = dp + be32_to_cpu(rhead->h_len); + num_logops = be32_to_cpu(rhead->h_num_logops); /* check the log format matches our own - else we can't recover */ if (xlog_header_check_recover(log->l_mp, rhead)) @@ -2915,15 +2904,20 @@ xlog_recover_process_data( ASSERT(0); return (XFS_ERROR(EIO)); } - tid = INT_GET(ohead->oh_tid, ARCH_CONVERT); + tid = be32_to_cpu(ohead->oh_tid); 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, - INT_GET(rhead->h_lsn, ARCH_CONVERT)); + be64_to_cpu(rhead->h_lsn)); } else { - ASSERT(dp+INT_GET(ohead->oh_len, ARCH_CONVERT) <= lp); + 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)); + } flags = ohead->oh_flags & ~XLOG_END_TRANS; if (flags & XLOG_WAS_CONT_TRANS) flags &= ~XLOG_CONTINUE_TRANS; @@ -2937,8 +2931,7 @@ xlog_recover_process_data( break; case XLOG_WAS_CONT_TRANS: error = xlog_recover_add_to_cont_trans(trans, - dp, INT_GET(ohead->oh_len, - ARCH_CONVERT)); + dp, be32_to_cpu(ohead->oh_len)); break; case XLOG_START_TRANS: xlog_warn( @@ -2949,8 +2942,7 @@ xlog_recover_process_data( case 0: case XLOG_CONTINUE_TRANS: error = xlog_recover_add_to_trans(trans, - dp, INT_GET(ohead->oh_len, - ARCH_CONVERT)); + dp, be32_to_cpu(ohead->oh_len)); break; default: xlog_warn( @@ -2962,7 +2954,7 @@ xlog_recover_process_data( if (error) return error; } - dp += INT_GET(ohead->oh_len, ARCH_CONVERT); + dp += be32_to_cpu(ohead->oh_len); num_logops--; } return 0; @@ -3075,10 +3067,9 @@ xlog_recover_process_efis( xfs_efi_log_item_t *efip; int gen; xfs_mount_t *mp; - SPLDECL(s); mp = log->l_mp; - AIL_LOCK(mp,s); + spin_lock(&mp->m_ail_lock); lip = xfs_trans_first_ail(mp, &gen); while (lip != NULL) { @@ -3099,12 +3090,12 @@ xlog_recover_process_efis( continue; } - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); xlog_recover_process_efi(mp, efip); - AIL_LOCK(mp,s); + spin_lock(&mp->m_ail_lock); lip = xfs_trans_next_ail(mp, lip, &gen, NULL); } - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); } /* @@ -3315,16 +3306,16 @@ xlog_pack_data_checksum( int size) { int i; - uint *up; + __be32 *up; uint chksum = 0; - up = (uint *)iclog->ic_datap; + up = (__be32 *)iclog->ic_datap; /* divide length by 4 to get # words */ for (i = 0; i < (size >> 2); i++) { - chksum ^= INT_GET(*up, ARCH_CONVERT); + chksum ^= be32_to_cpu(*up); up++; } - INT_SET(iclog->ic_header.h_chksum, ARCH_CONVERT, chksum); + iclog->ic_header.h_chksum = cpu_to_be32(chksum); } #else #define xlog_pack_data_checksum(log, iclog, size) @@ -3341,7 +3332,7 @@ xlog_pack_data( { int i, j, k; int size = iclog->ic_offset + roundoff; - uint cycle_lsn; + __be32 cycle_lsn; xfs_caddr_t dp; xlog_in_core_2_t *xhdr; @@ -3352,8 +3343,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] = *(uint *)dp; - *(uint *)dp = cycle_lsn; + iclog->ic_header.h_cycle_data[i] = *(__be32 *)dp; + *(__be32 *)dp = cycle_lsn; dp += BBSIZE; } @@ -3362,8 +3353,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] = *(uint *)dp; - *(uint *)dp = cycle_lsn; + xhdr[j].hic_xheader.xh_cycle_data[k] = *(__be32 *)dp; + *(__be32 *)dp = cycle_lsn; dp += BBSIZE; } @@ -3380,21 +3371,21 @@ xlog_unpack_data_checksum( xfs_caddr_t dp, xlog_t *log) { - uint *up = (uint *)dp; + __be32 *up = (__be32 *)dp; uint chksum = 0; int i; /* divide length by 4 to get # words */ - for (i=0; i < INT_GET(rhead->h_len, ARCH_CONVERT) >> 2; i++) { - chksum ^= INT_GET(*up, ARCH_CONVERT); + for (i=0; i < be32_to_cpu(rhead->h_len) >> 2; i++) { + chksum ^= be32_to_cpu(*up); up++; } - if (chksum != INT_GET(rhead->h_chksum, ARCH_CONVERT)) { + if (chksum != be32_to_cpu(rhead->h_chksum)) { 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", - INT_GET(rhead->h_chksum, ARCH_CONVERT), chksum); + be32_to_cpu(rhead->h_chksum), 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)) { @@ -3418,18 +3409,18 @@ xlog_unpack_data( int i, j, k; xlog_in_core_2_t *xhdr; - for (i = 0; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)) && + for (i = 0; i < BTOBB(be32_to_cpu(rhead->h_len)) && i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) { - *(uint *)dp = *(uint *)&rhead->h_cycle_data[i]; + *(__be32 *)dp = *(__be32 *)&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(INT_GET(rhead->h_len, ARCH_CONVERT)); i++) { + for ( ; i < BTOBB(be32_to_cpu(rhead->h_len)); i++) { j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - *(uint *)dp = xhdr[j].hic_xheader.xh_cycle_data[k]; + *(__be32 *)dp = xhdr[j].hic_xheader.xh_cycle_data[k]; dp += BBSIZE; } } @@ -3445,24 +3436,21 @@ xlog_valid_rec_header( { int hlen; - if (unlikely( - (INT_GET(rhead->h_magicno, ARCH_CONVERT) != - XLOG_HEADER_MAGIC_NUM))) { + if (unlikely(be32_to_cpu(rhead->h_magicno) != 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 || - (INT_GET(rhead->h_version, ARCH_CONVERT) & - (~XLOG_VERSION_OKBITS)) != 0))) { + (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS))))) { xlog_warn("XFS: %s: unrecognised log version (%d).", - __FUNCTION__, INT_GET(rhead->h_version, ARCH_CONVERT)); + __FUNCTION__, be32_to_cpu(rhead->h_version)); return XFS_ERROR(EIO); } /* LR body must have data or it wouldn't have been written */ - hlen = INT_GET(rhead->h_len, ARCH_CONVERT); + hlen = be32_to_cpu(rhead->h_len); if (unlikely( hlen <= 0 || hlen > INT_MAX )) { XFS_ERROR_REPORT("xlog_valid_rec_header(2)", XFS_ERRLEVEL_LOW, log->l_mp); @@ -3522,9 +3510,8 @@ xlog_do_recovery_pass( error = xlog_valid_rec_header(log, rhead, tail_blk); if (error) goto bread_err1; - h_size = INT_GET(rhead->h_size, ARCH_CONVERT); - if ((INT_GET(rhead->h_version, ARCH_CONVERT) - & XLOG_VERSION_2) && + h_size = be32_to_cpu(rhead->h_size); + if ((be32_to_cpu(rhead->h_version) & XLOG_VERSION_2) && (h_size > XLOG_HEADER_CYCLE_SIZE)) { hblks = h_size / XLOG_HEADER_CYCLE_SIZE; if (h_size % XLOG_HEADER_CYCLE_SIZE) @@ -3561,7 +3548,7 @@ xlog_do_recovery_pass( goto bread_err2; /* blocks in data section */ - bblks = (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); + bblks = (int)BTOBB(be32_to_cpu(rhead->h_len)); error = xlog_bread(log, blk_no + hblks, bblks, dbp); if (error) goto bread_err2; @@ -3636,7 +3623,7 @@ xlog_do_recovery_pass( if (error) goto bread_err2; - bblks = (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); + bblks = (int)BTOBB(be32_to_cpu(rhead->h_len)); blk_no += hblks; /* Read in data for log record */ @@ -3707,7 +3694,7 @@ xlog_do_recovery_pass( error = xlog_valid_rec_header(log, rhead, blk_no); if (error) goto bread_err2; - bblks = (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); + bblks = (int)BTOBB(be32_to_cpu(rhead->h_len)); 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/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index ebdb76da527c..6409b3762995 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -136,15 +136,9 @@ xfs_mount_init(void) mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB; } - AIL_LOCKINIT(&mp->m_ail_lock, "xfs_ail"); - spinlock_init(&mp->m_sb_lock, "xfs_sb"); + spin_lock_init(&mp->m_sb_lock); 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; @@ -171,7 +165,7 @@ xfs_mount_free( sizeof(xfs_perag_t) * mp->m_sb.sb_agcount); } - AIL_LOCK_DESTROY(&mp->m_ail_lock); + spinlock_destroy(&mp->m_ail_lock); spinlock_destroy(&mp->m_sb_lock); mutex_destroy(&mp->m_ilock); mutex_destroy(&mp->m_growlock); @@ -616,7 +610,7 @@ xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp) int i; mp->m_agfrotor = mp->m_agirotor = 0; - spinlock_init(&mp->m_agirotor_lock, "m_agirotor_lock"); + spin_lock_init(&mp->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; @@ -696,7 +690,6 @@ 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++) { /* @@ -721,11 +714,11 @@ xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount) /* * Overwrite incore superblock counters with just-read data */ - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); sbp->sb_ifree = ifree; sbp->sb_icount = ialloc; sbp->sb_fdblocks = bfree + bfreelst + btree; - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); /* Fixup the per-cpu counters as well. */ xfs_icsb_reinit_counters(mp); @@ -734,49 +727,13 @@ xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount) } /* - * 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 + * Update alignment values based on mount options and sb values */ -int -xfs_mountfs( - xfs_mount_t *mp, - int mfsi_flags) +STATIC int +xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_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 @@ -787,8 +744,7 @@ xfs_mountfs( if (mp->m_flags & XFS_MOUNT_RETERR) { cmn_err(CE_WARN, "XFS: alignment check 1 failed"); - error = XFS_ERROR(EINVAL); - goto error1; + return XFS_ERROR(EINVAL); } mp->m_dalign = mp->m_swidth = 0; } else { @@ -798,8 +754,7 @@ xfs_mountfs( 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) { - error = XFS_ERROR(EINVAL); - goto error1; + return XFS_ERROR(EINVAL); } xfs_fs_cmn_err(CE_WARN, mp, "stripe alignment turned off: sunit(%d)/swidth(%d) incompatible with agsize(%d)", @@ -816,8 +771,7 @@ xfs_mountfs( "stripe alignment turned off: sunit(%d) less than bsize(%d)", mp->m_dalign, mp->m_blockmask +1); - error = XFS_ERROR(EINVAL); - goto error1; + return XFS_ERROR(EINVAL); } mp->m_swidth = 0; } @@ -830,11 +784,11 @@ xfs_mountfs( 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 && @@ -843,49 +797,45 @@ xfs_mountfs( mp->m_swidth = sbp->sb_width; } - 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); + return 0; +} - if (sbp->sb_imax_pct) { - __uint64_t icount; +/* + * 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; - /* Make sure the maximum inode count is a multiple of the - * units we allocate inodes in. + if (sbp->sb_imax_pct) { + /* + * 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; - - 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). + */ +STATIC void +xfs_set_rw_sizes(xfs_mount_t *mp) +{ + xfs_sb_t *sbp = &(mp->m_sb); + int readio_log, writeio_log; - /* - * 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; @@ -911,17 +861,14 @@ xfs_mountfs( mp->m_writeio_log = writeio_log; } mp->m_writeio_blocks = 1 << (mp->m_writeio_log - sbp->sb_blocklog); +} - /* - * 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. - */ +/* + * Set whether we're using inode alignment. + */ +STATIC void +xfs_set_inoalignment(xfs_mount_t *mp) +{ if (XFS_SB_VERSION_HASALIGN(&mp->m_sb) && mp->m_sb.sb_inoalignmt >= XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) @@ -937,14 +884,22 @@ xfs_mountfs( mp->m_sinoalign = mp->m_dalign; else mp->m_sinoalign = 0; - /* - * Check that the data (and log if separate) are an ok size. - */ +} + +/* + * 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; + 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"); - error = XFS_ERROR(E2BIG); - goto error1; + return XFS_ERROR(E2BIG); } error = xfs_read_buf(mp, mp->m_ddev_targp, d - XFS_FSS_TO_BB(mp, 1), @@ -953,10 +908,9 @@ xfs_mountfs( xfs_buf_relse(bp); } else { cmn_err(CE_WARN, "XFS: size check 2 failed"); - if (error == ENOSPC) { + if (error == ENOSPC) error = XFS_ERROR(E2BIG); - } - goto error1; + return error; } if (((mfsi_flags & XFS_MFSI_CLIENT) == 0) && @@ -964,8 +918,7 @@ xfs_mountfs( 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"); - error = XFS_ERROR(E2BIG); - goto error1; + return XFS_ERROR(E2BIG); } error = xfs_read_buf(mp, mp->m_logdev_targp, d - XFS_FSB_TO_BB(mp, 1), @@ -974,17 +927,111 @@ xfs_mountfs( 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 */ - if ((error = xfs_rtmount_init(mp))) { + error = xfs_rtmount_init(mp); + if (error) { cmn_err(CE_WARN, "XFS: RT mount failed"); goto error1; } @@ -1102,7 +1149,8 @@ xfs_mountfs( /* * Initialize realtime inode pointers in the mount structure */ - if ((error = xfs_rtmount_inodes(mp))) { + error = xfs_rtmount_inodes(mp); + if (error) { /* * Free up the root inode. */ @@ -1120,7 +1168,8 @@ xfs_mountfs( /* * Initialise the XFS quota management subsystem for this mount */ - if ((error = XFS_QM_INIT(mp, "amount, "aflags))) + error = XFS_QM_INIT(mp, "amount, "aflags); + if (error) goto error4; /* @@ -1137,7 +1186,8 @@ xfs_mountfs( /* * Complete the quota initialisation, post-log-replay component. */ - if ((error = XFS_QM_MOUNT(mp, quotamount, quotaflags, mfsi_flags))) + error = XFS_QM_MOUNT(mp, quotamount, quotaflags, mfsi_flags); + if (error) goto error4; /* @@ -1255,7 +1305,6 @@ 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; } @@ -1441,7 +1490,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 SB_LOCK must be held when this routine is called. + * The m_sb_lock must be held when this routine is called. */ int xfs_mod_incore_sb_unlocked( @@ -1606,7 +1655,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 SB_LOCK. Just use the xfs_mod_incore_sb_unlocked() + * is protected by the m_sb_lock. Just use the xfs_mod_incore_sb_unlocked() * routine to do the work. */ int @@ -1616,7 +1665,6 @@ xfs_mod_incore_sb( int64_t delta, int rsvd) { - unsigned long s; int status; /* check for per-cpu counters */ @@ -1633,9 +1681,9 @@ xfs_mod_incore_sb( /* FALLTHROUGH */ #endif default: - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd); - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); break; } @@ -1656,7 +1704,6 @@ 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; @@ -1664,10 +1711,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 SB_LOCK so that all of the changes will + * the scope of the m_sb_lock so that all of the changes will * be atomic. */ - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); msbp = &msb[0]; for (msbp = &msbp[0]; msbp < (msb + nmsb); msbp++) { /* @@ -1681,11 +1728,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)) { - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); status = xfs_icsb_modify_counters(mp, msbp->msb_field, msbp->msb_delta, rsvd); - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); break; } /* FALLTHROUGH */ @@ -1719,12 +1766,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)) { - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); status = xfs_icsb_modify_counters(mp, msbp->msb_field, -(msbp->msb_delta), rsvd); - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); break; } /* FALLTHROUGH */ @@ -1740,7 +1787,7 @@ xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd) msbp--; } } - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); return status; } @@ -1888,12 +1935,12 @@ xfs_mount_log_sbunit( * * Locking rules: * - * 1. XFS_SB_LOCK() before picking up per-cpu locks + * 1. m_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 XFS_SB_LOCK + per cpu locks + * 3. accurate counter sync requires m_sb_lock + per cpu locks * 4. modifying per-cpu counters requires holding per-cpu lock - * 5. modifying global counters requires holding XFS_SB_LOCK - * 6. enabling or disabling a counter requires holding the XFS_SB_LOCK + * 5. modifying global counters requires holding m_sb_lock + * 6. enabling or disabling a counter requires holding the m_sb_lock * and _none_ of the per-cpu locks. * * Disabled counters are only ever re-enabled by a balance operation @@ -1920,7 +1967,6 @@ 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 *) @@ -1946,7 +1992,7 @@ xfs_icsb_cpu_notify( * count into the total on the global superblock and * re-enable the counters. */ xfs_icsb_lock(mp); - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); xfs_icsb_disable_counter(mp, XFS_SBS_ICOUNT); xfs_icsb_disable_counter(mp, XFS_SBS_IFREE); xfs_icsb_disable_counter(mp, XFS_SBS_FDBLOCKS); @@ -1963,7 +2009,7 @@ xfs_icsb_cpu_notify( XFS_ICSB_SB_LOCKED, 0); xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, XFS_ICSB_SB_LOCKED, 0); - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); xfs_icsb_unlock(mp); break; } @@ -2194,11 +2240,10 @@ 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) - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); xfs_icsb_count(mp, &cnt, flags); @@ -2211,7 +2256,7 @@ xfs_icsb_sync_counters_flags( mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks; if ((flags & XFS_ICSB_SB_LOCKED) == 0) - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); } /* @@ -2252,11 +2297,10 @@ 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)) - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); /* disable counter and sync counter */ xfs_icsb_disable_counter(mp, field); @@ -2290,10 +2334,10 @@ xfs_icsb_balance_counter( xfs_icsb_enable_counter(mp, field, count, resid); out: if (!(flags & XFS_ICSB_SB_LOCKED)) - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); } -int +STATIC int xfs_icsb_modify_counters( xfs_mount_t *mp, xfs_sb_field_t field, @@ -2302,7 +2346,7 @@ xfs_icsb_modify_counters( { xfs_icsb_cnts_t *icsbp; long long lcounter; /* long counter for 64 bit fields */ - int cpu, ret = 0, s; + int cpu, ret = 0; might_sleep(); again: @@ -2380,15 +2424,15 @@ slow_path: * 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 SB_LOCK. Doing so + * here even though we need to get the m_sb_lock. Doing so * will cause us to re-enter this function and deadlock. - * Hence we get the SB_LOCK ourselves and then call + * Hence we get the m_sb_lock ourselves and then call * xfs_mod_incore_sb_unlocked() as the unlocked path operates * directly on the global counters. */ - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); ret = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd); - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); /* * Now that we've modified the global superblock, we diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index c618f7cb5f0e..f7c620ec6e69 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -56,20 +56,12 @@ 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. */ @@ -196,105 +188,6 @@ 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 /* @@ -326,14 +219,20 @@ 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 */ - 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 */ + spinlock_t m_ail_lock; /* fs AIL mutex */ + xfs_ail_t m_ail; /* fs active log item list */ xfs_sb_t m_sb; /* copy of fs superblock */ - lock_t m_sb_lock; /* sb counter mutex */ + spinlock_t m_sb_lock; /* sb counter lock */ struct xfs_buf *m_sb_bp; /* buffer for superblock */ char *m_fsname; /* filesystem name */ int m_fsname_len; /* strlen of fs name */ @@ -342,7 +241,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 */ - lock_t m_agirotor_lock;/* .. and lock protecting it */ + spinlock_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 */ @@ -423,7 +322,6 @@ 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 */ @@ -610,8 +508,6 @@ 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); @@ -646,7 +542,6 @@ 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/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c index e0b358c1c533..a0b2c0a2589a 100644 --- a/fs/xfs/xfs_mru_cache.c +++ b/fs/xfs/xfs_mru_cache.c @@ -225,10 +225,14 @@ _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) + xfs_mru_cache_t *mru) __releases(mru->lock) __acquires(mru->lock) + { xfs_mru_cache_elem_t *elem, *next; struct list_head tmp; @@ -245,7 +249,7 @@ _xfs_mru_cache_clear_reap_list( */ list_move(&elem->list_node, &tmp); } - mutex_spinunlock(&mru->lock, 0); + spin_unlock(&mru->lock); list_for_each_entry_safe(elem, next, &tmp, list_node) { @@ -259,7 +263,7 @@ _xfs_mru_cache_clear_reap_list( kmem_zone_free(xfs_mru_elem_zone, elem); } - mutex_spinlock(&mru->lock); + spin_lock(&mru->lock); } /* @@ -280,7 +284,7 @@ _xfs_mru_cache_reap( if (!mru || !mru->lists) return; - mutex_spinlock(&mru->lock); + spin_lock(&mru->lock); next = _xfs_mru_cache_migrate(mru, jiffies); _xfs_mru_cache_clear_reap_list(mru); @@ -294,7 +298,7 @@ _xfs_mru_cache_reap( queue_delayed_work(xfs_mru_reap_wq, &mru->work, next); } - mutex_spinunlock(&mru->lock, 0); + spin_unlock(&mru->lock); } int @@ -368,7 +372,7 @@ xfs_mru_cache_create( */ INIT_RADIX_TREE(&mru->store, GFP_ATOMIC); INIT_LIST_HEAD(&mru->reap_list); - spinlock_init(&mru->lock, "xfs_mru_cache"); + spin_lock_init(&mru->lock); INIT_DELAYED_WORK(&mru->work, _xfs_mru_cache_reap); mru->grp_time = grp_time; @@ -398,17 +402,17 @@ xfs_mru_cache_flush( if (!mru || !mru->lists) return; - mutex_spinlock(&mru->lock); + spin_lock(&mru->lock); if (mru->queued) { - mutex_spinunlock(&mru->lock, 0); + spin_unlock(&mru->lock); cancel_rearming_delayed_workqueue(xfs_mru_reap_wq, &mru->work); - mutex_spinlock(&mru->lock); + spin_lock(&mru->lock); } _xfs_mru_cache_migrate(mru, jiffies + mru->grp_count * mru->grp_time); _xfs_mru_cache_clear_reap_list(mru); - mutex_spinunlock(&mru->lock, 0); + spin_unlock(&mru->lock); } void @@ -454,13 +458,13 @@ xfs_mru_cache_insert( elem->key = key; elem->value = value; - mutex_spinlock(&mru->lock); + spin_lock(&mru->lock); radix_tree_insert(&mru->store, key, elem); radix_tree_preload_end(); _xfs_mru_cache_list_insert(mru, elem); - mutex_spinunlock(&mru->lock, 0); + spin_unlock(&mru->lock); return 0; } @@ -483,14 +487,14 @@ xfs_mru_cache_remove( if (!mru || !mru->lists) return NULL; - mutex_spinlock(&mru->lock); + spin_lock(&mru->lock); elem = radix_tree_delete(&mru->store, key); if (elem) { value = elem->value; list_del(&elem->list_node); } - mutex_spinunlock(&mru->lock, 0); + spin_unlock(&mru->lock); if (elem) kmem_zone_free(xfs_mru_elem_zone, elem); @@ -528,6 +532,10 @@ 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( @@ -540,14 +548,14 @@ xfs_mru_cache_lookup( if (!mru || !mru->lists) return NULL; - mutex_spinlock(&mru->lock); + spin_lock(&mru->lock); elem = radix_tree_lookup(&mru->store, key); if (elem) { list_del(&elem->list_node); _xfs_mru_cache_list_insert(mru, elem); - } - else - mutex_spinunlock(&mru->lock, 0); + __release(mru_lock); /* help sparse not be stupid */ + } else + spin_unlock(&mru->lock); return elem ? elem->value : NULL; } @@ -571,10 +579,12 @@ xfs_mru_cache_peek( if (!mru || !mru->lists) return NULL; - mutex_spinlock(&mru->lock); + spin_lock(&mru->lock); elem = radix_tree_lookup(&mru->store, key); if (!elem) - mutex_spinunlock(&mru->lock, 0); + spin_unlock(&mru->lock); + else + __release(mru_lock); /* help sparse not be stupid */ return elem ? elem->value : NULL; } @@ -586,7 +596,7 @@ xfs_mru_cache_peek( */ void xfs_mru_cache_done( - xfs_mru_cache_t *mru) + xfs_mru_cache_t *mru) __releases(mru->lock) { - mutex_spinunlock(&mru->lock, 0); + spin_unlock(&mru->lock); } diff --git a/fs/xfs/xfs_qmops.c b/fs/xfs/xfs_qmops.c index 2ec1d8a27352..a294e58db8dd 100644 --- a/fs/xfs/xfs_qmops.c +++ b/fs/xfs/xfs_qmops.c @@ -49,18 +49,17 @@ 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 SB_LOCK. + * without m_sb_lock. */ if (mp->m_sb.sb_qflags == 0) return 0; - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); mp->m_sb.sb_qflags = 0; - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); /* * if the fs is readonly, let the incore superblock run diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c index 44ea0ba36476..7eb157a59f9e 100644 --- a/fs/xfs/xfs_rename.c +++ b/fs/xfs/xfs_rename.c @@ -39,6 +39,7 @@ #include "xfs_refcache.h" #include "xfs_utils.h" #include "xfs_trans_space.h" +#include "xfs_vnodeops.h" /* @@ -118,7 +119,7 @@ xfs_lock_for_rename( inum1 = ip1->i_ino; ASSERT(ip1); - ITRACE(ip1); + xfs_itrace_ref(ip1); /* * Unlock dp1 and lock dp2 if they are different. @@ -141,7 +142,7 @@ xfs_lock_for_rename( IRELE (ip1); return error; } else { - ITRACE(ip2); + xfs_itrace_ref(ip2); } /* @@ -247,8 +248,8 @@ xfs_rename( int src_namelen = VNAMELEN(src_vname); int target_namelen = VNAMELEN(target_vname); - 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); + xfs_itrace_entry(src_dp); + xfs_itrace_entry(xfs_vtoi(target_dir_vp)); /* * Find the XFS behavior descriptor for the target directory diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 47082c01872d..ca83ddf72af4 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -73,18 +73,6 @@ STATIC int xfs_rtmodify_summary(xfs_mount_t *, xfs_trans_t *, int, */ /* - * 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. */ STATIC int /* error */ @@ -444,6 +432,7 @@ 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). @@ -612,6 +601,8 @@ 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 @@ -669,6 +660,9 @@ 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 @@ -1954,6 +1948,7 @@ 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/fs/xfs/xfs_rtalloc.h b/fs/xfs/xfs_rtalloc.h index 799c1f871263..8d8dcd215716 100644 --- a/fs/xfs/xfs_rtalloc.h +++ b/fs/xfs/xfs_rtalloc.h @@ -21,8 +21,6 @@ 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/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h index 49875e1d129f..f87db5344ce6 100644 --- a/fs/xfs/xfs_rw.h +++ b/fs/xfs/xfs_rw.h @@ -32,18 +32,10 @@ struct xfs_mount; static inline xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb) { - return (((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) ? \ + return (XFS_IS_REALTIME_INODE(ip) ? \ (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 @@ -61,7 +53,7 @@ xfs_get_extsz_hint( { xfs_extlen_t extsz; - if (unlikely(ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { + if (unlikely(XFS_IS_REALTIME_INODE(ip))) { extsz = (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) ? ip->i_d.di_extsize : ip->i_mount->m_sb.sb_rextsize; diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 8878322ee793..71e4c8dcc69b 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -1322,7 +1322,6 @@ 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++) { @@ -1363,7 +1362,7 @@ xfs_trans_chunk_committed( * the test below. */ mp = lip->li_mountp; - AIL_LOCK(mp,s); + spin_lock(&mp->m_ail_lock); if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) { /* * This will set the item's lsn to item_lsn @@ -1372,9 +1371,9 @@ xfs_trans_chunk_committed( * * xfs_trans_update_ail() drops the AIL lock. */ - xfs_trans_update_ail(mp, lip, item_lsn, s); + xfs_trans_update_ail(mp, lip, item_lsn); } else { - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); } /* diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index 0e26e729023e..7f40628d85c7 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -992,8 +992,9 @@ 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); -void xfs_trans_ail_init(struct xfs_mount *); -xfs_lsn_t xfs_trans_push_ail(struct xfs_mount *, xfs_lsn_t); +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); xfs_lsn_t xfs_trans_tail_ail(struct xfs_mount *); void xfs_trans_unlocked_item(struct xfs_mount *, xfs_log_item_t *); @@ -1001,6 +1002,8 @@ 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/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 5b2ff59f19cf..4d6330eddc8d 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/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 *); +STATIC void xfs_ail_check(xfs_ail_entry_t *, xfs_log_item_t *); #else -#define xfs_ail_check(a) +#define xfs_ail_check(a,l) #endif /* DEBUG */ @@ -55,16 +55,15 @@ xfs_trans_tail_ail( { xfs_lsn_t lsn; xfs_log_item_t *lip; - SPLDECL(s); - AIL_LOCK(mp,s); - lip = xfs_ail_min(&(mp->m_ail)); + spin_lock(&mp->m_ail_lock); + lip = xfs_ail_min(&(mp->m_ail.xa_ail)); if (lip == NULL) { lsn = (xfs_lsn_t)0; } else { lsn = lip->li_lsn; } - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); return lsn; } @@ -72,120 +71,185 @@ 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 routine returns the lsn of the tail of the log. + * 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. */ -xfs_lsn_t +void 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); -#define XFS_TRANS_PUSH_AIL_RESTARTS 1000 + 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; - AIL_LOCK(mp,s); - lip = xfs_trans_first_ail(mp, &gen); - if (lip == NULL || XFS_FORCED_SHUTDOWN(mp)) { + 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)) { /* - * Just return if the AIL is empty. + * AIL is empty or our push has reached the end. */ - AIL_UNLOCK(mp, s); - return (xfs_lsn_t)0; + spin_unlock(&mp->m_ail_lock); + last_pushed_lsn = 0; + goto out; } XFS_STATS_INC(xs_push_ail); /* * While the item we are looking at is below the given threshold - * 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 + * try to flush it out. 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 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. + * 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. */ - flush_log = 0; - restarts = 0; - while (((restarts < XFS_TRANS_PUSH_AIL_RESTARTS) && - (XFS_LSN_CMP(lip->li_lsn, threshold_lsn) < 0))) { + tout = 10; + lsn = lip->li_lsn; + flush_log = stuck = count = restarts = 0; + while ((XFS_LSN_CMP(lip->li_lsn, target) < 0)) { + int lock_result; /* - * 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 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'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: - AIL_UNLOCK(mp, s); + case XFS_ITEM_SUCCESS: XFS_STATS_INC(xs_push_ail_success); IOP_PUSH(lip); - AIL_LOCK(mp,s); + last_pushed_lsn = lsn; break; - case XFS_ITEM_PUSHBUF: - AIL_UNLOCK(mp, s); + case XFS_ITEM_PUSHBUF: 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); - AIL_LOCK(mp,s); + last_pushed_lsn = lsn; 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; } - lip = xfs_trans_next_ail(mp, lip, &gen, &restarts); - if (lip == NULL) { + 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; - } - if (XFS_FORCED_SHUTDOWN(mp)) { - /* - * Just return if we shut down during the last try. - */ - AIL_UNLOCK(mp, s); - return (xfs_lsn_t)0; - } + lip = xfs_trans_next_ail(mp, lip, &gen, &restarts); + if (lip == NULL) + break; + if (restarts > XFS_TRANS_PUSH_AIL_RESTARTS) + break; + lsn = lip->li_lsn; } + spin_unlock(&mp->m_ail_lock); if (flush_log) { /* @@ -193,22 +257,35 @@ xfs_trans_push_ail( * 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); } - lip = xfs_ail_min(&(mp->m_ail)); - if (lip == NULL) { - lsn = (xfs_lsn_t)0; - } else { - lsn = lip->li_lsn; + /* + * 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; } - - AIL_UNLOCK(mp, s); - return lsn; -} /* xfs_trans_push_ail */ +out: + *last_lsn = last_pushed_lsn; + return tout; +} /* xfsaild_push */ /* @@ -249,7 +326,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); + min_lip = xfs_ail_min(&mp->m_ail.xa_ail); if (min_lip == lip) xfs_log_move_tail(mp, 1); @@ -269,21 +346,19 @@ xfs_trans_unlocked_item( * has changed. * * This function must be called with the AIL lock held. The lock - * is dropped before returning, so the caller must pass in the - * cookie returned by AIL_LOCK. + * is dropped before returning. */ void xfs_trans_update_ail( xfs_mount_t *mp, xfs_log_item_t *lip, - xfs_lsn_t lsn, - unsigned long s) __releases(mp->m_ail_lock) + xfs_lsn_t lsn) __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); + ailp = &(mp->m_ail.xa_ail); mlip = xfs_ail_min(ailp); if (lip->li_flags & XFS_LI_IN_AIL) { @@ -296,14 +371,14 @@ xfs_trans_update_ail( lip->li_lsn = lsn; xfs_ail_insert(ailp, lip); - mp->m_ail_gen++; + mp->m_ail.xa_gen++; if (mlip == dlip) { - mlip = xfs_ail_min(&(mp->m_ail)); - AIL_UNLOCK(mp, s); + mlip = xfs_ail_min(&(mp->m_ail.xa_ail)); + spin_unlock(&mp->m_ail_lock); xfs_log_move_tail(mp, mlip->li_lsn); } else { - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); } @@ -322,21 +397,19 @@ xfs_trans_update_ail( * has changed. * * This function must be called with the AIL lock held. The lock - * is dropped before returning, so the caller must pass in the - * cookie returned by AIL_LOCK. + * is dropped before returning. */ void xfs_trans_delete_ail( xfs_mount_t *mp, - xfs_log_item_t *lip, - unsigned long s) __releases(mp->m_ail_lock) + xfs_log_item_t *lip) __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); + ailp = &(mp->m_ail.xa_ail); mlip = xfs_ail_min(ailp); dlip = xfs_ail_delete(ailp, lip); ASSERT(dlip == lip); @@ -344,14 +417,14 @@ xfs_trans_delete_ail( lip->li_flags &= ~XFS_LI_IN_AIL; lip->li_lsn = 0; - mp->m_ail_gen++; + mp->m_ail.xa_gen++; if (mlip == dlip) { - mlip = xfs_ail_min(&(mp->m_ail)); - AIL_UNLOCK(mp, s); + mlip = xfs_ail_min(&(mp->m_ail.xa_ail)); + spin_unlock(&mp->m_ail_lock); xfs_log_move_tail(mp, (mlip ? mlip->li_lsn : 0)); } else { - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); } } else { @@ -360,12 +433,12 @@ xfs_trans_delete_ail( * serious trouble if we get to this stage. */ if (XFS_FORCED_SHUTDOWN(mp)) - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); else { xfs_cmn_err(XFS_PTAG_AILDELETE, CE_ALERT, mp, "%s: attempting to delete a log item that is not in the AIL", __FUNCTION__); - AIL_UNLOCK(mp, s); + spin_unlock(&mp->m_ail_lock); xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); } } @@ -385,10 +458,10 @@ xfs_trans_first_ail( { xfs_log_item_t *lip; - lip = xfs_ail_min(&(mp->m_ail)); - *gen = (int)mp->m_ail_gen; + lip = xfs_ail_min(&(mp->m_ail.xa_ail)); + *gen = (int)mp->m_ail.xa_gen; - return (lip); + return lip; } /* @@ -408,11 +481,11 @@ xfs_trans_next_ail( xfs_log_item_t *nlip; ASSERT(mp && lip && gen); - if (mp->m_ail_gen == *gen) { - nlip = xfs_ail_next(&(mp->m_ail), lip); + if (mp->m_ail.xa_gen == *gen) { + nlip = xfs_ail_next(&(mp->m_ail.xa_ail), lip); } else { - nlip = xfs_ail_min(&(mp->m_ail)); - *gen = (int)mp->m_ail_gen; + nlip = xfs_ail_min(&(mp->m_ail).xa_ail); + *gen = (int)mp->m_ail.xa_gen; if (restarts != NULL) { XFS_STATS_INC(xs_push_ail_restarts); (*restarts)++; @@ -437,12 +510,20 @@ xfs_trans_next_ail( /* * Initialize the doubly linked list to point only to itself. */ -void +int xfs_trans_ail_init( xfs_mount_t *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); + 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_mount_t *mp) +{ + xfsaild_stop(mp); } /* @@ -482,7 +563,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); + xfs_ail_check(base, lip); return; } @@ -496,12 +577,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; } @@ -545,13 +626,13 @@ xfs_ail_next( */ STATIC void xfs_ail_check( - xfs_ail_entry_t *base) + xfs_ail_entry_t *base, + xfs_log_item_t *lip) { - xfs_log_item_t *lip; xfs_log_item_t *prev_lip; - lip = base->ail_forw; - if (lip == (xfs_log_item_t*)base) { + prev_lip = base->ail_forw; + if (prev_lip == (xfs_log_item_t*)base) { /* * Make sure the pointers are correct when the list * is empty. @@ -561,9 +642,27 @@ xfs_ail_check( } /* + * 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. + * flag set. This is really expensive, so only do it when + * specifically debugging the transaction subsystem. */ prev_lip = (xfs_log_item_t*)base; while (lip != (xfs_log_item_t*)base) { @@ -578,5 +677,6 @@ 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/fs/xfs/xfs_trans_item.c b/fs/xfs/xfs_trans_item.c index 2912aac07c7b..66a09f0d894b 100644 --- a/fs/xfs/xfs_trans_item.c +++ b/fs/xfs/xfs_trans_item.c @@ -21,6 +21,7 @@ #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/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h index 447ac4308c91..3c748c456ed4 100644 --- a/fs/xfs/xfs_trans_priv.h +++ b/fs/xfs/xfs_trans_priv.h @@ -47,15 +47,22 @@ 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, - unsigned long s) + struct xfs_log_item *lip, xfs_lsn_t lsn) __releases(mp->m_ail_lock); void xfs_trans_delete_ail(struct xfs_mount *mp, - struct xfs_log_item *lip, unsigned long s) + struct xfs_log_item *lip) __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/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c index 673b405eaa31..45d740df53b7 100644 --- a/fs/xfs/xfs_utils.c +++ b/fs/xfs/xfs_utils.c @@ -73,7 +73,7 @@ xfs_dir_lookup_int( { int error; - vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(dp); error = xfs_dir_lookup(NULL, dp, VNAME(dentry), VNAMELEN(dentry), inum); if (!error) { @@ -302,6 +302,7 @@ 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; @@ -330,7 +331,6 @@ 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)) { - s = XFS_SB_LOCK(mp); + spin_lock(&mp->m_sb_lock); if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { XFS_SB_VERSION_ADDNLINK(&mp->m_sb); - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); xfs_mod_sb(tp, XFS_SB_VERSIONNUM); } else { - XFS_SB_UNLOCK(mp, s); + spin_unlock(&mp->m_sb_lock); } } /* Caller must log the inode */ @@ -366,6 +366,7 @@ 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/fs/xfs/xfs_utils.h b/fs/xfs/xfs_utils.h index a00b26d8840e..f857fcccb723 100644 --- a/fs/xfs/xfs_utils.h +++ b/fs/xfs/xfs_utils.h @@ -20,8 +20,6 @@ #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/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index a1544597bcd3..413587f02155 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -58,17 +58,12 @@ #include "xfs_vfsops.h" -int +int __init 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 lock_t xfs_dabuf_global_lock; - spinlock_init(&xfs_dabuf_global_lock, "xfsda"); + extern spinlock_t xfs_dabuf_global_lock; + spin_lock_init(&xfs_dabuf_global_lock); #endif /* @@ -152,18 +147,12 @@ xfs_init(void) return 0; } -void +void __exit 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(); @@ -449,8 +438,6 @@ xfs_mount( if (error) return error; - mp->m_io_ops = xfs_iocore_xfs; - if (args->flags & XFSMNT_QUIET) flags |= XFS_MFSI_QUIET; @@ -544,7 +531,7 @@ xfs_mount( if ((error = xfs_filestream_mount(mp))) goto error2; - error = XFS_IOINIT(mp, args, flags); + error = xfs_mountfs(mp, flags); if (error) goto error2; @@ -694,7 +681,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. */ -STATIC void +void xfs_attr_quiesce( xfs_mount_t *mp) { @@ -821,80 +808,6 @@ fscorrupt_out2: } /* - * 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. * * This routine is called by vfs_sync() to make sure that things make it @@ -981,8 +894,6 @@ 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; @@ -992,7 +903,6 @@ 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; @@ -1045,6 +955,8 @@ xfs_sync_inodes( #define XFS_PREEMPT_MASK 0x7f + ASSERT(!(flags & SYNC_BDFLUSH)); + if (bypassed) *bypassed = 0; if (mp->m_flags & XFS_MOUNT_RDONLY) @@ -1057,7 +969,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_BDFLUSH | SYNC_DELWRI)) + if (flags & SYNC_DELWRI) fflag = XFS_B_DELWRI; if (flags & SYNC_WAIT) fflag = 0; /* synchronous overrides all */ @@ -1147,24 +1059,6 @@ xfs_sync_inodes( } /* - * 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 * the mount lock and try again. If we're called from @@ -1181,7 +1075,7 @@ xfs_sync_inodes( * it. */ if (xfs_ilock_nowait(ip, lock_flags) == 0) { - if ((flags & SYNC_BDFLUSH) || (vp == NULL)) { + if (vp == NULL) { ip = ip->i_mnext; continue; } @@ -1242,160 +1136,27 @@ xfs_sync_inodes( xfs_ilock(ip, XFS_ILOCK_SHARED); } - 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); - } - - /* - * 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)) { - - 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); - } - } - - } + 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); - } 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); - 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)++; - } + /* + * 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)++; } } @@ -1627,499 +1388,3 @@ 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/fs/xfs/xfs_vfsops.h b/fs/xfs/xfs_vfsops.h index a592fe02a339..1688817c55ed 100644 --- a/fs/xfs/xfs_vfsops.h +++ b/fs/xfs/xfs_vfsops.h @@ -13,16 +13,9 @@ 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/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index efd5aff9eaf6..51305242ff8c 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/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; - vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(ip); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -136,7 +136,7 @@ xfs_getattr( default: vap->va_rdev = 0; - if (!(ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { + if (!(XFS_IS_REALTIME_INODE(ip))) { vap->va_blocksize = xfs_preferred_iosize(mp); } else { @@ -228,7 +228,7 @@ xfs_setattr( int file_owner; int need_iolock = 1; - vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(ip); 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) && - (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != + (XFS_IS_REALTIME_INODE(ip)) != (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 ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) || + if (XFS_IS_REALTIME_INODE(ip) || ((mask & XFS_AT_XFLAGS) && (vap->va_xflags & XFS_XFLAG_REALTIME))) { size = mp->m_sb.sb_rextsize << @@ -804,12 +804,8 @@ 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; } @@ -902,28 +898,6 @@ 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 @@ -987,7 +961,7 @@ xfs_readlink( int pathlen; int error = 0; - vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(ip); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -1033,7 +1007,7 @@ xfs_fsync( int error; int log_flushed = 0, changed = 1; - vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(ip); ASSERT(start >= 0 && stop >= -1); @@ -1149,7 +1123,7 @@ xfs_fsync( * If this inode is on the RT dev we need to flush that * cache as well. */ - if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) + if (XFS_IS_REALTIME_INODE(ip)) xfs_blkdev_issue_flush(ip->i_mount->m_rtdev_targp); } @@ -1188,7 +1162,7 @@ xfs_free_eofblocks( nimaps = 1; xfs_ilock(ip, XFS_ILOCK_SHARED); - error = XFS_BMAPI(mp, NULL, &ip->i_iocore, end_fsb, map_len, 0, + error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0, NULL, 0, &imap, &nimaps, NULL, NULL); xfs_iunlock(ip, XFS_ILOCK_SHARED); @@ -1562,9 +1536,6 @@ 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); } } @@ -1592,7 +1563,7 @@ xfs_inactive( int error; int truncate; - vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(ip); /* * If the inode is already free, then there can be nothing @@ -1638,9 +1609,6 @@ 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; } @@ -1805,7 +1773,7 @@ xfs_lookup( int error; uint lock_mode; - vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(dp); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return XFS_ERROR(EIO); @@ -1814,7 +1782,7 @@ xfs_lookup( error = xfs_dir_lookup_int(dp, lock_mode, dentry, &e_inum, &ip); if (!error) { *vpp = XFS_ITOV(ip); - ITRACE(ip); + xfs_itrace_ref(ip); } xfs_iunlock_map_shared(dp, lock_mode); return error; @@ -1848,7 +1816,7 @@ xfs_create( int namelen; ASSERT(!*vpp); - vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(dp); namelen = VNAMELEN(dentry); @@ -1930,7 +1898,7 @@ xfs_create( goto error_return; goto abort_return; } - ITRACE(ip); + xfs_itrace_ref(ip); /* * At this point, we've gotten a newly allocated inode. @@ -2098,7 +2066,7 @@ again: e_inum = ip->i_ino; - ITRACE(ip); + xfs_itrace_ref(ip); /* * We want to lock in increasing inum. Since we've already @@ -2321,7 +2289,7 @@ xfs_remove( uint resblks; int namelen; - vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(dp); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -2364,9 +2332,8 @@ xfs_remove( dm_di_mode = ip->i_d.di_mode; - vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); - - ITRACE(ip); + xfs_itrace_entry(ip); + xfs_itrace_ref(ip); error = XFS_QM_DQATTACH(mp, dp, 0); if (!error && dp != ip) @@ -2498,8 +2465,7 @@ xfs_remove( if (link_zero && xfs_inode_is_filestream(ip)) xfs_filestream_deassociate(ip); - vn_trace_exit(ip, __FUNCTION__, (inst_t *)__return_address); - + xfs_itrace_exit(ip); IRELE(ip); /* Fall through to std_return with error = 0 */ @@ -2562,8 +2528,8 @@ xfs_link( char *target_name = VNAME(dentry); int target_namelen; - vn_trace_entry(tdp, __FUNCTION__, (inst_t *)__return_address); - vn_trace_entry(xfs_vtoi(src_vp), __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(tdp); + xfs_itrace_entry(xfs_vtoi(src_vp)); target_namelen = VNAMELEN(dentry); ASSERT(!VN_ISDIR(src_vp)); @@ -2744,7 +2710,7 @@ xfs_mkdir( /* Return through std_return after this point. */ - vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(dp); mp = dp->i_mount; udqp = gdqp = NULL; @@ -2810,7 +2776,7 @@ xfs_mkdir( goto error_return; goto abort_return; } - ITRACE(cdp); + xfs_itrace_ref(cdp); /* * Now we add the directory inode to the transaction. @@ -2936,7 +2902,7 @@ xfs_rmdir( int last_cdp_link; uint resblks; - vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(dp); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -3041,7 +3007,7 @@ xfs_rmdir( VN_HOLD(dir_vp); } - ITRACE(cdp); + xfs_itrace_ref(cdp); xfs_trans_ijoin(tp, cdp, XFS_ILOCK_EXCL); ASSERT(cdp->i_d.di_nlink >= 2); @@ -3189,8 +3155,7 @@ xfs_symlink( ip = NULL; tp = NULL; - vn_trace_entry(dp, __FUNCTION__, (inst_t *)__return_address); - + xfs_itrace_entry(dp); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -3317,7 +3282,7 @@ xfs_symlink( goto error_return; goto error1; } - ITRACE(ip); + xfs_itrace_ref(ip); /* * An error after we've joined dp to the transaction will result in the @@ -3465,27 +3430,6 @@ std_return: 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, @@ -3558,11 +3502,11 @@ xfs_inode_flush( if (iip && iip->ili_last_lsn) { xlog_t *log = mp->m_log; xfs_lsn_t sync_lsn; - int s, log_flags = XFS_LOG_FORCE; + int log_flags = XFS_LOG_FORCE; - s = GRANT_LOCK(log); + spin_lock(&log->l_grant_lock); sync_lsn = log->l_last_sync_lsn; - GRANT_UNLOCK(log, s); + spin_unlock(&log->l_grant_lock); if ((XFS_LSN_CMP(iip->ili_last_lsn, sync_lsn) > 0)) { if (flags & FLUSH_SYNC) @@ -3637,8 +3581,8 @@ xfs_set_dmattrs( xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); - ip->i_iocore.io_dmevmask = ip->i_d.di_dmevmask = evmask; - ip->i_iocore.io_dmstate = ip->i_d.di_dmstate = state; + ip->i_d.di_dmevmask = evmask; + ip->i_d.di_dmstate = state; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); IHOLD(ip); @@ -3653,7 +3597,7 @@ xfs_reclaim( { bhv_vnode_t *vp = XFS_ITOV(ip); - vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(ip); ASSERT(!VN_MAPPED(vp)); @@ -3871,7 +3815,7 @@ xfs_alloc_file_space( int committed; int error; - vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(ip); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); @@ -3976,7 +3920,7 @@ retry: * Issue the xfs_bmapi() call to allocate the blocks */ XFS_BMAP_INIT(&free_list, &firstfsb); - error = XFS_BMAPI(mp, tp, &ip->i_iocore, startoffset_fsb, + error = xfs_bmapi(tp, ip, startoffset_fsb, allocatesize_fsb, bmapi_flag, &firstfsb, 0, imapp, &nimaps, &free_list, NULL); @@ -4052,13 +3996,13 @@ xfs_zero_remaining_bytes( int error = 0; bp = xfs_buf_get_noaddr(mp->m_sb.sb_blocksize, - ip->i_d.di_flags & XFS_DIFLAG_REALTIME ? + XFS_IS_REALTIME_INODE(ip) ? 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(mp, NULL, &ip->i_iocore, offset_fsb, 1, 0, + error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0, NULL, 0, &imap, &nimap, NULL, NULL); if (error || nimap < 1) break; @@ -4141,7 +4085,7 @@ xfs_free_file_space( vp = XFS_ITOV(ip); mp = ip->i_mount; - vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(ip); if ((error = XFS_QM_DQATTACH(mp, ip, 0))) return error; @@ -4149,7 +4093,7 @@ xfs_free_file_space( error = 0; if (len <= 0) /* if nothing being freed */ return error; - rt = (ip->i_d.di_flags & XFS_DIFLAG_REALTIME); + rt = XFS_IS_REALTIME_INODE(ip); startoffset_fsb = XFS_B_TO_FSB(mp, offset); end_dmi_offset = offset + len; endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset); @@ -4172,15 +4116,12 @@ 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, NBPP); + rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE); ioffset = offset & ~(rounding - 1); if (VN_CACHED(vp) != 0) { - 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); + xfs_inval_cached_trace(ip, ioffset, -1, ioffset, -1); + error = xfs_flushinval_pages(ip, ioffset, -1, FI_REMAPF_LOCKED); if (error) goto out_unlock_iolock; } @@ -4193,7 +4134,7 @@ xfs_free_file_space( */ if (rt && !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) { nimap = 1; - error = XFS_BMAPI(mp, NULL, &ip->i_iocore, startoffset_fsb, + error = xfs_bmapi(NULL, ip, startoffset_fsb, 1, 0, NULL, 0, &imap, &nimap, NULL, NULL); if (error) goto out_unlock_iolock; @@ -4208,7 +4149,7 @@ xfs_free_file_space( startoffset_fsb += mp->m_sb.sb_rextsize - mod; } nimap = 1; - error = XFS_BMAPI(mp, NULL, &ip->i_iocore, endoffset_fsb - 1, + error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, 1, 0, NULL, 0, &imap, &nimap, NULL, NULL); if (error) goto out_unlock_iolock; @@ -4284,7 +4225,7 @@ xfs_free_file_space( * issue the bunmapi() call to free the blocks */ XFS_BMAP_INIT(&free_list, &firstfsb); - error = XFS_BUNMAPI(mp, tp, &ip->i_iocore, startoffset_fsb, + error = xfs_bunmapi(tp, ip, startoffset_fsb, endoffset_fsb - startoffset_fsb, 0, 2, &firstfsb, &free_list, NULL, &done); if (error) { @@ -4347,23 +4288,11 @@ xfs_change_file_space( xfs_trans_t *tp; bhv_vattr_t va; - vn_trace_entry(ip, __FUNCTION__, (inst_t *)__return_address); + xfs_itrace_entry(ip); - /* - * 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/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h index b7e461c40cfb..4e3970f0e5e3 100644 --- a/fs/xfs/xfs_vnodeops.h +++ b/fs/xfs/xfs_vnodeops.h @@ -18,7 +18,6 @@ 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); @@ -39,7 +38,6 @@ 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/include/linux/dmi.h b/include/linux/dmi.h index b1251b2af568..bbc9992ec374 100644 --- a/include/linux/dmi.h +++ b/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/include/linux/enclosure.h b/include/linux/enclosure.h new file mode 100644 index 000000000000..a5978f18ca40 --- /dev/null +++ b/include/linux/enclosure.h @@ -0,0 +1,129 @@ +/* + * Enclosure Services + * + * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com> + * +**----------------------------------------------------------------------------- +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** version 2 as published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +**----------------------------------------------------------------------------- +*/ +#ifndef _LINUX_ENCLOSURE_H_ +#define _LINUX_ENCLOSURE_H_ + +#include <linux/device.h> +#include <linux/list.h> + +/* 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/include/linux/hrtimer.h b/include/linux/hrtimer.h index 8371b664b41f..203591e23210 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -225,11 +225,14 @@ 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 KTIME_HIGH_RES (ktime_t) { .tv64 = 1 } +# define HIGH_RES_NSEC 1 +# define KTIME_HIGH_RES (ktime_t) { .tv64 = HIGH_RES_NSEC } +# define MONOTONIC_RES_NSEC HIGH_RES_NSEC # 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/include/linux/i2c-id.h b/include/linux/i2c-id.h index f922b060158b..b979112f74e0 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -96,42 +96,6 @@ #define I2C_DRIVERID_I2CDEV 900 -/* IDs -- Use DRIVERIDs 1000-1999 for sensors. - These were originally in sensors.h in the lm_sensors package */ -#define I2C_DRIVERID_LM78 1002 -#define I2C_DRIVERID_LM75 1003 -#define I2C_DRIVERID_GL518 1004 -#define I2C_DRIVERID_EEPROM 1005 -#define I2C_DRIVERID_W83781D 1006 -#define I2C_DRIVERID_LM80 1007 -#define I2C_DRIVERID_ADM1021 1008 -#define I2C_DRIVERID_ADM9240 1009 -#define I2C_DRIVERID_LTC1710 1010 -#define I2C_DRIVERID_BT869 1013 -#define I2C_DRIVERID_MAXILIFE 1014 -#define I2C_DRIVERID_MATORB 1015 -#define I2C_DRIVERID_GL520 1016 -#define I2C_DRIVERID_THMC50 1017 -#define I2C_DRIVERID_ADM1025 1020 -#define I2C_DRIVERID_LM87 1021 -#define I2C_DRIVERID_PCF8574 1022 -#define I2C_DRIVERID_MTP008 1023 -#define I2C_DRIVERID_DS1621 1024 -#define I2C_DRIVERID_ADM1024 1025 -#define I2C_DRIVERID_CH700X 1027 /* single driver for CH7003-7009 digital pc to tv encoders */ -#define I2C_DRIVERID_FSCPOS 1028 -#define I2C_DRIVERID_FSCSCY 1029 -#define I2C_DRIVERID_PCF8591 1030 -#define I2C_DRIVERID_LM92 1033 -#define I2C_DRIVERID_SMARTBATT 1035 -#define I2C_DRIVERID_BMCSENSORS 1036 -#define I2C_DRIVERID_FS451 1037 -#define I2C_DRIVERID_LM85 1039 -#define I2C_DRIVERID_LM83 1040 -#define I2C_DRIVERID_LM90 1042 -#define I2C_DRIVERID_ASB100 1043 -#define I2C_DRIVERID_FSCHER 1046 -#define I2C_DRIVERID_W83L785TS 1047 #define I2C_DRIVERID_OV7670 1048 /* Omnivision 7670 camera */ /* diff --git a/include/linux/ktime.h b/include/linux/ktime.h index a6ddec141f96..36c542b70c6d 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -316,7 +316,8 @@ 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 KTIME_LOW_RES (ktime_t){ .tv64 = TICK_NSEC } +#define LOW_RES_NSEC TICK_NSEC +#define KTIME_LOW_RES (ktime_t){ .tv64 = LOW_RES_NSEC } /* Get the monotonic time in timespec format: */ extern void ktime_get_ts(struct timespec *ts); diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 34023c65d466..bfee0bd1d435 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -64,7 +64,10 @@ struct page { #if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS spinlock_t ptl; #endif - struct kmem_cache *slab; /* SLUB: Pointer to slab */ + struct { + struct kmem_cache *slab; /* SLUB: Pointer to slab */ + void *end; /* SLUB: end marker */ + }; struct page *first_page; /* Compound tail pages */ }; union { diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h index ddb1a706b144..5e6d3d634d5b 100644 --- a/include/linux/slub_def.h +++ b/include/linux/slub_def.h @@ -11,12 +11,35 @@ #include <linux/workqueue.h> #include <linux/kobject.h> +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/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h index 318a909e7ae1..5ffec8ad6964 100644 --- a/include/scsi/iscsi_proto.h +++ b/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, id, age) ((__force itt_t)\ - ((itt) | ((id) << ISCSI_CID_SHIFT) | ((age) << ISCSI_AGE_SHIFT))) +#define build_itt(itt, age) ((__force itt_t)\ + ((itt) | ((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/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 889f51fabab9..7b90b63fb5c7 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -70,8 +70,6 @@ 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) @@ -135,6 +133,14 @@ 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 */ @@ -227,6 +233,17 @@ 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 @@ -325,6 +342,10 @@ 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 */ @@ -339,6 +360,9 @@ 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 */ @@ -349,8 +373,6 @@ 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/include/scsi/scsi.h b/include/scsi/scsi.h index 82251575a9b4..1f74bcd603fe 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -235,6 +235,20 @@ 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/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 5c58d594126a..d1299e999723 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -280,39 +280,45 @@ 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 []); @@ -351,7 +357,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; @@ -372,12 +378,12 @@ struct scsi_host_template { unsigned short sg_tablesize; /* - * If the host adapter has limitations beside segment count + * Set this 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; @@ -386,7 +392,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 @@ -413,12 +419,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 @@ -428,7 +434,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; @@ -438,12 +444,12 @@ struct scsi_host_template { unsigned skip_settle_delay:1; /* - * ordered write support + * True if we are using 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; @@ -522,8 +528,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; @@ -596,16 +602,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/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 404f11d331d6..dbc96ef4cc72 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -149,13 +149,6 @@ 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 */ @@ -169,27 +162,31 @@ struct iscsi_cls_conn { #define iscsi_dev_to_conn(_dev) \ container_of(_dev, struct iscsi_cls_conn, dev) -/* 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 +#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, +}; 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 */ @@ -206,14 +203,22 @@ struct iscsi_cls_session { struct iscsi_host { struct list_head sessions; + atomic_t nr_scans; struct mutex mutex; - struct workqueue_struct *unbind_workq; - char unbind_workq_name[KOBJ_NAME_LEN]; + struct workqueue_struct *scan_workq; + char scan_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, @@ -231,6 +236,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/lib/Kconfig.debug b/lib/Kconfig.debug index 0d385be682db..4f4008fc73e4 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -205,6 +205,19 @@ 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/mm/slub.c b/mm/slub.c index 3f056677fa8f..e2989ae243b5 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -149,6 +149,13 @@ 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 /* @@ -243,6 +250,7 @@ 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) @@ -251,8 +259,16 @@ 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 *******************************************************************/ @@ -280,15 +296,32 @@ 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) + if (object == page->end) return 1; - base = page_address(page); + base = slab_address(page); if (object < base || object >= base + s->objects * s->size || (object - base) % s->size) { return 0; @@ -321,7 +354,8 @@ 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; __p = get_freepointer((__s), __p)) + for (__p = (__free); (__p) != page->end; __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) @@ -473,7 +507,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 = page_address(page); + u8 *addr = slab_address(page); print_tracking(s, p); @@ -651,7 +685,7 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page) if (!(s->flags & SLAB_POISON)) return 1; - start = page_address(page); + start = slab_address(page); end = start + (PAGE_SIZE << s->order); length = s->objects * s->size; remainder = end - (start + length); @@ -685,9 +719,10 @@ 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) { @@ -718,7 +753,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, NULL); + set_freepointer(s, p, page->end); return 0; } return 1; @@ -752,18 +787,18 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search) void *fp = page->freelist; void *object = NULL; - while (fp && nr <= s->objects) { + while (fp != page->end && 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, NULL); + set_freepointer(s, object, page->end); break; } else { slab_err(s, page, "Freepointer corrupt"); - page->freelist = NULL; + page->freelist = page->end; page->inuse = s->objects; slab_fix(s, "Freelist cleared"); return 0; @@ -869,7 +904,7 @@ bad: */ slab_fix(s, "Marking all objects used"); page->inuse = s->objects; - page->freelist = NULL; + page->freelist = page->end; } return 0; } @@ -894,11 +929,10 @@ 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 <none>: no slab for object 0x%p.\n", object); @@ -910,7 +944,7 @@ static int free_debug_processing(struct kmem_cache *s, struct page *page, } /* Special debug activities for freeing objects */ - if (!SlabFrozen(page) && !page->freelist) + if (!SlabFrozen(page) && page->freelist == page->end) remove_full(s, page); if (s->flags & SLAB_STORE_USER) set_track(s, object, TRACK_FREE, addr); @@ -1007,7 +1041,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; } @@ -1102,6 +1136,7 @@ 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); @@ -1113,7 +1148,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, NULL); + set_freepointer(s, last, page->end); page->freelist = start; page->inuse = 0; @@ -1129,7 +1164,7 @@ static void __free_slab(struct kmem_cache *s, struct page *page) void *p; slab_pad_check(s, page); - for_each_object(p, s, page_address(page)) + for_each_object(p, s, slab_address(page)) check_object(s, page, p, 0); ClearSlabDebug(page); } @@ -1139,6 +1174,7 @@ 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); } @@ -1183,7 +1219,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) @@ -1294,8 +1330,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; @@ -1337,17 +1373,22 @@ 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) + if (page->freelist != page->end) { add_partial(n, page, tail); - else if (SlabDebug(page) && (s->flags & SLAB_STORE_USER)) - add_full(n, page); + 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); + } slab_unlock(page); - } else { + stat(c, DEACTIVATE_EMPTY); if (n->nr_partial < MIN_PARTIAL) { /* * Adding an empty slab to the partial slabs in order @@ -1361,6 +1402,7 @@ 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); } } @@ -1373,12 +1415,19 @@ 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(c->freelist)) { + while (unlikely(!is_end(c->freelist))) { void **object; tail = 0; /* Hot objects. Put the slab first */ @@ -1398,6 +1447,7 @@ 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); } @@ -1469,16 +1519,21 @@ 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)) + if (unlikely(object == c->page->end)) goto another_slab; if (unlikely(SlabDebug(c->page))) goto debug; @@ -1486,9 +1541,15 @@ load_freelist: object = c->page->freelist; c->freelist = object[c->offset]; c->page->inuse = s->objects; - c->page->freelist = NULL; + c->page->freelist = c->page->end; 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: @@ -1498,6 +1559,7 @@ new_slab: new = get_partial(s, gfpflags, node); if (new) { c->page = new; + stat(c, ALLOC_FROM_PARTIAL); goto load_freelist; } @@ -1511,6 +1573,7 @@ new_slab: if (new) { c = get_cpu_slab(s, smp_processor_id()); + stat(c, ALLOC_SLAB); if (c->page) flush_slab(s, c); slab_lock(new); @@ -1518,7 +1581,8 @@ new_slab: c->page = new; goto load_freelist; } - return NULL; + object = NULL; + goto out; debug: object = c->page->freelist; if (!alloc_debug_processing(s, c->page, object, addr)) @@ -1527,8 +1591,7 @@ debug: c->page->inuse++; c->page->freelist = object[c->offset]; c->node = -1; - slab_unlock(c->page); - return object; + goto unlock_out; } /* @@ -1545,20 +1608,50 @@ static __always_inline void *slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, void *addr) { void **object; - unsigned long flags; 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; + local_irq_save(flags); c = get_cpu_slab(s, smp_processor_id()); - if (unlikely(!c->freelist || !node_match(c, node))) + if (unlikely(is_end(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); @@ -1593,7 +1686,15 @@ 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))) @@ -1603,8 +1704,10 @@ checks_ok: page->freelist = object; page->inuse--; - if (unlikely(SlabFrozen(page))) + if (unlikely(SlabFrozen(page))) { + stat(c, FREE_FROZEN); goto out_unlock; + } if (unlikely(!page->inuse)) goto slab_empty; @@ -1614,21 +1717,31 @@ checks_ok: * was not on the partial list before * then add it. */ - if (unlikely(!prior)) + if (unlikely(prior == page->end)) { 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) + if (prior != page->end) { /* * 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; @@ -1653,19 +1766,49 @@ static __always_inline void slab_free(struct kmem_cache *s, struct page *page, void *x, void *addr) { void **object = (void *)x; - unsigned long flags; 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; + local_irq_save(flags); debug_check_no_locks_freed(object, s->objsize); c = get_cpu_slab(s, smp_processor_id()); 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) @@ -1842,7 +1985,7 @@ static void init_kmem_cache_cpu(struct kmem_cache *s, struct kmem_cache_cpu *c) { c->page = NULL; - c->freelist = NULL; + c->freelist = (void *)PAGE_MAPPING_ANON; c->node = 0; c->offset = s->offset / sizeof(void *); c->objsize = s->objsize; @@ -2446,7 +2589,8 @@ 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, @@ -2601,6 +2745,7 @@ EXPORT_SYMBOL(ksize); void kfree(const void *x) { struct page *page; + void *object = (void *)x; if (unlikely(ZERO_OR_NULL_PTR(x))) return; @@ -2610,7 +2755,7 @@ void kfree(const void *x) put_page(page); return; } - slab_free(page->slab, page, (void *)x, __builtin_return_address(0)); + slab_free(page->slab, page, object, __builtin_return_address(0)); } EXPORT_SYMBOL(kfree); @@ -2896,7 +3041,8 @@ 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, @@ -3063,7 +3209,7 @@ static int __cpuinit slab_cpuup_callback(struct notifier_block *nfb, } static struct notifier_block __cpuinitdata slab_notifier = { - &slab_cpuup_callback, NULL, 0 + .notifier_call = slab_cpuup_callback }; #endif @@ -3104,7 +3250,7 @@ static int validate_slab(struct kmem_cache *s, struct page *page, unsigned long *map) { void *p; - void *addr = page_address(page); + void *addr = slab_address(page); if (!check_slab(s, page) || !on_freelist(s, page, NULL)) @@ -3221,8 +3367,9 @@ 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); @@ -3230,7 +3377,8 @@ 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"); @@ -3243,7 +3391,8 @@ 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); @@ -3384,7 +3533,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 = page_address(page); + void *addr = slab_address(page); DECLARE_BITMAP(map, s->objects); void *p; @@ -3872,6 +4021,62 @@ 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, @@ -3902,6 +4107,25 @@ static struct attribute *slab_attrs[] = { #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 }; |